class QualType;
class RecordDecl;
class TagDecl;
+ class ValueDecl;
class VarDecl;
class VarTemplateDecl;
class VarTemplateSpecializationDecl;
/// \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) {}
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,
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;
dyn_cast<VarTemplateSpecializationDecl>(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);
+ }
}
}
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<MemberSpecializationInfo*>()) {
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");
}
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,
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) {
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);
// 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<CXXRecordDecl>(Func->getDeclContext()) &&
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
CodeSynthesisContexts.size())
TSK == TSK_ImplicitInstantiation ||
(TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
- if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(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(
// 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<VarTemplateSpecializationDecl>(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));
}
if (!HasNoEffect) {
// Instantiate static data member or variable template.
-
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (PrevTemplate) {
// Merge attributes.
continue;
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
} else {
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
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.
///
/// \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<VarTemplateSpecializationDecl>(Var);
VarDecl *PatternDecl = nullptr, *Def = nullptr;
// 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()) {
void Sema::completeExprArrayBound(Expr *E) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
if (VarDecl *Var = dyn_cast<VarDecl>(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<VarTemplateSpecializationDecl>(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);
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,
break;
}
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ case UPD_CXX_ADDED_VAR_DEFINITION: {
VarDecl *VD = cast<VarDecl>(D);
- VD->getMemberSpecializationInfo()->setPointOfInstantiation(
- ReadSourceLocation());
VD->NonParmVarDeclBits.IsInline = Record.readInt();
VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt();
uint64_t Val = Record.readInt();
break;
}
+ case UPD_CXX_POINT_OF_INSTANTIATION: {
+ SourceLocation POI = Record.readSourceLocation();
+ if (VarTemplateSpecializationDecl *VTSD =
+ dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ VTSD->setPointOfInstantiation(POI);
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ VD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ } else {
+ auto *FD = cast<FunctionDecl>(D);
+ if (auto *FTSInfo = FD->TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>())
+ FTSInfo->setPointOfInstantiation(POI);
+ else
+ FD->TemplateOrSpecialization.get<MemberSpecializationInfo *>()
+ ->setPointOfInstantiation(POI);
+ }
+ break;
+ }
+
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: {
auto Param = cast<ParmVarDecl>(D);
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
break;
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
- const VarDecl *VD = cast<VarDecl>(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<VarDecl>(D);
Record.push_back(VD->isInline());
Record.push_back(VD->isInlineSpecified());
if (VD->getInit()) {
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!");
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())
// 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<VarDecl>(D))
+ POI = VD->getPointOfInstantiation();
+ else
+ POI = cast<FunctionDecl>(D)->getPointOfInstantiation();
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_POINT_OF_INSTANTIATION, POI));
}
void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) {
--- /dev/null
+// 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> 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(); }