From: Richard Smith Date: Tue, 5 Dec 2017 01:31:47 +0000 (+0000) Subject: Generalize "static data member instantiated" notification to cover variable templates... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=25b45aa81854313486df891985cdd7ef1ec09780;p=clang Generalize "static data member instantiated" notification to cover variable templates too. While here, split the "point of instantiation changed" notification out from it; these two really are orthogonal changes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@319727 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index ed82b32342..9395d36d87 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -36,6 +36,7 @@ namespace clang { class QualType; class RecordDecl; class TagDecl; + class ValueDecl; class VarDecl; class VarTemplateDecl; class VarTemplateSpecializationDecl; @@ -87,8 +88,13 @@ public: /// \brief An implicit member got a definition. virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} - /// \brief A static data member was implicitly instantiated. - virtual void StaticDataMemberInstantiated(const VarDecl *D) {} + /// \brief The instantiation of a templated function or variable was + /// requested. In particular, the point of instantiation and template + /// specialization kind of \p D may have changed. + virtual void InstantiationRequested(const ValueDecl *D) {} + + /// \brief A templated variable's definition was implicitly instantiated. + virtual void VariableDefinitionInstantiated(const VarDecl *D) {} /// \brief A function template's definition was instantiated. virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {} diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4ca56ab101..8a51abecaf 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7790,11 +7790,6 @@ public: VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); - void InstantiateStaticDataMemberDefinition( - SourceLocation PointOfInstantiation, - VarDecl *Var, - bool Recursive = false, - bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 51ee5508ad..9437bf7f2c 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -727,10 +727,11 @@ private: const FunctionDecl *Delete, Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; - void StaticDataMemberInstantiated(const VarDecl *D) override; + void InstantiationRequested(const ValueDecl *D) override; + void VariableDefinitionInstantiated(const VarDecl *D) override; + void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; - void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; void DeclarationMarkedUsed(const Decl *D) override; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 29846b6101..2f51ec31a7 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2418,15 +2418,21 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, dyn_cast(this)) { Spec->setSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - Spec->getPointOfInstantiation().isInvalid()) + Spec->getPointOfInstantiation().isInvalid()) { Spec->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { MSI->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - MSI->getPointOfInstantiation().isInvalid()) + MSI->getPointOfInstantiation().isInvalid()) { MSI->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } } @@ -3442,15 +3448,21 @@ FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, FTSInfo->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - FTSInfo->getPointOfInstantiation().isInvalid()) + FTSInfo->getPointOfInstantiation().isInvalid()) { FTSInfo->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } else if (MemberSpecializationInfo *MSInfo = TemplateOrSpecialization.dyn_cast()) { MSInfo->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->getPointOfInstantiation().isInvalid()) { MSInfo->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } else llvm_unreachable("Function cannot have a template specialization kind"); } diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index 16000bc159..04a8f6c1cd 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -119,12 +119,13 @@ public: const FunctionDecl *Delete, Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; - void StaticDataMemberInstantiated(const VarDecl *D) override; + void InstantiationRequested(const ValueDecl *D) override; + void VariableDefinitionInstantiated(const VarDecl *D) override; + void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; - void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; void DeclarationMarkedOpenMPDeclareTarget(const Decl *D, @@ -193,10 +194,19 @@ void MultiplexASTMutationListener::CompletedImplicitDefinition( for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->CompletedImplicitDefinition(D); } -void MultiplexASTMutationListener::StaticDataMemberInstantiated( - const VarDecl *D) { +void MultiplexASTMutationListener::InstantiationRequested(const ValueDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->InstantiationRequested(D); +} +void MultiplexASTMutationListener::VariableDefinitionInstantiated( + const VarDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) - Listeners[i]->StaticDataMemberInstantiated(D); + Listeners[i]->VariableDefinitionInstantiated(D); +} +void MultiplexASTMutationListener::FunctionDefinitionInstantiated( + const FunctionDecl *D) { + for (auto &Listener : Listeners) + Listener->FunctionDefinitionInstantiated(D); } void MultiplexASTMutationListener::DefaultArgumentInstantiated( const ParmVarDecl *D) { @@ -214,11 +224,6 @@ void MultiplexASTMutationListener::AddedObjCCategoryToInterface( for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedObjCCategoryToInterface(CatD, IFD); } -void MultiplexASTMutationListener::FunctionDefinitionInstantiated( - const FunctionDecl *D) { - for (auto &Listener : Listeners) - Listener->FunctionDefinitionInstantiated(D); -} void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclarationMarkedUsed(D); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b47c89174a..b6514811ca 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13960,29 +13960,21 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { - bool AlreadyInstantiated = false; - SourceLocation PointOfInstantiation = Loc; - if (FunctionTemplateSpecializationInfo *SpecInfo - = Func->getTemplateSpecializationInfo()) { - if (SpecInfo->getPointOfInstantiation().isInvalid()) - SpecInfo->setPointOfInstantiation(Loc); - else if (SpecInfo->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - AlreadyInstantiated = true; - PointOfInstantiation = SpecInfo->getPointOfInstantiation(); - } - } else if (MemberSpecializationInfo *MSInfo - = Func->getMemberSpecializationInfo()) { - if (MSInfo->getPointOfInstantiation().isInvalid()) - MSInfo->setPointOfInstantiation(Loc); - else if (MSInfo->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - AlreadyInstantiated = true; - PointOfInstantiation = MSInfo->getPointOfInstantiation(); - } - } - - if (!AlreadyInstantiated || Func->isConstexpr()) { + TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind(); + SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Func->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } else if (TSK != TSK_ImplicitInstantiation) { + // Use the point of use as the point of instantiation, instead of the + // point of explicit instantiation (which we track as the actual point of + // instantiation). This gives better backtraces in diagnostics. + PointOfInstantiation = Loc; + } + + if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || + Func->isConstexpr()) { if (isa(Func->getDeclContext()) && cast(Func->getDeclContext())->isLocalClass() && CodeSynthesisContexts.size()) @@ -14859,22 +14851,14 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, TSK == TSK_ImplicitInstantiation || (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr); - if (TryInstantiating && !isa(Var)) { - if (Var->getPointOfInstantiation().isInvalid()) { - // This is a modification of an existing AST node. Notify listeners. - if (ASTMutationListener *L = SemaRef.getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); - } else if (!UsableInConstantExpr) - // Don't bother trying to instantiate it again, unless we might need - // its initializer before we get to the end of the TU. - TryInstantiating = false; - } - - if (Var->getPointOfInstantiation().isInvalid()) - Var->setTemplateSpecializationKind(TSK, Loc); - if (TryInstantiating) { SourceLocation PointOfInstantiation = Var->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } + bool InstantiationDependent = false; bool IsNonDependent = VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments( @@ -14884,10 +14868,16 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // Do not instantiate specializations that are still type-dependent. if (IsNonDependent) { if (UsableInConstantExpr) { - // Do not defer instantiations of variables which could be used in a + // Do not defer instantiations of variables that could be used in a // constant expression. SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); - } else { + } else if (FirstInstantiation || + isa(Var)) { + // FIXME: For a specialization of a variable template, we don't + // distinguish between "declaration and type implicitly instantiated" + // and "implicit instantiation of definition requested", so we have + // no direct way to avoid enqueueing the pending instantiation + // multiple times. SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c3afafeb10..d192a97995 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -9071,7 +9071,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!HasNoEffect) { // Instantiate static data member or variable template. - Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (PrevTemplate) { // Merge attributes. diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 03ad89100d..a48e2466a8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2613,7 +2613,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, continue; Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); - InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); + InstantiateVariableDefinition(PointOfInstantiation, Var); } else { Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index eacb325642..f627f6017f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4142,6 +4142,9 @@ void Sema::BuildVariableInstantiation( void Sema::InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs) { + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->VariableDefinitionInstantiated(Var); + // We propagate the 'inline' flag with the initializer, because it // would otherwise imply that the variable is a definition for a // non-static data member. @@ -4204,36 +4207,22 @@ void Sema::InstantiateVariableInitializer( /// /// \param PointOfInstantiation the point at which the instantiation was /// required. Note that this is not precisely a "point of instantiation" -/// for the function, but it's close. +/// for the variable, but it's close. /// -/// \param Var the already-instantiated declaration of a static member -/// variable of a class template specialization. +/// \param Var the already-instantiated declaration of a templated variable. /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. /// /// \param DefinitionRequired if true, then we are performing an explicit -/// instantiation where an out-of-line definition of the member variable -/// is required. Complain if there is no such definition. -void Sema::InstantiateStaticDataMemberDefinition( - SourceLocation PointOfInstantiation, - VarDecl *Var, - bool Recursive, - bool DefinitionRequired) { - InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive, - DefinitionRequired); -} - +/// instantiation where a definition of the variable is required. Complain +/// if there is no such definition. void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, bool DefinitionRequired, bool AtEndOfTU) { if (Var->isInvalidDecl()) return; - // FIXME: We're missing ASTMutationListener notifications for all of the work - // done here. (Some of our callers notify the listeners for the static data - // member case, but not in general.) - VarTemplateSpecializationDecl *VarSpec = dyn_cast(Var); VarDecl *PatternDecl = nullptr, *Def = nullptr; @@ -4284,6 +4273,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // If this is a static data member template, there might be an // uninstantiated initializer on the declaration. If so, instantiate // it now. + // + // FIXME: This largely duplicates what we would do below. The difference + // is that along this path we may instantiate an initializer from an + // in-class declaration of the template and instantiate the definition + // from a separate out-of-class definition. if (PatternDecl->isStaticDataMember() && (PatternDecl = PatternDecl->getFirstDecl())->hasInit() && !Var->hasInit()) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c53b24b5fe..710b734f03 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -7268,32 +7268,28 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, void Sema::completeExprArrayBound(Expr *E) { if (DeclRefExpr *DRE = dyn_cast(E->IgnoreParens())) { if (VarDecl *Var = dyn_cast(DRE->getDecl())) { - if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) { + if (isTemplateInstantiation(Var->getTemplateSpecializationKind()) && + !Var->getDefinition()) { SourceLocation PointOfInstantiation = E->getExprLoc(); - - if (MemberSpecializationInfo *MSInfo = - Var->getMemberSpecializationInfo()) { - // If we don't already have a point of instantiation, this is it. - if (MSInfo->getPointOfInstantiation().isInvalid()) { - MSInfo->setPointOfInstantiation(PointOfInstantiation); - - // This is a modification of an existing AST node. Notify - // listeners. - if (ASTMutationListener *L = getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); - } - } else { - VarTemplateSpecializationDecl *VarSpec = - cast(Var); - if (VarSpec->getPointOfInstantiation().isInvalid()) - VarSpec->setPointOfInstantiation(PointOfInstantiation); - } - InstantiateVariableDefinition(PointOfInstantiation, Var); + auto *Def = Var->getDefinition(); + + // If we don't already have a point of instantiation, and we managed to + // instantiate a definition, this is the point of instantiation. + // Otherwise, we don't request an end-of-TU instantiation, so this is + // not a point of instantiation. + // FIXME: Is this really the right behavior? + if (Var->getPointOfInstantiation().isInvalid() && Def) { + assert(Var->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation && + "explicit instantiation with no point of instantiation"); + Var->setTemplateSpecializationKind( + Var->getTemplateSpecializationKind(), PointOfInstantiation); + } // Update the type to the newly instantiated definition's type both // here and within the expression. - if (VarDecl *Def = Var->getDefinition()) { + if (Def) { DRE->setDecl(Def); QualType T = Def->getType(); DRE->setType(T); diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index cbc5f04738..6aca453bbb 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -27,7 +27,8 @@ enum DeclUpdateKind { UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, UPD_CXX_ADDED_FUNCTION_DEFINITION, - UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, + UPD_CXX_ADDED_VAR_DEFINITION, + UPD_CXX_POINT_OF_INSTANTIATION, UPD_CXX_INSTANTIATED_CLASS_DEFINITION, UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 846c57a96d..a3bf0d9712 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -3984,10 +3984,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, break; } - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: { + case UPD_CXX_ADDED_VAR_DEFINITION: { VarDecl *VD = cast(D); - VD->getMemberSpecializationInfo()->setPointOfInstantiation( - ReadSourceLocation()); VD->NonParmVarDeclBits.IsInline = Record.readInt(); VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt(); uint64_t Val = Record.readInt(); @@ -4002,6 +4000,25 @@ void ASTDeclReader::UpdateDecl(Decl *D, break; } + case UPD_CXX_POINT_OF_INSTANTIATION: { + SourceLocation POI = Record.readSourceLocation(); + if (VarTemplateSpecializationDecl *VTSD = + dyn_cast(D)) { + VTSD->setPointOfInstantiation(POI); + } else if (auto *VD = dyn_cast(D)) { + VD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + } else { + auto *FD = cast(D); + if (auto *FTSInfo = FD->TemplateOrSpecialization + .dyn_cast()) + FTSInfo->setPointOfInstantiation(POI); + else + FD->TemplateOrSpecialization.get() + ->setPointOfInstantiation(POI); + } + break; + } + case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: { auto Param = cast(D); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index e9e379aab6..1e72ced2ee 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -5135,9 +5135,13 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { case UPD_CXX_ADDED_FUNCTION_DEFINITION: break; - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: { - const VarDecl *VD = cast(D); + case UPD_CXX_POINT_OF_INSTANTIATION: + // FIXME: Do we need to also save the template specialization kind here? Record.AddSourceLocation(Update.getLoc()); + break; + + case UPD_CXX_ADDED_VAR_DEFINITION: { + const VarDecl *VD = cast(D); Record.push_back(VD->isInline()); Record.push_back(VD->isInlineSpecified()); if (VD->getInit()) { @@ -6256,6 +6260,15 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } +void ASTWriter::VariableDefinitionInstantiated(const VarDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_VAR_DEFINITION)); +} + void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); @@ -6265,7 +6278,7 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } -void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { +void ASTWriter::InstantiationRequested(const ValueDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) @@ -6273,9 +6286,12 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { // Since the actual instantiation is delayed, this really means that we need // to update the instantiation location. - DeclUpdates[D].push_back( - DeclUpdate(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, - D->getMemberSpecializationInfo()->getPointOfInstantiation())); + SourceLocation POI; + if (auto *VD = dyn_cast(D)) + POI = VD->getPointOfInstantiation(); + else + POI = cast(D)->getPointOfInstantiation(); + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_POINT_OF_INSTANTIATION, POI)); } void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) { diff --git a/test/Modules/var-templates.cpp b/test/Modules/var-templates.cpp new file mode 100644 index 0000000000..20e431bc90 --- /dev/null +++ b/test/Modules/var-templates.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fmodules -std=c++14 -emit-llvm %s -o - | FileCheck %s + +#pragma clang module build A +module A {} +#pragma clang module contents +#pragma clang module begin A +template int n = 42; +decltype(n<0>) f(); +#pragma clang module end +#pragma clang module endbuild + +#pragma clang module build B +module B {} +#pragma clang module contents +#pragma clang module begin B +#pragma clang module import A +inline int f() { return n<0>; } +#pragma clang module end +#pragma clang module endbuild + +#pragma clang module import B + +// CHECK: @_Z1nILi0EE = linkonce_odr global i32 42, comdat +int g() { return f(); }