summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp57
-rw-r--r--clang/lib/AST/ASTImporter.cpp247
-rw-r--r--clang/lib/AST/Decl.cpp64
-rw-r--r--clang/lib/AST/DeclBase.cpp3
-rw-r--r--clang/lib/AST/DeclTemplate.cpp245
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp10
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp3
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp8
-rw-r--r--clang/lib/Frontend/MultiplexConsumer.cpp8
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp6
-rw-r--r--clang/lib/Parse/ParseDecl.cpp66
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp8
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp10
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp33
-rw-r--r--clang/lib/Parse/Parser.cpp6
-rw-r--r--clang/lib/Sema/SemaDecl.cpp245
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp6
-rw-r--r--clang/lib/Sema/SemaExpr.cpp134
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp645
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp213
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp42
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp768
-rw-r--r--clang/lib/Serialization/ASTCommon.cpp3
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp141
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp16
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp85
26 files changed, 2717 insertions, 355 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a3718fea338..63b1b0ead18 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1041,13 +1041,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) {
}
}
+// FIXME: Remove ?
MemberSpecializationInfo *
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
- llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos
- = InstantiatedFromStaticDataMember.find(Var);
- if (Pos == InstantiatedFromStaticDataMember.end())
- return 0;
+ return getTemplateOrSpecializationInfo(Var)
+ .dyn_cast<MemberSpecializationInfo *>();
+}
+
+ASTContext::TemplateOrSpecializationInfo
+ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) {
+ llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos =
+ TemplateOrInstantiation.find(Var);
+ if (Pos == TemplateOrInstantiation.end())
+ return TemplateOrSpecializationInfo();
return Pos->second;
}
@@ -1058,10 +1065,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
SourceLocation PointOfInstantiation) {
assert(Inst->isStaticDataMember() && "Not a static data member");
assert(Tmpl->isStaticDataMember() && "Not a static data member");
- assert(!InstantiatedFromStaticDataMember[Inst] &&
- "Already noted what static data member was instantiated from");
- InstantiatedFromStaticDataMember[Inst]
- = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
+ setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo(
+ Tmpl, TSK, PointOfInstantiation));
+}
+
+void
+ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst,
+ TemplateOrSpecializationInfo TSI) {
+ assert(!TemplateOrInstantiation[Inst] &&
+ "Already noted what the variable was instantiated from");
+ TemplateOrInstantiation[Inst] = TSI;
}
FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
@@ -7973,20 +7986,20 @@ MangleContext *ASTContext::createMangleContext() {
CXXABI::~CXXABI() {}
size_t ASTContext::getSideTableAllocatedMemory() const {
- return ASTRecordLayouts.getMemorySize()
- + llvm::capacity_in_bytes(ObjCLayouts)
- + llvm::capacity_in_bytes(KeyFunctions)
- + llvm::capacity_in_bytes(ObjCImpls)
- + llvm::capacity_in_bytes(BlockVarCopyInits)
- + llvm::capacity_in_bytes(DeclAttrs)
- + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember)
- + llvm::capacity_in_bytes(InstantiatedFromUsingDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
- + llvm::capacity_in_bytes(OverriddenMethods)
- + llvm::capacity_in_bytes(Types)
- + llvm::capacity_in_bytes(VariableArrayTypes)
- + llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+ return ASTRecordLayouts.getMemorySize() +
+ llvm::capacity_in_bytes(ObjCLayouts) +
+ llvm::capacity_in_bytes(KeyFunctions) +
+ llvm::capacity_in_bytes(ObjCImpls) +
+ llvm::capacity_in_bytes(BlockVarCopyInits) +
+ llvm::capacity_in_bytes(DeclAttrs) +
+ llvm::capacity_in_bytes(TemplateOrInstantiation) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) +
+ llvm::capacity_in_bytes(OverriddenMethods) +
+ llvm::capacity_in_bytes(Types) +
+ llvm::capacity_in_bytes(VariableArrayTypes) +
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
}
void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index deac0c5dfbe..922172701f0 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -106,6 +106,8 @@ namespace clang {
bool ImportDefinition(RecordDecl *From, RecordDecl *To,
ImportDefinitionKind Kind = IDK_Default);
+ bool ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To,
@@ -120,9 +122,12 @@ namespace clang {
SmallVectorImpl<TemplateArgument> &ToArgs);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
+ bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
+ bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
@@ -157,7 +162,9 @@ namespace clang {
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
Decl *VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D);
-
+ Decl *VisitVarTemplateDecl(VarTemplateDecl *D);
+ Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+
// Importing statements
Stmt *VisitStmt(Stmt *S);
@@ -2017,6 +2024,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
return false;
}
+bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition())
+ return false;
+
+ // FIXME: Can we really import any initializer? Alternatively, we could force
+ // ourselves to import every declaration of a variable and then only use
+ // getInit() here.
+ To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer())));
+
+ // FIXME: Other bits to merge?
+
+ return false;
+}
+
bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind) {
if (To->getDefinition() || To->isBeingDefined()) {
@@ -2162,6 +2184,14 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord);
}
+bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain) {
+ StructuralEquivalenceContext Ctx(
+ Importer.getFromContext(), Importer.getToContext(),
+ Importer.getNonEquivalentDecls(), false, Complain);
+ return Ctx.IsStructurallyEquivalent(FromVar, ToVar);
+}
+
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2188,6 +2218,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
return Ctx.IsStructurallyEquivalent(From, To);
}
+bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
+ VarTemplateDecl *To) {
+ StructuralEquivalenceContext Ctx(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getNonEquivalentDecls());
+ return Ctx.IsStructurallyEquivalent(From, To);
+}
+
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
@@ -3092,13 +3130,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
LexicalDC->addDeclInternal(ToVar);
// Merge the initializer.
- // FIXME: Can we really import any initializer? Alternatively, we could force
- // ourselves to import every declaration of a variable and then only use
- // getInit() here.
- ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
+ if (ImportDefinition(D, ToVar))
+ return 0;
- // FIXME: Other bits to merge?
-
return ToVar;
}
@@ -4112,6 +4146,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
return D2;
}
+Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ // If this variable has a definition in the translation unit we're coming
+ // from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition =
+ cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition());
+ if (Definition && Definition != D->getTemplatedDecl()) {
+ Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate());
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this variable template.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // We may already have a template of the same name; try to find and match it.
+ assert(!DC->isFunctionOrMethod() &&
+ "Variable templates cannot be declared at function scope");
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ Decl *Found = FoundDecls[I];
+ if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ // The variable templates structurally match; call it the same template.
+ Importer.Imported(D->getTemplatedDecl(),
+ FoundTemplate->getTemplatedDecl());
+ return Importer.Imported(D, FoundTemplate);
+ }
+ }
+
+ ConflictingDecls.push_back(FoundDecls[I]);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+
+ if (!Name)
+ return 0;
+
+ VarDecl *DTemplated = D->getTemplatedDecl();
+
+ // Import the type.
+ QualType T = Importer.Import(DTemplated->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the declaration that is being templated.
+ SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
+ SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
+ TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo());
+ VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc,
+ IdLoc, Name.getAsIdentifierInfo(), T,
+ TInfo, DTemplated->getStorageClass());
+ D2Templated->setAccess(DTemplated->getAccess());
+ D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
+ D2Templated->setLexicalDeclContext(LexicalDC);
+
+ // Importer.Imported(DTemplated, D2Templated);
+ // LexicalDC->addDeclInternal(D2Templated);
+
+ // Merge the initializer.
+ if (ImportDefinition(DTemplated, D2Templated))
+ return 0;
+
+ // Create the variable template declaration itself.
+ TemplateParameterList *TemplateParams =
+ ImportTemplateParameterList(D->getTemplateParameters());
+ if (!TemplateParams)
+ return 0;
+
+ VarTemplateDecl *D2 = VarTemplateDecl::Create(
+ Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated,
+ /*PrevDecl=*/0);
+ D2Templated->setDescribedVarTemplate(D2);
+
+ D2->setAccess(D->getAccess());
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+
+ // Note the relationship between the variable templates.
+ Importer.Imported(D, D2);
+ Importer.Imported(DTemplated, D2Templated);
+
+ if (DTemplated->isThisDeclarationADefinition() &&
+ !D2Templated->isThisDeclarationADefinition()) {
+ // FIXME: Import definition!
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>(
+ Importer.Import(D->getSpecializedTemplate()));
+ if (!VarTemplate)
+ return 0;
+
+ // Import the context of this declaration.
+ DeclContext *DC = VarTemplate->getDeclContext();
+ if (!DC)
+ return 0;
+
+ DeclContext *LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+ }
+
+ // Import the location of this declaration.
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
+ SourceLocation IdLoc = Importer.Import(D->getLocation());
+
+ // Import template arguments.
+ SmallVector<TemplateArgument, 2> TemplateArgs;
+ if (ImportTemplateArguments(D->getTemplateArgs().data(),
+ D->getTemplateArgs().size(), TemplateArgs))
+ return 0;
+
+ // Try to find an existing specialization with these template arguments.
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization(
+ TemplateArgs.data(), TemplateArgs.size(), InsertPos);
+ if (D2) {
+ // We already have a variable template specialization with these template
+ // arguments.
+
+ // FIXME: Check for specialization vs. instantiation errors.
+
+ if (VarDecl *FoundDef = D2->getDefinition()) {
+ if (!D->isThisDeclarationADefinition() ||
+ IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // variable.
+ return Importer.Imported(D, FoundDef);
+ }
+ }
+ } else {
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+
+ // Create a new specialization.
+ D2 = VarTemplateSpecializationDecl::Create(
+ Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo,
+ D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size());
+ D2->setSpecializationKind(D->getSpecializationKind());
+ D2->setTemplateArgsInfo(D->getTemplateArgsInfo());
+
+ // Add this specialization to the class template.
+ VarTemplate->AddSpecialization(D2, InsertPos);
+
+ // Import the qualifier, if any.
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
+
+ // Add the specialization to this context.
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+ }
+ Importer.Imported(D, D2);
+
+ if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2))
+ return 0;
+
+ return D2;
+}
+
//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 772f7353c36..9562879de6a 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1557,6 +1557,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
llvm_unreachable("Invalid storage class");
}
+VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC)
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
+ assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
+ assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
+ AllBits = 0;
+ VarDeclBits.SClass = SC;
+ // Everything else is implicitly initialized to false.
+}
+
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
@@ -1952,28 +1963,63 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
return TSK_Undeclared;
}
+VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<VarTemplateDecl *>();
+}
+
+void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) {
+ getASTContext().setTemplateOrSpecializationInfo(this, Template);
+}
+
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
if (isStaticDataMember())
- return getASTContext().getInstantiatedFromStaticDataMember(this);
-
+ // FIXME: Remove ?
+ // return getASTContext().getInstantiatedFromStaticDataMember(this);
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<MemberSpecializationInfo *>();
return 0;
}
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation) {
- MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
- assert(MSI && "Not an instantiated static data member?");
- MSI->setTemplateSpecializationKind(TSK);
- if (TSK != TSK_ExplicitSpecialization &&
- PointOfInstantiation.isValid() &&
- MSI->getPointOfInstantiation().isInvalid())
- MSI->setPointOfInstantiation(PointOfInstantiation);
+ if (VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this)) {
+ Spec->setSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ Spec->getPointOfInstantiation().isInvalid())
+ Spec->setPointOfInstantiation(PointOfInstantiation);
+ return;
+ }
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
+ MSI->setTemplateSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ MSI->getPointOfInstantiation().isInvalid())
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ return;
+ }
+
+ llvm_unreachable(
+ "Not a variable or static data member template specialization");
+}
+
+void
+VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD,
+ TemplateSpecializationKind TSK) {
+ assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() &&
+ "Previous template or instantiation?");
+ getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 13bde4ca860..e99f7ec5b06 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -538,6 +538,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Namespace;
case FunctionTemplate:
+ case VarTemplate:
return IDNS_Ordinary;
case ClassTemplate:
@@ -560,6 +561,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
case ClassScopeFunctionSpecialization:
+ case VarTemplateSpecialization:
+ case VarTemplatePartialSpecialization:
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index ac0d54f5011..555800a8bef 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -958,3 +958,248 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0,
false, TemplateArgumentListInfo());
}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void VarTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+
+VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl,
+ VarTemplateDecl *PrevDecl) {
+ VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl);
+ New->setPreviousDeclaration(PrevDecl);
+ return New;
+}
+
+VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl));
+ return new (Mem) VarTemplateDecl(EmptyShell());
+}
+
+// FIXME: Should this be unified accross class, function and variable
+// templates? Perhaps also moved to RedeclarableTemplateDecl?
+void VarTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
+VarTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
+llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
+VarTemplateDecl::getPartialSpecializations() {
+ LoadLazySpecializations();
+ return getCommonPtr()->PartialSpecializations;
+}
+
+RedeclarableTemplateDecl::CommonBase *
+VarTemplateDecl::newCommon(ASTContext &C) const {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ return CommonPtr;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateDecl::findSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+}
+
+void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
+ void *InsertPos) {
+ if (InsertPos)
+ getSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplateSpecializationDecl *Existing =
+ getSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs,
+ InsertPos);
+}
+
+void VarTemplateDecl::AddPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *D, void *InsertPos) {
+ if (InsertPos)
+ getPartialSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplatePartialSpecializationDecl *Existing =
+ getPartialSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+void VarTemplateDecl::getPartialSpecializations(
+ SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) {
+ llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs =
+ getPartialSpecializations();
+ PS.clear();
+ PS.resize(PartialSpecs.size());
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = PartialSpecs.begin(),
+ PEnd = PartialSpecs.end();
+ P != PEnd; ++P) {
+ assert(!PS[P->getSequenceNumber()]);
+ PS[P->getSequenceNumber()] = P->getMostRecentDecl();
+ }
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecInstantiatedFromMember(
+ VarTemplatePartialSpecializationDecl *D) {
+ Decl *DCanon = D->getCanonicalDecl();
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = getPartialSpecializations().begin(),
+ PEnd = getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+ return P->getMostRecentDecl();
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(
+ ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs)
+ : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T,
+ TInfo, S),
+ SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0),
+ TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
+ SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK)
+ : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0,
+ SC_None),
+ ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs) {
+ VarTemplateSpecializationDecl *Result = new (Context)
+ VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC,
+ StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs);
+ return Result;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem =
+ AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl));
+ VarTemplateSpecializationDecl *Result =
+ new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization);
+ return Result;
+}
+
+void VarTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
+
+ const TemplateArgumentList &TemplateArgs = getTemplateArgs();
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
+}
+
+VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return PartialSpec->PartialSpecialization->getSpecializedTemplate();
+ return SpecializedTemplate.get<VarTemplateDecl *>();
+}
+
+void VarTemplateSpecializationDecl::setTemplateArgsInfo(
+ const TemplateArgumentListInfo &ArgsInfo) {
+ unsigned N = ArgsInfo.size();
+ TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc());
+ TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc());
+ for (unsigned I = 0; I != N; ++I)
+ TemplateArgsInfo.addArgument(ArgsInfo[I]);
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+void VarTemplatePartialSpecializationDecl::anchor() {}
+
+VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ TemplateArgumentLoc *ArgInfos, unsigned NumArgInfos,
+ unsigned SequenceNumber)
+ : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization,
+ DC, StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs),
+ TemplateParams(Params), ArgsAsWritten(ArgInfos),
+ NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
+ InstantiatedFromMember(0, false) {
+ // TODO: The template parameters should be in DC by now. Verify.
+ // AdoptTemplateParameterList(Params, DC);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const TemplateArgumentListInfo &ArgInfos, unsigned SequenceNumber) {
+ unsigned N = ArgInfos.size();
+ TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
+ for (unsigned I = 0; I != N; ++I)
+ ClonedArgs[I] = ArgInfos[I];
+
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Context) VarTemplatePartialSpecializationDecl(
+ Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
+ S, Args, NumArgs, ClonedArgs, N, SequenceNumber);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ return Result;
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(
+ C, ID, sizeof(VarTemplatePartialSpecializationDecl));
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Mem) VarTemplatePartialSpecializationDecl();
+ return Result;
+}
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 9bce9a0fa3b..ac551d8695b 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -432,7 +432,8 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
- if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage)
+ if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
+ !isa<VarTemplateSpecializationDecl>(D))
return false;
}
@@ -554,6 +555,13 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return Spec->getSpecializedTemplate();
}
+ // Check if we have a variable template.
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
return 0;
}
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 49364e6b563..970f9781b78 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -37,6 +37,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::UnresolvedUsingTypename:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
case Decl::TemplateTypeParm:
case Decl::UnresolvedUsingValue:
case Decl::NonTypeTemplateParm:
@@ -52,6 +54,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::ParmVar:
case Decl::ImplicitParam:
case Decl::ClassTemplate:
+ case Decl::VarTemplate:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
case Decl::TemplateTemplateParm:
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 21edc7e6513..dbdf016b31b 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2841,8 +2841,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitGlobal(cast<FunctionDecl>(D));
break;
-
+
case Decl::Var:
+ // Skip variable templates
+ if (cast<VarDecl>(D)->getDescribedVarTemplate())
+ return;
+ case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
break;
@@ -2859,6 +2863,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::UsingShadow:
case Decl::Using:
case Decl::ClassTemplate:
+ case Decl::VarTemplate:
+ case Decl::VarTemplatePartialSpecialization:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
case Decl::Block:
diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp
index 7ed9d36ca3b..f8ee36a50dc 100644
--- a/clang/lib/Frontend/MultiplexConsumer.cpp
+++ b/clang/lib/Frontend/MultiplexConsumer.cpp
@@ -94,6 +94,9 @@ public:
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D);
+ virtual void
+ AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
+ const VarTemplateSpecializationDecl *D);
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D);
virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
@@ -135,6 +138,11 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
+ const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
+}
+void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
const FunctionTemplateDecl *TD, const FunctionDecl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index e04685cfa4d..9f832e5195e 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -55,11 +55,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
TemplateParams, 0,
VS, ICIS_NoInit);
if (FnD) {
- Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
- false, true);
+ Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false,
+ true);
bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType();
if (Init.isUsable())
- Actions.AddInitializerToDecl(FnD, Init.get(), false,
+ Actions.AddInitializerToDecl(FnD, Init.get(), false,
TypeSpecContainsAuto);
else
Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 0b276d0b58f..80fab62f41e 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -1797,24 +1797,69 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
break;
case ParsedTemplateInfo::Template:
- case ParsedTemplateInfo::ExplicitSpecialization:
+ case ParsedTemplateInfo::ExplicitSpecialization: {
ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(),
*TemplateInfo.TemplateParams,
D);
- break;
- case ParsedTemplateInfo::ExplicitInstantiation: {
- DeclResult ThisRes
- = Actions.ActOnExplicitInstantiation(getCurScope(),
- TemplateInfo.ExternLoc,
- TemplateInfo.TemplateLoc,
- D);
- if (ThisRes.isInvalid()) {
+ // If this is a forward declaration of a variable template or variable
+ // template partial specialization with nested name specifier, complain.
+ // FIXME: Move to Sema.
+ CXXScopeSpec &SS = D.getCXXScopeSpec();
+ if (Tok.is(tok::semi) && ThisDecl && SS.isNotEmpty() &&
+ (isa<VarTemplateDecl>(ThisDecl) ||
+ isa<VarTemplatePartialSpecializationDecl>(ThisDecl))) {
+ Diag(SS.getBeginLoc(), diag::err_forward_var_nested_name_specifier)
+ << isa<VarTemplatePartialSpecializationDecl>(ThisDecl)
+ << SS.getRange();
SkipUntil(tok::semi, true, true);
return 0;
}
- ThisDecl = ThisRes.get();
+ if (VarTemplateDecl *VT =
+ ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0)
+ // Re-direct this decl to refer to the templated decl so that we can
+ // initialize it.
+ ThisDecl = VT->getTemplatedDecl();
+ break;
+ }
+ case ParsedTemplateInfo::ExplicitInstantiation: {
+ if (Tok.is(tok::semi)) {
+ DeclResult ThisRes = Actions.ActOnExplicitInstantiation(
+ getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D);
+ if (ThisRes.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return 0;
+ }
+ ThisDecl = ThisRes.get();
+ } else {
+ // FIXME: This check should be for a variable template instantiation only.
+
+ // Check that this is a valid instantiation
+ if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ // If the declarator-id is not a template-id, issue a diagnostic and
+ // recover by ignoring the 'template' keyword.
+ Diag(Tok, diag::err_template_defn_explicit_instantiation)
+ << 2 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
+ ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
+ } else {
+ SourceLocation LAngleLoc =
+ PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
+
+ // Recover as if it were an explicit specialization.
+ TemplateParameterLists FakedParamLists;
+ FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
+ LAngleLoc));
+
+ ThisDecl =
+ Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D);
+ }
+ }
break;
}
}
@@ -1825,6 +1870,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
// If a '==' or '+=' is found, suggest a fixit to '='.
if (isTokenEqualOrEqualTypo()) {
ConsumeToken();
+
if (Tok.is(tok::kw_delete)) {
if (D.isFunctionDeclarator())
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8df15ba75df..e62be697893 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -15,6 +15,7 @@
#include "RAIIObjectsForParser.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -2264,6 +2265,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
TemplateParams,
BitfieldSize.release(),
VS, HasInClassInit);
+
+ if (VarTemplateDecl *VT =
+ ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0)
+ // Re-direct this decl to refer to the templated decl so that we can
+ // initialize it.
+ ThisDecl = VT->getTemplatedDecl();
+
if (ThisDecl && AccessAttrs)
Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs,
false, true);
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 9704b98d48e..d4a83fb0c9c 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -465,8 +465,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TemplateName, false))
return true;
continue;
- }
-
+ }
+
if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
(IsTypename || IsTemplateArgumentList(1))) {
// We have something like t::getAs<T>, where getAs is a
@@ -561,6 +561,12 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// '::' unqualified-id
//
CXXScopeSpec SS;
+ if (Tok.getKind() == tok::annot_template_id) {
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ // FIXME: This is a hack for now. It may need to be done from within
+ // ParseUnqualifiedId(), or most likely ParseOptionalCXXScopeSpecifier();
+ SS = TemplateId->SS;
+ }
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
SourceLocation TemplateKWLoc;
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index d8ad2597115..fa23bd1face 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -242,32 +242,31 @@ Parser::ParseSingleDeclarationAfterTemplate(
// If the declarator-id is not a template-id, issue a diagnostic and
// recover by ignoring the 'template' keyword.
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
- return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
- &LateParsedAttrs);
+ return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
+ &LateParsedAttrs);
} else {
SourceLocation LAngleLoc
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
- Diag(DeclaratorInfo.getIdentifierLoc(),
+ Diag(DeclaratorInfo.getIdentifierLoc(),
diag::err_explicit_instantiation_with_definition)
- << SourceRange(TemplateInfo.TemplateLoc)
- << FixItHint::CreateInsertion(LAngleLoc, "<>");
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
- // Recover as if it were an explicit specialization.
+ // Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
- FakedParamLists.push_back(
- Actions.ActOnTemplateParameterList(0, SourceLocation(),
- TemplateInfo.TemplateLoc,
- LAngleLoc, 0, 0, LAngleLoc));
-
- return ParseFunctionDefinition(DeclaratorInfo,
- ParsedTemplateInfo(&FakedParamLists,
- /*isSpecialization=*/true,
- /*LastParamListWasEmpty=*/true),
- &LateParsedAttrs);
+ FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
+ LAngleLoc));
+
+ return ParseFunctionDefinition(
+ DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
+ /*isSpecialization=*/true,
+ /*LastParamListWasEmpty=*/true),
+ &LateParsedAttrs);
}
}
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
- &LateParsedAttrs);
+ &LateParsedAttrs);
}
// Parse this declaration.
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 036278f72ed..8f894818bb4 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1437,8 +1437,9 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
return ANK_TemplateName;
}
// Fall through.
+ case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate: {
- // We have a type or function template followed by '<'.
+ // We have a type, variable or function template followed by '<'.
ConsumeToken();
UnqualifiedId Id;
Id.setIdentifier(Name, NameLoc);
@@ -1653,7 +1654,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
// annotation token to a type annotation token now.
AnnotateTemplateIdTokenAsType();
return false;
- }
+ } else if (TemplateId->Kind == TNK_Var_template)
+ return false;
}
if (SS.isEmpty())
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index aca71b05928..80ac1167ffa 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -799,6 +799,7 @@ Corrected:
if (!Result.empty()) {
bool IsFunctionTemplate;
+ bool IsVarTemplate;
TemplateName Template;
if (Result.end() - Result.begin() > 1) {
IsFunctionTemplate = true;
@@ -808,7 +809,8 @@ Corrected:
TemplateDecl *TD
= cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl());
IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
-
+ IsVarTemplate = isa<VarTemplateDecl>(TD);
+
if (SS.isSet() && !SS.isInvalid())
Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
/*TemplateKeyword=*/false,
@@ -825,8 +827,9 @@ Corrected:
return NameClassification::FunctionTemplate(Template);
}
-
- return NameClassification::TypeTemplate(Template);
+
+ return IsVarTemplate ? NameClassification::VarTemplate(Template)
+ : NameClassification::TypeTemplate(Template);
}
}
@@ -3013,8 +3016,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
if (getLangOpts().CPlusPlus &&
New->isThisDeclarationADefinition() == VarDecl::Definition &&
(Def = Old->getDefinition())) {
- Diag(New->getLocation(), diag::err_redefinition)
- << New->getDeclName();
+ Diag(New->getLocation(), diag::err_redefinition) << New;
Diag(Def->getLocation(), diag::note_previous_definition);
New->setInvalidDecl();
return;
@@ -4258,8 +4260,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
TemplateParamLists,
AddToScope);
} else {
- New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
- TemplateParamLists);
+ New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists,
+ AddToScope);
}
if (New == 0)
@@ -4768,10 +4770,11 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) {
llvm_unreachable("Unexpected context");
}
-NamedDecl*
+NamedDecl *
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists) {
+ MultiTemplateParamsArg TemplateParamLists,
+ bool &AddToScope) {
QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
@@ -4862,7 +4865,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- bool isExplicitSpecialization = false;
+ bool IsExplicitSpecialization = false;
+ bool IsVariableTemplateSpecialization = false;
+ bool IsPartialSpecialization = false;
+ bool Invalid = false; // TODO: Can we remove this (error-prone)?
+ TemplateParameterList *TemplateParams = 0;
+ VarTemplateDecl *PrevVarTemplate = 0;
VarDecl *NewVD;
if (!getLangOpts().CPlusPlus) {
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
@@ -4922,23 +4930,20 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ NamedDecl *PrevDecl = 0;
+ if (Previous.begin() != Previous.end())
+ PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+ PrevVarTemplate = dyn_cast_or_null<VarTemplateDecl>(PrevDecl);
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
- isExplicitSpecialization = false;
- bool Invalid = false;
- if (TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateParamLists,
- /*never a friend*/ false, isExplicitSpecialization, Invalid)) {
- if (TemplateParams->size() > 0) {
- // There is no such thing as a variable template.
- Diag(D.getIdentifierLoc(), diag::err_template_variable)
- << II
- << SourceRange(TemplateParams->getTemplateLoc(),
- TemplateParams->getRAngleLoc());
- return 0;
- } else {
+ TemplateParams = MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(), TemplateParamLists,
+ /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+ if (TemplateParams) {
+ if (!TemplateParams->size() &&
+ D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
// There is an extraneous 'template<>' for this variable. Complain
// about it, but allow the declaration of the variable.
Diag(TemplateParams->getTemplateLoc(),
@@ -4946,12 +4951,116 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
+ } else {
+ // Only C++1y supports variable templates (N3651).
+ Diag(D.getIdentifierLoc(),
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_variable_template
+ : diag::ext_variable_template);
+
+ if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
+ // This is an explicit specialization or a partial specialization.
+ // Check that we can declare a specialization here
+
+ IsVariableTemplateSpecialization = true;
+ IsPartialSpecialization = TemplateParams->size() > 0;
+
+ } else { // if (TemplateParams->size() > 0)
+ // This is a template declaration.
+
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return 0;
+
+ // If there is a previous declaration with the same name, check
+ // whether this is a valid redeclaration.
+ if (PrevDecl && !isDeclInScope(PrevDecl, DC, S))
+ PrevDecl = PrevVarTemplate = 0;
+
+ if (PrevVarTemplate) {
+ // Ensure that the template parameter lists are compatible.
+ if (!TemplateParameterListsAreEqual(
+ TemplateParams, PrevVarTemplate->getTemplateParameters(),
+ /*Complain=*/true, TPL_TemplateMatch))
+ return 0;
+ } else if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
+
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ } else if (PrevDecl) {
+ // C++ [temp]p5:
+ // ... a template name declared in namespace scope or in class
+ // scope shall be unique in that scope.
+ Diag(D.getIdentifierLoc(), diag::err_redefinition_different_kind)
+ << Name;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ return 0;
+ }
+
+ // Check the template parameter list of this declaration, possibly
+ // merging in the template parameter list from the previous variable
+ // template declaration.
+ if (CheckTemplateParameterList(
+ TemplateParams,
+ PrevVarTemplate ? PrevVarTemplate->getTemplateParameters()
+ : 0,
+ (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() &&
+ DC->isDependentContext())
+ ? TPC_ClassTemplateMember
+ : TPC_VarTemplate))
+ Invalid = true;
+
+ if (D.getCXXScopeSpec().isSet()) {
+ // If the name of the template was qualified, we must be defining
+ // the template out-of-line.
+ if (!D.getCXXScopeSpec().isInvalid() && !Invalid &&
+ !PrevVarTemplate) {
+ Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
+ << Name << DC << D.getCXXScopeSpec().getRange();
+ Invalid = true;
+ }
+ }
+ }
}
+ } else if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
+ TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+
+ // We have encountered something that the user meant to be a
+ // specialization (because it has explicitly-specified template
+ // arguments) but that was not introduced with a "template<>" (or had
+ // too few of them).
+ // FIXME: Differentiate between attempts for explicit instantiations
+ // (starting with "template") and the rest.
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
+ << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
+ << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(),
+ "template<> ");
+ IsVariableTemplateSpecialization = true;
}
- NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
- D.getIdentifierLoc(), II,
- R, TInfo, SC);
+ if (IsVariableTemplateSpecialization) {
+ if (!PrevVarTemplate) {
+ Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template)
+ << IsPartialSpecialization;
+ return 0;
+ }
+
+ SourceLocation TemplateKWLoc =
+ TemplateParamLists.size() > 0
+ ? TemplateParamLists[0]->getTemplateLoc()
+ : SourceLocation();
+ DeclResult Res = ActOnVarTemplateSpecialization(
+ S, PrevVarTemplate, D, TInfo, TemplateKWLoc, TemplateParams, SC,
+ IsPartialSpecialization);
+ if (Res.isInvalid())
+ return 0;
+ NewVD = cast<VarDecl>(Res.get());
+ AddToScope = false;
+ } else
+ NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
+ D.getIdentifierLoc(), II, R, TInfo, SC);
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
@@ -4963,7 +5072,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
SetNestedNameSpecifier(NewVD, D);
- if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) {
+ // FIXME: Do we need D.getCXXScopeSpec().isSet()?
+ if (TemplateParams && TemplateParamLists.size() > 1 &&
+ (!IsVariableTemplateSpecialization || D.getCXXScopeSpec().isSet())) {
+ NewVD->setTemplateParameterListsInfo(
+ Context, TemplateParamLists.size() - 1, TemplateParamLists.data());
+ } else if (IsVariableTemplateSpecialization ||
+ (!TemplateParams && TemplateParamLists.size() > 0 &&
+ (D.getCXXScopeSpec().isSet()))) {
NewVD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
TemplateParamLists.data());
@@ -5020,7 +5136,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (D.getDeclSpec().isModulePrivateSpecified()) {
- if (isExplicitSpecialization)
+ if (IsVariableTemplateSpecialization)
+ Diag(NewVD->getLocation(), diag::err_module_private_specialization)
+ << (IsPartialSpecialization ? 1 : 0)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getModulePrivateSpecLoc());
+ else if (IsExplicitSpecialization)
Diag(NewVD->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
@@ -5089,15 +5210,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// Diagnose shadowed variables before filtering for scope.
+ // FIXME: Special treatment for static variable template members (?).
if (!D.getCXXScopeSpec().isSet())
CheckShadow(S, NewVD, Previous);
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD),
- isExplicitSpecialization);
-
+ FilterLookupForScope(
+ Previous, DC, S, shouldConsiderLinkage(NewVD),
+ IsExplicitSpecialization || IsVariableTemplateSpecialization);
+
if (!getLangOpts().CPlusPlus) {
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
} else {
@@ -5121,10 +5244,19 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
- D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+ if (!IsVariableTemplateSpecialization) {
+ if (PrevVarTemplate) {
+ LookupResult PrevDecl(*this, GetNameForDeclarator(D),
+ LookupOrdinaryName, ForRedeclaration);
+ PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
+ } else
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+ }
// This is an explicit specialization of a static data member. Check it.
- if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ // FIXME: Special treatment for static variable template members (?).
+ if (IsExplicitSpecialization && !NewVD->isInvalidDecl() &&
CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();
}
@@ -5147,7 +5279,45 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- return NewVD;
+ // If this is not a variable template, return it now
+ if (!TemplateParams || IsVariableTemplateSpecialization)
+ return NewVD;
+
+ // If this is supposed to be a variable template, create it as such.
+ VarTemplateDecl *NewTemplate =
+ VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
+ TemplateParams, NewVD, PrevVarTemplate);
+ NewVD->setDescribedVarTemplate(NewTemplate);
+
+ if (D.getDeclSpec().isModulePrivateSpecified())
+ NewTemplate->setModulePrivate();
+
+ // If we are providing an explicit specialization of a static variable
+ // template, make a note of that.
+ if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate())
+ NewTemplate->setMemberSpecialization();
+
+ // Set the lexical context of this template
+ NewTemplate->setLexicalDeclContext(CurContext);
+ if (NewVD->isStaticDataMember() && NewVD->isOutOfLine())
+ NewTemplate->setAccess(NewVD->getAccess());
+
+ if (PrevVarTemplate)
+ mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl());
+
+ AddPushedVisibilityAttribute(NewVD);
+
+ PushOnScopeChains(NewTemplate, S);
+ AddToScope = false;
+
+ if (Invalid) {
+ NewTemplate->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ }
+
+ ActOnDocumentableDecl(NewTemplate);
+
+ return NewTemplate;
}
/// \brief Diagnose variable or built-in function shadowing. Implements
@@ -6705,6 +6875,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// specialization (because it has explicitly-specified template
// arguments) but that was not introduced with a "template<>" (or had
// too few of them).
+ // FIXME: Differentiate between attempts for explicit instantiations
+ // (starting with "template") and the rest.
Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
<< FixItHint::CreateInsertion(
@@ -7666,7 +7838,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
RealDecl->setInvalidDecl();
return;
}
-
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3df0472df6b..bd8b566769c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2001,10 +2001,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Member->setAccess(AS);
- // If we have declared a member function template, set the access of the
- // templated declaration as well.
+ // If we have declared a member function template or static data member
+ // template, set the access of the templated declaration as well.
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member))
FunTmpl->getTemplatedDecl()->setAccess(AS);
+ else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member))
+ VarTmpl->getTemplatedDecl()->setAccess(AS);
}
if (VS.isOverrideSpecified())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8d370ce9063..8038a4502ab 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1559,7 +1559,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS, NamedDecl *FoundD) {
+ const CXXScopeSpec *SS, NamedDecl *FoundD,
+ const TemplateArgumentListInfo *TemplateArgs) {
if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
@@ -1578,12 +1579,24 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
(CurContext != D->getDeclContext() &&
D->getDeclContext()->isFunctionOrMethod());
- DeclRefExpr *E = DeclRefExpr::Create(Context,
- SS ? SS->getWithLocInContext(Context)
- : NestedNameSpecifierLoc(),
- SourceLocation(),
- D, refersToEnclosingScope,
- NameInfo, Ty, VK, FoundD);
+ DeclRefExpr *E;
+ if (isa<VarTemplateSpecializationDecl>(D)) {
+ VarTemplateSpecializationDecl *VarSpec =
+ cast<VarTemplateSpecializationDecl>(D);
+
+ E = DeclRefExpr::Create(
+ Context,
+ SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
+ VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope,
+ NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs);
+ } else {
+ assert(!TemplateArgs && "No template arguments for non-variable"
+ " template specialization referrences");
+ E = DeclRefExpr::Create(
+ Context,
+ SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
+ SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD);
+ }
MarkDeclRefReferenced(E);
@@ -1870,7 +1883,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
bool IsInlineAsmIdentifier) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
-
if (SS.isInvalid())
return ExprError();
@@ -1961,6 +1973,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
if (R.empty() && !ADL) {
+
// Otherwise, this could be an implicitly declared function reference (legal
// in C90, extension in C99, forbidden in C++).
if (HasTrailingLParen && II && !getLangOpts().CPlusPlus) {
@@ -2056,8 +2069,19 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
R, TemplateArgs);
}
- if (TemplateArgs || TemplateKWLoc.isValid())
+ if (TemplateArgs || TemplateKWLoc.isValid()) {
+
+ // In C++1y, if this is a variable template id, then check it
+ // in BuildTemplateIdExpr().
+ // The single lookup result must be a variable template declaration.
+ if (Id.getKind() == UnqualifiedId::IK_TemplateId && Id.TemplateId &&
+ Id.TemplateId->Kind == TNK_Var_template) {
+ assert(R.getAsSingle<VarTemplateDecl>() &&
+ "There should only be one declaration found.");
+ }
+
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs);
+ }
return BuildDeclarationNameExpr(SS, R, ADL);
}
@@ -2524,10 +2548,9 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
/// \brief Complete semantic analysis for a reference to the given declaration.
-ExprResult
-Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- NamedDecl *D, NamedDecl *FoundD) {
+ExprResult Sema::BuildDeclarationNameExpr(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
+ NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) {
assert(D && "Cannot refer to a NULL declaration");
assert(!isa<FunctionTemplateDecl>(D) &&
"Cannot refer unambiguously to a function template");
@@ -2539,8 +2562,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
// Specifically diagnose references to class templates that are missing
// a template argument list.
- Diag(Loc, diag::err_template_decl_ref)
- << Template << SS.getRange();
+ Diag(Loc, diag::err_template_decl_ref) << (isa<VarTemplateDecl>(D) ? 1 : 0)
+ << Template << SS.getRange();
Diag(Template->getLocation(), diag::note_template_decl_here);
return ExprError();
}
@@ -2630,6 +2653,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
case Decl::Var:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
// In C, "extern void blah;" is valid and is an r-value.
if (!getLangOpts().CPlusPlus &&
!type.hasQualifiers() &&
@@ -2727,7 +2752,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
break;
}
- return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD);
+ return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
+ TemplateArgs);
}
}
@@ -11690,28 +11716,64 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (!IsPotentiallyEvaluatedContext(SemaRef))
return;
- // Implicit instantiation of static data members of class templates.
- if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) {
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
+
+ // Implicit instantiation of static data members, static data member
+ // templates of class templates, and variable template specializations.
+ // Delay instantiations of variable templates, except for those
+ // that could be used in a constant expression.
+ if (VarSpec || (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember())) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
- bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
- if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation &&
- (!AlreadyInstantiated ||
- Var->isUsableInConstantExpressions(SemaRef.Context))) {
- if (!AlreadyInstantiated) {
- // This is a modification of an existing AST node. Notify listeners.
- if (ASTMutationListener *L = SemaRef.getASTMutationListener())
- L->StaticDataMemberInstantiated(Var);
- MSInfo->setPointOfInstantiation(Loc);
+ if (VarSpec)
+ assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
+ "Can't instantiate a partial template specialization.");
+ if (Var->isStaticDataMember())
+ assert(MSInfo && "Missing member specialization information?");
+
+ SourceLocation PointOfInstantiation;
+ bool InstantiationIsOkay = true;
+ if (MSInfo) {
+ bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
+ TemplateSpecializationKind TSK = MSInfo->getTemplateSpecializationKind();
+
+ if (TSK == TSK_ImplicitInstantiation &&
+ (!AlreadyInstantiated ||
+ Var->isUsableInConstantExpressions(SemaRef.Context))) {
+ if (!AlreadyInstantiated) {
+ // This is a modification of an existing AST node. Notify listeners.
+ if (ASTMutationListener *L = SemaRef.getASTMutationListener())
+ L->StaticDataMemberInstantiated(Var);
+ MSInfo->setPointOfInstantiation(Loc);
+ }
+ PointOfInstantiation = MSInfo->getPointOfInstantiation();
+ } else
+ InstantiationIsOkay = false;
+ } else {
+ if (VarSpec->getPointOfInstantiation().isInvalid())
+ VarSpec->setPointOfInstantiation(Loc);
+ PointOfInstantiation = VarSpec->getPointOfInstantiation();
+ }
+
+ if (InstantiationIsOkay) {
+ bool InstantiationDependent = false;
+ bool IsNonDependent =
+ VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(
+ VarSpec->getTemplateArgsInfo(), InstantiationDependent)
+ : true;
+
+ // Do not instantiate specializations that are still type-dependent.
+ if (IsNonDependent) {
+ if (Var->isUsableInConstantExpressions(SemaRef.Context)) {
+ // Do not defer instantiations of variables which could be used in a
+ // constant expression.
+ SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ } else {
+ SemaRef.PendingInstantiations
+ .push_back(std::make_pair(Var, PointOfInstantiation));
+ }
}
- SourceLocation PointOfInstantiation = MSInfo->getPointOfInstantiation();
- if (Var->isUsableInConstantExpressions(SemaRef.Context))
- // Do not defer instantiations of variables which could be used in a
- // constant expression.
- SemaRef.InstantiateStaticDataMemberDefinition(PointOfInstantiation,Var);
- else
- SemaRef.PendingInstantiations.push_back(
- std::make_pair(Var, PointOfInstantiation));
}
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index af0eb08f203..098187244a6 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11,6 +11,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -207,8 +208,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
R.suppressDiagnostics();
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
- isa<TypeAliasTemplateDecl>(TD));
- TemplateKind = TNK_Type_template;
+ isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD));
+ TemplateKind =
+ isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
}
}
@@ -1159,6 +1161,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
SourceRange DefArgRange) {
switch (TPC) {
case Sema::TPC_ClassTemplate:
+ case Sema::TPC_VarTemplate:
case Sema::TPC_TypeAliasTemplate:
return false;
@@ -1430,7 +1433,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// If a template parameter of a primary class template or alias template
// is a template parameter pack, it shall be the last template parameter.
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
- (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
+ (TPC == TPC_ClassTemplate || TPC == TPC_VarTemplate ||
+ TPC == TPC_TypeAliasTemplate)) {
Diag((*NewParam)->getLocation(),
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
@@ -1924,11 +1928,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
void Sema::NoteAllFoundTemplates(TemplateName Name) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
Diag(Template->getLocation(), diag::note_template_declared_here)
- << (isa<FunctionTemplateDecl>(Template)? 0
- : isa<ClassTemplateDecl>(Template)? 1
- : isa<TypeAliasTemplateDecl>(Template)? 2
- : 3)
- << Template->getDeclName();
+ << (isa<FunctionTemplateDecl>(Template)
+ ? 0
+ : isa<ClassTemplateDecl>(Template)
+ ? 1
+ : isa<VarTemplateDecl>(Template)
+ ? 2
+ : isa<TypeAliasTemplateDecl>(Template) ? 3 : 4)
+ << Template->getDeclName();
return;
}
@@ -2263,6 +2270,452 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
+static bool CheckTemplatePartialSpecializationArgs(
+ Sema &S, TemplateParameterList *TemplateParams,
+ SmallVectorImpl<TemplateArgument> &TemplateArgs);
+
+static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
+ NamedDecl *PrevDecl,
+ SourceLocation Loc,
+ bool IsPartialSpecialization);
+
+static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
+/*
+/// \brief Check the new variable specialization against the parsed input.
+///
+/// FIXME: Model this against function specializations where
+/// a new function declaration is checked against the specialization
+/// as candidate for redefinition... (?)
+static bool CheckVariableTemplateSpecializationType() {
+
+ if (ExpectedType is undeduced && ParsedType is not undeduced)
+ ExpectedType = dedudeType();
+
+ if (both types are undeduced)
+ ???;
+
+ bool CheckType = !ExpectedType()->
+
+ if (!Context.hasSameType(DI->getType(), ExpectedDI->getType())) {
+ unsigned ErrStr = IsPartialSpecialization ? 2 : 1;
+ Diag(D.getIdentifierLoc(), diag::err_invalid_var_template_spec_type)
+ << ErrStr << VarTemplate << DI->getType() << ExpectedDI->getType();
+ Diag(VarTemplate->getLocation(), diag::note_template_declared_here)
+ << 2 << VarTemplate->getDeclName();
+ return true;
+ }
+}
+*/
+
+DeclResult Sema::ActOnVarTemplateSpecialization(
+ Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
+ SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
+ VarDecl::StorageClass SC, bool IsPartialSpecialization) {
+ assert(VarTemplate && "A variable template id without template?");
+
+ // D must be variable template id.
+ assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId &&
+ "Variable template specialization is declared with a template it.");
+
+ TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ SourceLocation TemplateNameLoc = D.getIdentifierLoc();
+ SourceLocation LAngleLoc = TemplateId->LAngleLoc;
+ SourceLocation RAngleLoc = TemplateId->RAngleLoc;
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
+ translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ TemplateName Name(VarTemplate);
+
+ // Check for unexpanded parameter packs in any of the template arguments.
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ if (DiagnoseUnexpandedParameterPack(TemplateArgs[I],
+ UPPC_PartialSpecialization))
+ return true;
+
+ // Check that the template argument list is well-formed for this
+ // template.
+ SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
+ false, Converted))
+ return true;
+
+ // Check that the type of this variable template specialization
+ // matches the expected type.
+ TypeSourceInfo *ExpectedDI;
+ {
+ // Do substitution on the type of the declaration
+ TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+ InstantiatingTemplate Inst(*this, TemplateKWLoc, VarTemplate);
+ if (Inst)
+ return true;
+ VarDecl *Templated = VarTemplate->getTemplatedDecl();
+ ExpectedDI =
+ SubstType(Templated->getTypeSourceInfo(),
+ MultiLevelTemplateArgumentList(TemplateArgList),
+ Templated->getTypeSpecStartLoc(), Templated->getDeclName());
+ }
+ if (!ExpectedDI)
+ return true;
+
+ /*
+ // Check the new variable specialization against the parsed input.
+ // (Attributes are merged later below.)
+ if (CheckVariableTemplateSpecializationType())
+ return true;
+ */
+
+ // Find the variable template (partial) specialization declaration that
+ // corresponds to these arguments.
+ if (IsPartialSpecialization) {
+ if (CheckTemplatePartialSpecializationArgs(
+ *this, VarTemplate->getTemplateParameters(), Converted))
+ return true;
+
+ bool InstantiationDependent;
+ if (!Name.isDependent() &&
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs.getArgumentArray(), TemplateArgs.size(),
+ InstantiationDependent)) {
+ Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
+ << VarTemplate->getDeclName();
+ IsPartialSpecialization = false;
+ }
+ }
+
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *PrevDecl = 0;
+
+ if (IsPartialSpecialization)
+ // FIXME: Template parameter list matters too
+ PrevDecl = VarTemplate->findPartialSpecialization(
+ Converted.data(), Converted.size(), InsertPos);
+ else
+ PrevDecl = VarTemplate->findSpecialization(Converted.data(),
+ Converted.size(), InsertPos);
+
+ VarTemplateSpecializationDecl *Specialization = 0;
+
+ // Check whether we can declare a variable template specialization in
+ // the current scope.
+ if (CheckTemplateSpecializationScope(*this, VarTemplate, PrevDecl,
+ TemplateNameLoc,
+ IsPartialSpecialization))
+ return true;
+
+ if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+ // Since the only prior variable template specialization with these
+ // arguments was referenced but not declared, reuse that
+ // declaration node as our own, updating its source location and
+ // the list of outer template parameters to reflect our new declaration.
+ Specialization = PrevDecl;
+ Specialization->setLocation(TemplateNameLoc);
+ PrevDecl = 0;
+ } else if (IsPartialSpecialization) {
+ // Create a new class template partial specialization declaration node.
+ VarTemplatePartialSpecializationDecl *PrevPartial =
+ cast_or_null<VarTemplatePartialSpecializationDecl>(PrevDecl);
+ unsigned SequenceNumber =
+ PrevPartial ? PrevPartial->getSequenceNumber()
+ : VarTemplate->getNextPartialSpecSequenceNumber();
+ VarTemplatePartialSpecializationDecl *Partial =
+ VarTemplatePartialSpecializationDecl::Create(
+ Context, VarTemplate->getDeclContext(), TemplateKWLoc,
+ TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
+ Converted.data(), Converted.size(), TemplateArgs, SequenceNumber);
+
+ if (!PrevPartial)
+ VarTemplate->AddPartialSpecialization(Partial, InsertPos);
+ Specialization = Partial;
+
+ // If we are providing an explicit specialization of a member variable
+ // template specialization, make a note of that.
+ if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+ Partial->setMemberSpecialization();
+
+ // Check that all of the template parameters of the variable template
+ // partial specialization are deducible from the template
+ // arguments. If not, this variable template partial specialization
+ // will never be used.
+ llvm::SmallBitVector DeducibleParams(TemplateParams->size());
+ MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
+ TemplateParams->getDepth(), DeducibleParams);
+
+ if (!DeducibleParams.all()) {
+ unsigned NumNonDeducible =
+ DeducibleParams.size() - DeducibleParams.count();
+ Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
+ << (NumNonDeducible > 1) << SourceRange(TemplateNameLoc, RAngleLoc);
+ for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
+ if (!DeducibleParams[I]) {
+ NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
+ if (Param->getDeclName())
+ Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
+ << Param->getDeclName();
+ else
+ Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
+ << "<anonymous>";
+ }
+ }
+ }
+ } else {
+ // Create a new class template specialization declaration node for
+ // this explicit specialization or friend declaration.
+ Specialization = VarTemplateSpecializationDecl::Create(
+ Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
+ VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size());
+ Specialization->setTemplateArgsInfo(TemplateArgs);
+
+ if (!PrevDecl)
+ VarTemplate->AddSpecialization(Specialization, InsertPos);
+ }
+
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that specialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
+ bool Okay = false;
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
+ // Is there any previous explicit specialization declaration?
+ if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+ Okay = true;
+ break;
+ }
+ }
+
+ if (!Okay) {
+ SourceRange Range(TemplateNameLoc, RAngleLoc);
+ Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
+ << Name << Range;
+
+ Diag(PrevDecl->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (PrevDecl->getTemplateSpecializationKind() !=
+ TSK_ImplicitInstantiation);
+ return true;
+ }
+ }
+
+ Specialization->setTemplateKeywordLoc(TemplateKWLoc);
+ Specialization->setLexicalDeclContext(CurContext);
+
+ // Add the specialization into its lexical context, so that it can
+ // be seen when iterating through the list of declarations in that
+ // context. However, specializations are not found by name lookup.
+ CurContext->addDecl(Specialization);
+
+ // Note that this is an explicit specialization.
+ Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
+
+ if (PrevDecl) {
+ // Check that this isn't a redefinition of this specialization,
+ // merging with previous declarations.
+ LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName,
+ ForRedeclaration);
+ PrevSpec.addDecl(PrevDecl);
+ D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Specialization->isStaticDataMember())
+ Specialization->setInstantiationOfStaticDataMember(
+ VarTemplate->getTemplatedDecl(),
+ Specialization->getSpecializationKind());
+
+ return Specialization;
+}
+
+namespace {
+/// \brief A partial specialization whose template arguments have matched
+/// a given template-id.
+struct PartialSpecMatchResult {
+ VarTemplatePartialSpecializationDecl *Partial;
+ TemplateArgumentList *Args;
+};
+}
+
+DeclResult
+Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation TemplateNameLoc,
+ const TemplateArgumentListInfo &TemplateArgs) {
+ assert(Template && "A variable template id without template?");
+
+ // Check that the template argument list is well-formed for this template.
+ SmallVector<TemplateArgument, 4> Converted;
+ bool ExpansionIntoFixedList = false;
+ if (CheckTemplateArgumentList(
+ Template, TemplateNameLoc,
+ const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
+ Converted, &ExpansionIntoFixedList))
+ return true;
+
+ // Find the variable template specialization declaration that
+ // corresponds to these arguments.
+ void *InsertPos = 0;
+ if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
+ Converted.data(), Converted.size(), InsertPos))
+ // If we already have a variable template specialization, return it.
+ return Spec;
+
+ // This is the first time we have referenced this variable template
+ // specialization. Create the canonical declaration and add it to
+ // the set of specializations, based on the closest partial specialization
+ // that it represents. That is,
+ VarDecl *InstantiationPattern = Template->getTemplatedDecl();
+ TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+ TemplateArgumentList *InstantiationArgs = &TemplateArgList;
+ bool AmbiguousPartialSpec = false;
+ typedef PartialSpecMatchResult MatchResult;
+ SmallVector<MatchResult, 4> Matched;
+ SourceLocation PointOfInstantiation = TemplateNameLoc;
+ TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
+
+ // 1. Attempt to find the closest partial specialization that this
+ // specializes, if any.
+ // If any of the template arguments is dependent, then this is probably
+ // a placeholder for an incomplete declarative context; which must be
+ // complete by instantiation time. Thus, do not search through the partial
+ // specializations yet.
+ // FIXME: Unify with InstantiateClassTemplateSpecialization()?
+ bool InstantiationDependent = false;
+ if (!TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, InstantiationDependent)) {
+
+ SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ Template->getPartialSpecializations(PartialSpecs);
+
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+ VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
+ TemplateDeductionInfo Info(FailedCandidates.getLocation());
+
+ if (TemplateDeductionResult Result =
+ DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
+ // Store the failed-deduction information for use in diagnostics, later.
+ FailedCandidates.addCandidate()
+ .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
+ (void)Result;
+ } else {
+ Matched.push_back(PartialSpecMatchResult());
+ Matched.back().Partial = Partial;
+ Matched.back().Args = Info.take();
+ }
+ }
+
+ // If we're dealing with a member template where the template parameters
+ // have been instantiated, this provides the original template parameters
+ // from which the member template's parameters were instantiated.
+ SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
+
+ if (Matched.size() >= 1) {
+ SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ if (Matched.size() == 1) {
+ // -- If exactly one matching specialization is found, the
+ // instantiation is generated from that specialization.
+ // We don't need to do anything for this.
+ } else {
+ // -- If more than one matching specialization is found, the
+ // partial order rules (14.5.4.2) are used to determine
+ // whether one of the specializations is more specialized
+ // than the others. If none of the specializations is more
+ // specialized than all of the other matching
+ // specializations, then the use of the variable template is
+ // ambiguous and the program is ill-formed.
+ for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
+ PointOfInstantiation) ==
+ P->Partial)
+ Best = P;
+ }
+
+ // Determine if the best partial specialization is more specialized than
+ // the others.
+ for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (P != Best && getMoreSpecializedPartialSpecialization(
+ P->Partial, Best->Partial,
+ PointOfInstantiation) != Best->Partial) {
+ AmbiguousPartialSpec = true;
+ break;
+ }
+ }
+ }
+
+ // Instantiate using the best variable template partial specialization.
+ InstantiationPattern = Best->Partial;
+ InstantiationArgs = Best->Args;
+ } else {
+ // -- If no match is found, the instantiation is generated
+ // from the primary template.
+ // InstantiationPattern = Template->getTemplatedDecl();
+ }
+ }
+
+ // FIXME: Actually use FailedCandidates.
+
+ // 2. Create the canonical declaration.
+ // Note that we do not instantiate the variable just yet, since
+ // instantiation is handled in DoMarkVarDeclReferenced().
+ // FIXME: LateAttrs et al.?
+ VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
+ Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
+ Converted, TemplateNameLoc, InsertPos /*, LateAttrs, StartingScope*/);
+ if (!Decl)
+ return true;
+
+ if (AmbiguousPartialSpec) {
+ // Partial ordering did not produce a clear winner. Complain.
+ Decl->setInvalidDecl();
+ Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+ << Decl;
+
+ // Print the matching partial specializations.
+ for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P)
+ Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
+ << getTemplateArgumentBindingsText(
+ P->Partial->getTemplateParameters(), *P->Args);
+ return true;
+ }
+
+ if (VarTemplatePartialSpecializationDecl *D =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
+ Decl->setInstantiationOf(D, InstantiationArgs);
+
+ assert(Decl && "No variable template specialization?");
+ return Decl;
+}
+
+ExprResult
+Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ VarTemplateDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+
+ DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
+ *TemplateArgs);
+ if (Decl.isInvalid())
+ return ExprError();
+
+ VarDecl *Var = cast<VarDecl>(Decl.get());
+ if (!Var->getTemplateSpecializationKind())
+ Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
+ NameInfo.getLoc());
+
+ // Build an ordinary singleton decl ref.
+ return BuildDeclarationNameExpr(SS, NameInfo, Var,
+ /*FoundD=*/0, TemplateArgs);
+}
+
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -2282,6 +2735,13 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
assert(!R.empty() && "empty lookup results when building templateid");
assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");
+ // In C++1y, check variable template ids.
+ if (R.getAsSingle<VarTemplateDecl>()) {
+ return Owned(CheckVarTemplateId(SS, R.getLookupNameInfo(),
+ R.getAsSingle<VarTemplateDecl>(),
+ TemplateKWLoc, TemplateArgs));
+ }
+
// We don't want lookup warnings at this point.
R.suppressDiagnostics();
@@ -2302,6 +2762,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
+
assert(TemplateArgs || TemplateKWLoc.isValid());
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) ||
@@ -4962,16 +5423,18 @@ static bool CheckTemplateSpecializationScope(Sema &S,
int EntityKind = 0;
if (isa<ClassTemplateDecl>(Specialized))
EntityKind = IsPartialSpecialization? 1 : 0;
+ else if (isa<VarTemplateDecl>(Specialized))
+ EntityKind = IsPartialSpecialization ? 3 : 2;
else if (isa<FunctionTemplateDecl>(Specialized))
- EntityKind = 2;
+ EntityKind = 4;
else if (isa<CXXMethodDecl>(Specialized))
- EntityKind = 3;
+ EntityKind = 5;
else if (isa<VarDecl>(Specialized))
- EntityKind = 4;
+ EntityKind = 6;
else if (isa<RecordDecl>(Specialized))
- EntityKind = 5;
+ EntityKind = 7;
else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus11)
- EntityKind = 6;
+ EntityKind = 8;
else {
S.Diag(Loc, diag::err_template_spec_unknown_kind)
<< S.getLangOpts().CPlusPlus11;
@@ -5095,17 +5558,15 @@ static bool CheckTemplateSpecializationScope(Sema &S,
return false;
}
-/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs
+/// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs
/// that checks non-type template partial specialization arguments.
-static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
- NonTypeTemplateParmDecl *Param,
- const TemplateArgument *Args,
- unsigned NumArgs) {
+static bool CheckNonTypeTemplatePartialSpecializationArgs(
+ Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args,
+ unsigned NumArgs) {
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].getKind() == TemplateArgument::Pack) {
- if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param,
- Args[I].pack_begin(),
- Args[I].pack_size()))
+ if (CheckNonTypeTemplatePartialSpecializationArgs(
+ S, Param, Args[I].pack_begin(), Args[I].pack_size()))
return true;
continue;
@@ -5176,9 +5637,9 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
/// partial specialization.
///
/// \returns true if there was an error, false otherwise.
-static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
- TemplateParameterList *TemplateParams,
- SmallVectorImpl<TemplateArgument> &TemplateArgs) {
+static bool CheckTemplatePartialSpecializationArgs(
+ Sema &S, TemplateParameterList *TemplateParams,
+ SmallVectorImpl<TemplateArgument> &TemplateArgs) {
const TemplateArgument *ArgList = TemplateArgs.data();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
@@ -5187,8 +5648,7 @@ static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
if (!Param)
continue;
- if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param,
- &ArgList[I], 1))
+ if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1))
return true;
}
@@ -5334,9 +5794,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Find the class template (partial) specialization declaration that
// corresponds to these arguments.
if (isPartialSpecialization) {
- if (CheckClassTemplatePartialSpecializationArgs(*this,
- ClassTemplate->getTemplateParameters(),
- Converted))
+ if (CheckTemplatePartialSpecializationArgs(
+ *this, ClassTemplate->getTemplateParameters(), Converted))
return true;
bool InstantiationDependent;
@@ -6207,9 +6666,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
InstantiationVar->setLocation(Member->getLocation());
}
- Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
- cast<VarDecl>(InstantiatedFrom),
- TSK_ExplicitSpecialization);
+ cast<VarDecl>(Member)->setInstantiationOfStaticDataMember(
+ cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(InstantiationVar);
} else if (isa<CXXRecordDecl>(Member)) {
CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
@@ -6697,7 +7155,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::err_explicit_instantiation_inline :
diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType())
// FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is
// not already specified.
Diag(D.getDeclSpec().getConstexprSpecLoc(),
@@ -6719,28 +7177,68 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// A [...] static data member of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
+ // C++1y [temp.explicit]p1:
+ // A [...] variable [...] template specialization can be explicitly
+ // instantiated from its template.
if (Previous.isAmbiguous())
return true;
VarDecl *Prev = Previous.getAsSingle<VarDecl>();
- if (!Prev || !Prev->isStaticDataMember()) {
- // We expect to see a data data member here.
- Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
- << Name;
- for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
- P != PEnd; ++P)
- Diag((*P)->getLocation(), diag::note_explicit_instantiation_here);
- return true;
- }
+ VarTemplateDecl *PrevTemplate = Previous.getAsSingle<VarTemplateDecl>();
+
+ if (!PrevTemplate) {
+ if (!Prev || !Prev->isStaticDataMember()) {
+ // We expect to see a data data member here.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
+ << Name;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P)
+ Diag((*P)->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+ }
- if (!Prev->getInstantiatedFromStaticDataMember()) {
- // FIXME: Check for explicit specialization?
- Diag(D.getIdentifierLoc(),
- diag::err_explicit_instantiation_data_member_not_instantiated)
- << Prev;
- Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
- // FIXME: Can we provide a note showing where this was declared?
- return true;
+ if (!Prev->getInstantiatedFromStaticDataMember()) {
+ // FIXME: Check for explicit specialization?
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_data_member_not_instantiated)
+ << Prev;
+ Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
+ // FIXME: Can we provide a note showing where this was declared?
+ return true;
+ }
+ } else {
+ // Explicitly instantiate a variable template.
+
+ // C++1y [dcl.spec.auto]p6:
+ // ... A program that uses auto or decltype(auto) in a context not
+ // explicitly allowed in this section is ill-formed.
+ //
+ // This includes auto-typed variable template instantiations.
+ if (R->isUndeducedType()) {
+ Diag(T->getTypeLoc().getLocStart(),
+ diag::err_auto_not_allowed_var_inst);
+ return true;
+ }
+
+ TemplateArgumentListInfo TemplateArgs;
+ if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
+ // Translate the parser's template argument list into our AST format.
+ TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ }
+
+ DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
+ D.getIdentifierLoc(), TemplateArgs);
+ if (Res.isInvalid())
+ return true;
+
+ // Ignore access control bits, we don't need them for redeclaration
+ // checking.
+ Prev = cast<VarDecl>(Res.get());
}
// C++0x [temp.explicit]p2:
@@ -6750,7 +7248,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// name shall be a simple-template-id.
//
// C++98 has the same restriction, just worded differently.
- if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()))
+ //
+ // C++1y If the explicit instantiation is for a variable, the
+ // unqualified-id in the declaration shall be a template-id.
+ if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()) &&
+ (!PrevTemplate ||
+ (D.getName().getKind() != UnqualifiedId::IK_TemplateId &&
+ D.getCXXScopeSpec().isSet())))
Diag(D.getIdentifierLoc(),
diag::ext_explicit_instantiation_without_qualified_id)
<< Prev << D.getCXXScopeSpec().getRange();
@@ -6760,20 +7264,39 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// Verify that it is okay to explicitly instantiate here.
MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
- assert(MSInfo && "Missing static data member specialization info?");
+ TemplateSpecializationKind PrevTSK =
+ MSInfo ? MSInfo->getTemplateSpecializationKind()
+ : Prev->getTemplateSpecializationKind();
+ SourceLocation POI = MSInfo ? MSInfo->getPointOfInstantiation()
+ : cast<VarTemplateSpecializationDecl>(Prev)
+ ->getPointOfInstantiation();
bool HasNoEffect = false;
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
- MSInfo->getTemplateSpecializationKind(),
- MSInfo->getPointOfInstantiation(),
- HasNoEffect))
+ PrevTSK, POI, HasNoEffect))
return true;
- if (HasNoEffect)
- return (Decl*) 0;
- // Instantiate static data member.
- Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
- if (TSK == TSK_ExplicitInstantiationDefinition)
- InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev);
+ if (!HasNoEffect) {
+ // Instantiate static data member or variable template.
+
+ Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
+ if (PrevTemplate) {
+ // Merge attributes.
+ if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList())
+ ProcessDeclAttributeList(S, Prev, Attr);
+ }
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
+ }
+
+ // Check the new variable specialization against the parsed input.
+ if (PrevTemplate && Prev && !Context.hasSameType(Prev->getType(), R)) {
+ Diag(T->getTypeLoc().getLocStart(),
+ diag::err_invalid_var_template_spec_type)
+ << 0 << PrevTemplate << R << Prev->getType();
+ Diag(PrevTemplate->getLocation(), diag::note_template_declared_here)
+ << 2 << PrevTemplate->getDeclName();
+ return true;
+ }
// FIXME: Create an ExplicitInstantiation node?
return (Decl*) 0;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 8d6aaa096df..e87354663b0 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2246,7 +2246,7 @@ FinishTemplateArgumentDeduction(Sema &S,
}
/// \brief Perform template argument deduction to determine whether
-/// the given template arguments match the given class template
+/// the given template arguments match the given variable template
/// partial specialization per C++ [temp.class.spec.match].
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
@@ -2287,6 +2287,160 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Deduced, Info);
}
+/// Complete template argument deduction for a variable template partial
+/// specialization.
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version.
+static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
+ Sema &S, VarTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info) {
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ Sema::SFINAETrap Trap(S);
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ SmallVector<TemplateArgument, 4> Builder;
+ TemplateParameterList *PartialParams = Partial->getTemplateParameters();
+ for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
+ NamedDecl *Param = PartialParams->getParam(I);
+ if (Deduced[I].isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ return Sema::TDK_Incomplete;
+ }
+
+ // We have deduced this argument, so it still needs to be
+ // checked and converted.
+
+ // First, for a non-type template parameter type that is
+ // initialized by a declaration, we need the type of the
+ // corresponding non-type template parameter.
+ QualType NTTPType;
+ if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+ Builder.data(), Builder.size());
+ NTTPType =
+ S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(), NTTP->getDeclName());
+ if (NTTPType.isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ // FIXME: These template arguments are temporary. Free them!
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
+ Builder.size()));
+ return Sema::TDK_SubstitutionFailure;
+ }
+ }
+ }
+
+ if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, NTTPType,
+ 0, Info, false, Builder)) {
+ Info.Param = makeTemplateParameter(Param);
+ // FIXME: These template arguments are temporary. Free them!
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
+ Builder.size()));
+ return Sema::TDK_SubstitutionFailure;
+ }
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy(
+ S.Context, Builder.data(), Builder.size());
+
+ Info.reset(DeducedArgumentList);
+
+ // Substitute the deduced template arguments into the template
+ // arguments of the class template partial specialization, and
+ // verify that the instantiated template arguments are both valid
+ // and are equivalent to the template arguments originally provided
+ // to the class template.
+ LocalInstantiationScope InstScope(S);
+ VarTemplateDecl *VarTemplate = Partial->getSpecializedTemplate();
+ const TemplateArgumentLoc *PartialTemplateArgs =
+ Partial->getTemplateArgsAsWritten();
+
+ // Note that we don't provide the langle and rangle locations.
+ TemplateArgumentListInfo InstArgs;
+
+ if (S.Subst(PartialTemplateArgs, Partial->getNumTemplateArgsAsWritten(),
+ InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
+ unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
+ if (ParamIdx >= Partial->getTemplateParameters()->size())
+ ParamIdx = Partial->getTemplateParameters()->size() - 1;
+
+ Decl *Param = const_cast<NamedDecl *>(
+ Partial->getTemplateParameters()->getParam(ParamIdx));
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument();
+ return Sema::TDK_SubstitutionFailure;
+ }
+ SmallVector<TemplateArgument, 4> ConvertedInstArgs;
+ if (S.CheckTemplateArgumentList(VarTemplate, Partial->getLocation(), InstArgs,
+ false, ConvertedInstArgs))
+ return Sema::TDK_SubstitutionFailure;
+
+ TemplateParameterList *TemplateParams = VarTemplate->getTemplateParameters();
+ for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
+ TemplateArgument InstArg = ConvertedInstArgs.data()[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
+ Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
+ Info.FirstArg = TemplateArgs[I];
+ Info.SecondArg = InstArg;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ }
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return Sema::TDK_Success;
+}
+
+/// \brief Perform template argument deduction to determine whether
+/// the given template arguments match the given variable template
+/// partial specialization per C++ [temp.class.spec.match].
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info) {
+ if (Partial->isInvalidDecl())
+ return TDK_Invalid;
+
+ // C++ [temp.class.spec.match]p2:
+ // A partial specialization matches a given actual template
+ // argument list if the template arguments of the partial
+ // specialization can be deduced from the actual template argument
+ // list (14.8.2).
+
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ SFINAETrap Trap(*this);
+
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ if (TemplateDeductionResult Result = ::DeduceTemplateArguments(
+ *this, Partial->getTemplateParameters(), Partial->getTemplateArgs(),
+ TemplateArgs, Info, Deduced))
+ return Result;
+
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
+ InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
+ DeducedArgs, Info);
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs,
+ Deduced, Info);
+}
+
/// \brief Determine whether the given type T is a simple-template-id type.
static bool isSimpleTemplateIdType(QualType T) {
if (const TemplateSpecializationType *Spec
@@ -4278,6 +4432,63 @@ Sema::getMoreSpecializedPartialSpecialization(
/*RefParamComparisons=*/0);
if (Better1) {
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
+ InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs,
+ Info);
+ Better1 = !::FinishTemplateArgumentDeduction(
+ *this, PS2, PS1->getTemplateArgs(), Deduced, Info);
+ }
+
+ // Determine whether PS2 is at least as specialized as PS1
+ Deduced.clear();
+ Deduced.resize(PS1->getTemplateParameters()->size());
+ bool Better2 = !DeduceTemplateArgumentsByTypeMatch(
+ *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ /*RefParamComparisons=*/0);
+ if (Better2) {
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+ Deduced.end());
+ InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, DeducedArgs,
+ Info);
+ Better2 = !::FinishTemplateArgumentDeduction(
+ *this, PS1, PS2->getTemplateArgs(), Deduced, Info);
+ }
+
+ if (Better1 == Better2)
+ return 0;
+
+ return Better1 ? PS1 : PS2;
+}
+
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version.
+VarTemplatePartialSpecializationDecl *
+Sema::getMoreSpecializedPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *PS1,
+ VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) {
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
+ TemplateDeductionInfo Info(Loc);
+
+ assert(PS1->getSpecializedTemplate() == PS1->getSpecializedTemplate() &&
+ "the partial specializations being compared should specialize"
+ " the same template.");
+ TemplateName Name(PS1->getSpecializedTemplate());
+ TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
+ QualType PT1 = Context.getTemplateSpecializationType(
+ CanonTemplate, PS1->getTemplateArgs().data(),
+ PS1->getTemplateArgs().size());
+ QualType PT2 = Context.getTemplateSpecializationType(
+ CanonTemplate, PS2->getTemplateArgs().data(),
+ PS2->getTemplateArgs().size());
+
+ // Determine whether PS1 is at least as specialized as PS2
+ Deduced.resize(PS2->getTemplateParameters()->size());
+ bool Better1 = !DeduceTemplateArgumentsByTypeMatch(
+ *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ /*RefParamComparisons=*/0);
+ if (Better1) {
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+ Deduced.end());
InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2,
DeducedArgs, Info);
Better1 = !::FinishTemplateArgumentDeduction(*this, PS2,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 57eb64d127a..25eb72ce1cb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -61,7 +61,24 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
DeclContext *Ctx = dyn_cast<DeclContext>(D);
if (!Ctx) {
Ctx = D->getDeclContext();
-
+
+ // Add template arguments from a variable template instantiation.
+ if (VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ // We're done when we hit an explicit specialization.
+ if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(Spec))
+ return Result;
+
+ Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
+
+ // If this variable template specialization was instantiated from a
+ // specialized member that is a variable template, we're done.
+ assert(Spec->getSpecializedTemplate() && "No variable template?");
+ if (Spec->getSpecializedTemplate()->isMemberSpecialization())
+ return Result;
+ }
+
// If we have a template template parameter with translation unit context,
// then we're performing substitution into a default template argument of
// this template template parameter before we've constructed the template
@@ -292,6 +309,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
}
}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ VarTemplatePartialSpecializationDecl *PartialSpec,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext) {
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind =
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = PartialSpec;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
+ Inst.DeductionInfo = &DeductionInfo;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
+}
+
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ParmVarDecl *Param,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 52075229971..b93fe9a966a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -318,7 +318,13 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
return Inst;
}
+// FIXME: Revise for static member templates.
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
+ return VisitVarDecl(D, /*ForVarTemplate=*/false);
+}
+
+Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, bool ForVarTemplate) {
+
// If this is the variable for an anonymous struct or union,
// instantiate the anonymous struct/union type first.
if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
@@ -340,105 +346,22 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
return 0;
}
- // Build the instantiated declaration
- VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
- D->getInnerLocStart(),
+ // Build the instantiated declaration.
+ VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(),
D->getLocation(), D->getIdentifier(),
- DI->getType(), DI,
- D->getStorageClass());
- Var->setTSCSpec(D->getTSCSpec());
- Var->setInitStyle(D->getInitStyle());
- Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
- Var->setConstexpr(D->isConstexpr());
+ DI->getType(), DI, D->getStorageClass());
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Var))
- return 0;
-
- // If we are instantiating a static data member defined
- // out-of-line, the instantiation will have the same lexical
- // context (which will be a namespace scope) as the template.
- if (D->isOutOfLine())
- Var->setLexicalDeclContext(D->getLexicalDeclContext());
-
- Var->setAccess(D->getAccess());
-
- if (!D->isStaticDataMember()) {
- Var->setUsed(D->isUsed(false));
- Var->setReferenced(D->isReferenced());
- }
-
- SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
-
- if (Var->hasAttrs())
- SemaRef.CheckAlignasUnderalignment(Var);
-
- // FIXME: In theory, we could have a previous declaration for variables that
- // are not static data members.
- // FIXME: having to fake up a LookupResult is dumb.
- LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (D->isStaticDataMember())
- SemaRef.LookupQualifiedName(Previous, Owner, false);
-
// In ARC, infer 'retaining' for variables of retainable type.
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
SemaRef.inferObjCARCLifetime(Var))
Var->setInvalidDecl();
- SemaRef.CheckVariableDeclaration(Var, Previous);
-
- if (D->isOutOfLine()) {
- D->getLexicalDeclContext()->addDecl(Var);
- Owner->makeDeclVisibleInContext(Var);
- } else {
- Owner->addDecl(Var);
- if (Owner->isFunctionOrMethod())
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
- }
-
- // Link instantiations of static data members back to the template from
- // which they were instantiated.
- if (Var->isStaticDataMember())
- SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
- TSK_ImplicitInstantiation);
-
- if (Var->getAnyInitializer()) {
- // We already have an initializer in the class.
- } else if (D->getInit()) {
- if (Var->isStaticDataMember() && !D->isOutOfLine())
- SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated, D);
- else
- SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, D);
-
- // Instantiate the initializer.
- ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs,
- D->getInitStyle() == VarDecl::CallInit);
- if (!Init.isInvalid()) {
- bool TypeMayContainAuto = true;
- if (Init.get()) {
- bool DirectInit = D->isDirectInit();
- SemaRef.AddInitializerToDecl(Var, Init.take(), DirectInit,
- TypeMayContainAuto);
- } else
- SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto);
- } else {
- // FIXME: Not too happy about invalidating the declaration
- // because of a bogus initializer.
- Var->setInvalidDecl();
- }
-
- SemaRef.PopExpressionEvaluationContext();
- } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
- !Var->isCXXForRangeDecl())
- SemaRef.ActOnUninitializedDecl(Var, false);
-
- // Diagnose unused local variables with dependent types, where the diagnostic
- // will have been deferred.
- if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() &&
- D->getType()->isDependentType())
- SemaRef.DiagnoseUnusedDecl(Var);
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Var))
+ return 0;
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
+ StartingScope, ForVarTemplate);
return Var;
}
@@ -1026,6 +949,102 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D);
}
+Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ assert(D->getTemplatedDecl()->isStaticDataMember() &&
+ "Only static data member templates are allowed.");
+ // FIXME: Also only when instantiating a class?
+
+ // Create a local instantiation scope for this variable template, which
+ // will contain the instantiations of the template parameters.
+ LocalInstantiationScope Scope(SemaRef);
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ VarDecl *Pattern = D->getTemplatedDecl();
+ VarTemplateDecl *PrevVarTemplate = 0;
+
+ if (Pattern->getPreviousDecl()) {
+ DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
+ if (!Found.empty())
+ PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
+ }
+
+ // FIXME: This, and ForVarTemplate, is a hack that is probably unnecessary.
+ // We should use a simplified version of VisitVarDecl.
+ VarDecl *VarInst = cast_or_null<VarDecl>(VisitVarDecl(Pattern, /*ForVarTemplate=*/true));
+
+ DeclContext *DC = Owner;
+
+ /* FIXME: This should be handled in VisitVarDecl, as used to produce
+ VarInst above.
+ // Instantiate the qualifier.
+ NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc =
+ SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs);
+ if (!QualifierLoc)
+ return 0;
+ }
+
+ if (QualifierLoc)
+ VarInst->setQualifierInfo(QualifierLoc);
+ */
+
+ VarTemplateDecl *Inst = VarTemplateDecl::Create(
+ SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams,
+ VarInst, PrevVarTemplate);
+ VarInst->setDescribedVarTemplate(Inst);
+
+ Inst->setAccess(D->getAccess());
+ if (!PrevVarTemplate)
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ if (D->isOutOfLine()) {
+ Inst->setLexicalDeclContext(D->getLexicalDeclContext());
+ VarInst->setLexicalDeclContext(D->getLexicalDeclContext());
+ }
+
+ Owner->addDecl(Inst);
+
+ if (!PrevVarTemplate) {
+ // Queue up any out-of-line partial specializations of this member
+ // variable template; the client will force their instantiation once
+ // the enclosing class has been instantiated.
+ SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ D->getPartialSpecializations(PartialSpecs);
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
+ if (PartialSpecs[I]->isOutOfLine())
+ OutOfLineVarPartialSpecs.push_back(
+ std::make_pair(Inst, PartialSpecs[I]));
+ }
+
+ return Inst;
+}
+
+Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ assert(D->isStaticDataMember() &&
+ "Only static data member templates are allowed.");
+ // FIXME: Also only when instantiating a class?
+
+ VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
+
+ // Lookup the already-instantiated declaration and return that.
+ DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName());
+ assert(!Found.empty() && "Instantiation found nothing?");
+
+ VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
+ assert(InstVarTemplate && "Instantiation did not find a variable template?");
+
+ if (VarTemplatePartialSpecializationDecl *Result =
+ InstVarTemplate->findPartialSpecInstantiatedFromMember(D))
+ return Result;
+
+ return InstantiateVarTemplatePartialSpecialization(InstVarTemplate, D);
+}
+
Decl *
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// Create a local instantiation scope for this function template, which
@@ -2256,6 +2275,87 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
"inside templates");
}
+Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+
+ TemplateArgumentListInfo VarTemplateArgsInfo;
+ VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
+ assert(VarTemplate &&
+ "A template specialization without specialized template?");
+
+ // Substitute the current template arguments.
+ const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo();
+ VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc());
+ VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo.getRAngleLoc());
+
+ if (SemaRef.Subst(TemplateArgsInfo.getArgumentArray(),
+ TemplateArgsInfo.size(), VarTemplateArgsInfo, TemplateArgs))
+ return 0;
+
+ // Check that the template argument list is well-formed for this template.
+ SmallVector<TemplateArgument, 4> Converted;
+ bool ExpansionIntoFixedList = false;
+ if (SemaRef.CheckTemplateArgumentList(
+ VarTemplate, VarTemplate->getLocStart(),
+ const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
+ Converted, &ExpansionIntoFixedList))
+ return 0;
+
+ // Find the variable template specialization declaration that
+ // corresponds to these arguments.
+ void *InsertPos = 0;
+ if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization(
+ Converted.data(), Converted.size(), InsertPos))
+ // If we already have a variable template specialization, return it.
+ return VarSpec;
+
+ return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos,
+ VarTemplateArgsInfo, Converted);
+}
+
+Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
+ VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
+ const TemplateArgumentListInfo &TemplateArgsInfo,
+ SmallVectorImpl<TemplateArgument> &Converted) {
+
+ // If this is the variable for an anonymous struct or union,
+ // instantiate the anonymous struct/union type first.
+ if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
+ if (RecordTy->getDecl()->isAnonymousStructOrUnion())
+ if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
+ return 0;
+
+ // Do substitution on the type of the declaration
+ TypeSourceInfo *DI =
+ SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
+ D->getTypeSpecStartLoc(), D->getDeclName());
+ if (!DI)
+ return 0;
+
+ if (DI->getType()->isFunctionType()) {
+ SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function)
+ << D->isStaticDataMember() << DI->getType();
+ return 0;
+ }
+
+ // Build the instantiated declaration
+ VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
+ SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
+ VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
+ Converted.size());
+ Var->setTemplateArgsInfo(TemplateArgsInfo);
+ VarTemplate->AddSpecialization(Var, InsertPos);
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(D, Var))
+ return 0;
+
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
+ StartingScope);
+
+ return Var;
+}
+
Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
llvm_unreachable("@defs is not supported in Objective-C++");
}
@@ -2442,6 +2542,134 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
return InstPartialSpec;
}
+/// \brief Instantiate the declaration of a variable template partial
+/// specialization.
+///
+/// \param VarTemplate the (instantiated) variable template that is partially
+/// specialized by the instantiation of \p PartialSpec.
+///
+/// \param PartialSpec the (uninstantiated) variable template partial
+/// specialization that we are instantiating.
+///
+/// \returns The instantiated partial specialization, if successful; otherwise,
+/// NULL to indicate an error.
+VarTemplatePartialSpecializationDecl *
+TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
+ VarTemplateDecl *VarTemplate,
+ VarTemplatePartialSpecializationDecl *PartialSpec) {
+ // Create a local instantiation scope for this variable template partial
+ // specialization, which will contain the instantiations of the template
+ // parameters.
+ LocalInstantiationScope Scope(SemaRef);
+
+ // Substitute into the template parameters of the variable template partial
+ // specialization.
+ TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return 0;
+
+ // Substitute into the template arguments of the variable template partial
+ // specialization.
+ TemplateArgumentListInfo InstTemplateArgs; // no angle locations
+ if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(),
+ PartialSpec->getNumTemplateArgsAsWritten(),
+ InstTemplateArgs, TemplateArgs))
+ return 0;
+
+ // Check that the template argument list is well-formed for this
+ // class template.
+ SmallVector<TemplateArgument, 4> Converted;
+ if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
+ InstTemplateArgs, false, Converted))
+ return 0;
+
+ // Figure out where to insert this variable template partial specialization
+ // in the member template's set of variable template partial specializations.
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *PrevDecl =
+ VarTemplate->findPartialSpecialization(Converted.data(), Converted.size(),
+ InsertPos);
+
+ // Build the canonical type that describes the converted template
+ // arguments of the variable template partial specialization.
+ QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(VarTemplate), Converted.data(), Converted.size());
+
+ // Build the fully-sugared type for this variable template
+ // specialization as the user wrote in the specialization
+ // itself. This means that we'll pretty-print the type retrieved
+ // from the specialization's declaration the way that the user
+ // actually wrote the specialization, rather than formatting the
+ // name based on the "canonical" representation used to store the
+ // template arguments in the specialization.
+ TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
+ TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs,
+ CanonType);
+
+ if (PrevDecl) {
+ // We've already seen a partial specialization with the same template
+ // parameters and template arguments. This can happen, for example, when
+ // substituting the outer template arguments ends up causing two
+ // variable template partial specializations of a member variable template
+ // to have identical forms, e.g.,
+ //
+ // template<typename T, typename U>
+ // struct Outer {
+ // template<typename X, typename Y> pair<X,Y> p;
+ // template<typename Y> pair<T, Y> p;
+ // template<typename Y> pair<U, Y> p;
+ // };
+ //
+ // Outer<int, int> outer; // error: the partial specializations of Inner
+ // // have the same signature.
+ SemaRef.Diag(PartialSpec->getLocation(),
+ diag::err_var_partial_spec_redeclared)
+ << WrittenTy->getType();
+ SemaRef.Diag(PrevDecl->getLocation(),
+ diag::note_var_prev_partial_spec_here);
+ return 0;
+ }
+
+ // Do substitution on the type of the declaration
+ TypeSourceInfo *DI = SemaRef.SubstType(
+ PartialSpec->getTypeSourceInfo(), TemplateArgs,
+ PartialSpec->getTypeSpecStartLoc(), PartialSpec->getDeclName());
+ if (!DI)
+ return 0;
+
+ if (DI->getType()->isFunctionType()) {
+ SemaRef.Diag(PartialSpec->getLocation(),
+ diag::err_variable_instantiates_to_function)
+ << PartialSpec->isStaticDataMember() << DI->getType();
+ return 0;
+ }
+
+ // Create the variable template partial specialization declaration.
+ VarTemplatePartialSpecializationDecl *InstPartialSpec =
+ VarTemplatePartialSpecializationDecl::Create(
+ SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
+ PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
+ DI, PartialSpec->getStorageClass(), Converted.data(),
+ Converted.size(), InstTemplateArgs,
+ VarTemplate->getNextPartialSpecSequenceNumber());
+
+ // Substitute the nested name specifier, if any.
+ if (SubstQualifier(PartialSpec, InstPartialSpec))
+ return 0;
+
+ InstPartialSpec->setInstantiatedFromMember(PartialSpec);
+ InstPartialSpec->setTypeAsWritten(WrittenTy);
+
+ InstPartialSpec->setAccess(PartialSpec->getAccess());
+ // FIXME: How much of BuildVariableInstantiation() should go in here?
+
+ // Add this partial specialization to the set of variable template partial
+ // specializations. The instantiation of the initializer is not necessary.
+ VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
+ return InstPartialSpec;
+}
+
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
SmallVectorImpl<ParmVarDecl *> &Params) {
@@ -3026,6 +3254,167 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
PendingLocalImplicitInstantiations);
}
+VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
+ VarTemplateDecl *VarTemplate, VarDecl *FromVar,
+ const TemplateArgumentList &TemplateArgList,
+ const TemplateArgumentListInfo &TemplateArgsInfo,
+ SmallVectorImpl<TemplateArgument> &Converted,
+ SourceLocation PointOfInstantiation, void *InsertPos,
+ LateInstantiatedAttrVec *LateAttrs,
+ LocalInstantiationScope *StartingScope) {
+ if (FromVar->isInvalidDecl())
+ return 0;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar);
+ if (Inst)
+ return 0;
+
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
+
+ TemplateDeclInstantiator Instantiator(
+ *this, VarTemplate->getDeclContext(),
+ MultiLevelTemplateArgumentList(TemplateArgList));
+
+ // TODO: Set LateAttrs and StartingScope ...
+
+ return cast_or_null<VarTemplateSpecializationDecl>(
+ Instantiator.VisitVarTemplateSpecializationDecl(
+ VarTemplate, FromVar, InsertPos, TemplateArgsInfo, Converted));
+}
+
+/// \brief Instantiates a variable template specialization by completing it
+/// with appropriate type information and initializer.
+VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ // Do substitution on the type of the declaration
+ TypeSourceInfo *DI =
+ SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
+ PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
+ if (!DI)
+ return 0;
+
+ // Update the type of this variable template specialization.
+ VarSpec->setType(DI->getType());
+
+ // Instantiate the initializer.
+ InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs);
+
+ return VarSpec;
+}
+
+/// BuildVariableInstantiation - Used after a new variable has been created.
+/// Sets basic variable data and decides whether to postpone the
+/// variable instantiation.
+void Sema::BuildVariableInstantiation(
+ VarDecl *NewVar, VarDecl *OldVar,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ LateInstantiatedAttrVec *LateAttrs,
+ LocalInstantiationScope *StartingScope,
+ bool ForVarTemplate) {
+
+ // If we are instantiating a static data member defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (OldVar->isOutOfLine())
+ NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext());
+ NewVar->setTSCSpec(OldVar->getTSCSpec());
+ NewVar->setInitStyle(OldVar->getInitStyle());
+ NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl());
+ NewVar->setConstexpr(OldVar->isConstexpr());
+ NewVar->setAccess(OldVar->getAccess());
+
+ if (!OldVar->isStaticDataMember()) {
+ NewVar->setUsed(OldVar->isUsed(false));
+ NewVar->setReferenced(OldVar->isReferenced());
+ }
+
+ InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope);
+
+ if (NewVar->hasAttrs())
+ CheckAlignasUnderalignment(NewVar);
+
+ // FIXME: In theory, we could have a previous declaration for variables that
+ // are not static data members.
+ // FIXME: having to fake up a LookupResult is dumb.
+ LookupResult Previous(*this, NewVar->getDeclName(), NewVar->getLocation(),
+ Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+
+ if (!isa<VarTemplateSpecializationDecl>(NewVar))
+ LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
+
+ CheckVariableDeclaration(NewVar, Previous);
+
+ if (OldVar->isOutOfLine()) {
+ OldVar->getLexicalDeclContext()->addDecl(NewVar);
+ if (!ForVarTemplate)
+ NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar);
+ } else {
+ if (!ForVarTemplate)
+ NewVar->getDeclContext()->addDecl(NewVar);
+ if (NewVar->getDeclContext()->isFunctionOrMethod())
+ CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar);
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (NewVar->isStaticDataMember() && !ForVarTemplate)
+ NewVar->setInstantiationOfStaticDataMember(OldVar,
+ TSK_ImplicitInstantiation);
+
+ if (isa<VarTemplateSpecializationDecl>(NewVar)) {
+ // Do not instantiate the variable just yet.
+ } else
+ InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+
+ // Diagnose unused local variables with dependent types, where the diagnostic
+ // will have been deferred.
+ if (!NewVar->isInvalidDecl() &&
+ NewVar->getDeclContext()->isFunctionOrMethod() && !NewVar->isUsed() &&
+ OldVar->getType()->isDependentType())
+ DiagnoseUnusedDecl(NewVar);
+}
+
+/// \brief Instantiate the initializer of a variable.
+void Sema::InstantiateVariableInitializer(
+ VarDecl *Var, VarDecl *OldVar,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ if (Var->getAnyInitializer())
+ // We already have an initializer in the class.
+ return;
+
+ if (OldVar->getInit()) {
+ if (Var->isStaticDataMember() && !OldVar->isOutOfLine())
+ PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar);
+ else
+ PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar);
+
+ // Instantiate the initializer.
+ ExprResult Init =
+ SubstInitializer(OldVar->getInit(), TemplateArgs,
+ OldVar->getInitStyle() == VarDecl::CallInit);
+ if (!Init.isInvalid()) {
+ bool TypeMayContainAuto = true;
+ if (Init.get()) {
+ bool DirectInit = OldVar->isDirectInit();
+ AddInitializerToDecl(Var, Init.take(), DirectInit, TypeMayContainAuto);
+ } else
+ ActOnUninitializedDecl(Var, TypeMayContainAuto);
+ } else {
+ // FIXME: Not too happy about invalidating the declaration
+ // because of a bogus initializer.
+ Var->setInvalidDecl();
+ }
+
+ PopExpressionEvaluationContext();
+ } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
+ !Var->isCXXForRangeDecl())
+ ActOnUninitializedDecl(Var, false);
+}
+
/// \brief Instantiate the definition of the given variable from its
/// template.
///
@@ -3047,26 +3436,76 @@ void Sema::InstantiateStaticDataMemberDefinition(
VarDecl *Var,
bool Recursive,
bool DefinitionRequired) {
+ InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive,
+ DefinitionRequired);
+}
+
+void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
+ VarDecl *Var, bool Recursive,
+ bool DefinitionRequired) {
+
if (Var->isInvalidDecl())
return;
- // Find the out-of-line definition of this static data member.
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
+ assert((VarSpec || Var->isStaticDataMember()) &&
+ "Not a static data member, nor a variable template specialization?");
+ VarDecl *PatternDecl = 0;
+
+ // If this is a variable template specialization, make sure that it is
+ // non-dependent, then find its instantiation pattern.
+ if (VarSpec) {
+ bool InstantiationDependent = false;
+ assert(!TemplateSpecializationType::anyDependentTemplateArguments(
+ VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
+ "Only instantiate variable template specializations that are "
+ "not type-dependent");
+
+ // Find the variable initialization that we'll be substituting.
+ assert(VarSpec->getSpecializedTemplate() &&
+ "Specialization without specialized template?");
+ llvm::PointerUnion<VarTemplateDecl *,
+ VarTemplatePartialSpecializationDecl *> PatternPtr =
+ VarSpec->getSpecializedTemplateOrPartial();
+ if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>())
+ PatternDecl = cast<VarDecl>(
+ PatternPtr.get<VarTemplatePartialSpecializationDecl *>());
+ else
+ PatternDecl = (PatternPtr.get<VarTemplateDecl *>())->getTemplatedDecl();
+ assert(PatternDecl && "instantiating a non-template");
+ }
+
+ // If this is a static data member, find its out-of-line definition.
VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
- assert(Def && "This data member was not instantiated from a template?");
- assert(Def->isStaticDataMember() && "Not a static data member?");
- Def = Def->getOutOfLineDefinition();
-
- if (!Def) {
- // We did not find an out-of-line definition of this static data member,
- // so we won't perform any instantiation. Rather, we rely on the user to
- // instantiate this definition (or provide a specialization for it) in
- // another translation unit.
+ if (Var->isStaticDataMember()) {
+ assert(Def && "This data member was not instantiated from a template?");
+ assert(Def->isStaticDataMember() && "Not a static data member?");
+ Def = Def->getOutOfLineDefinition();
+ }
+
+ // If the instantiation pattern does not have an initializer, or if an
+ // out-of-line definition is not found, we won't perform any instantiation.
+ // Rather, we rely on the user to instantiate this definition (or provide
+ // a specialization for it) in another translation unit.
+ if ((VarSpec && !PatternDecl->getInit()) ||
+ (!VarSpec && Var->isStaticDataMember() && !Def)) {
if (DefinitionRequired) {
- Def = Var->getInstantiatedFromStaticDataMember();
- Diag(PointOfInstantiation,
- diag::err_explicit_instantiation_undefined_member)
- << 2 << Var->getDeclName() << Var->getDeclContext();
- Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
+ if (!Var->isStaticDataMember()) {
+ Diag(PointOfInstantiation,
+ diag::err_explicit_instantiation_undefined_var_template)
+ << PatternDecl;
+ Diag(PatternDecl->getLocation(),
+ diag::note_explicit_instantiation_here);
+ } else {
+ Def = Var->getInstantiatedFromStaticDataMember();
+ Diag(PointOfInstantiation,
+ diag::err_explicit_instantiation_undefined_member)
+ << 3 << Var->getDeclName() << Var->getDeclContext();
+ Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
+ }
+ if (VarSpec)
+ Var->setInvalidDecl();
} else if (Var->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDefinition) {
PendingInstantiations.push_back(
@@ -3086,6 +3525,11 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Except for inline functions, other explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
+ //
+ // C++11 [temp.explicit]p10:
+ // Except for inline functions, [...] explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
if (TSK == TSK_ExplicitInstantiationDeclaration)
return;
@@ -3098,17 +3542,24 @@ void Sema::InstantiateStaticDataMemberDefinition(
: Consumer(Consumer), Var(Var) { }
~PassToConsumerRAII() {
- Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+ if (Var->isStaticDataMember())
+ Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+ else {
+ DeclGroupRef DG(Var);
+ Consumer.HandleTopLevelDecl(DG);
+ }
}
} PassToConsumerRAII(Consumer, Var);
- // If we already have a definition, we're done.
- if (VarDecl *Def = Var->getDefinition()) {
- // We may be explicitly instantiating something we've already implicitly
- // instantiated.
- Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
- PointOfInstantiation);
- return;
+ if (!VarSpec) {
+ // If we already have a definition, we're done.
+ if (VarDecl *Def = Var->getDefinition()) {
+ // We may be explicitly instantiating something we've already implicitly
+ // instantiated.
+ Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
+ PointOfInstantiation);
+ return;
+ }
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
@@ -3127,22 +3578,41 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
- ContextRAII previousContext(*this, Var->getDeclContext());
+ ContextRAII PreviousContext(*this, Var->getDeclContext());
LocalInstantiationScope Local(*this);
-
+
VarDecl *OldVar = Var;
- Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
- getTemplateInstantiationArgs(Var)));
+ if (!VarSpec)
+ Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
+ getTemplateInstantiationArgs(Var)));
+ else
+ // Construct a VarTemplateSpecializationDecl to avoid name clashing with
+ // the primary template. (Note that unlike function declarations, variable
+ // declarations cannot be overloaded.)
+ // In fact, there is no need to construct a new declaration from scratch.
+ // Thus, simply complete its definition with an appropriately substituted
+ // type and initializer.
+ Var = CompleteVarTemplateSpecializationDecl(
+ VarSpec, PatternDecl, getTemplateInstantiationArgs(Var));
- previousContext.pop();
+ PreviousContext.pop();
if (Var) {
- PassToConsumerRAII.Var = Var;
MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
- Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(),
- MSInfo->getPointOfInstantiation());
+ if (!VarSpec)
+ assert(MSInfo && "Missing member specialization information?");
+
+ PassToConsumerRAII.Var = Var;
+ if (MSInfo)
+ Var->setTemplateSpecializationKind(
+ MSInfo->getTemplateSpecializationKind(),
+ MSInfo->getPointOfInstantiation());
}
+
+ // This variable may have local implicit instantiations that need to be
+ // instantiated within this scope.
+ PerformPendingInstantiations(/*LocalOnly=*/true);
+
Local.Exit();
if (Recursive) {
@@ -3155,14 +3625,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Restore the set of pending vtables.
assert(VTableUses.empty() &&
- "VTableUses should be empty before it is discarded, "
- "while instantiating static data member.");
+ "VTableUses should be empty before it is discarded.");
VTableUses.swap(SavedVTableUses);
// Restore the set of pending implicit instantiations.
assert(PendingInstantiations.empty() &&
- "PendingInstantiations should be empty before it is discarded, "
- "while instantiating static data member.");
+ "PendingInstantiations should be empty before it is discarded.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
}
@@ -3593,6 +4061,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return cast<LabelDecl>(Inst);
}
+ // For variable template specializations, update those that are still
+ // type-dependent.
+ if (VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ bool InstantiationDependent = false;
+ const TemplateArgumentListInfo &VarTemplateArgs =
+ VarSpec->getTemplateArgsInfo();
+ if (TemplateSpecializationType::anyDependentTemplateArguments(
+ VarTemplateArgs, InstantiationDependent))
+ D = cast<NamedDecl>(
+ SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs));
+ return D;
+ }
+
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
if (!Record->isDependentContext())
return D;
@@ -3605,7 +4087,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
else if (ClassTemplatePartialSpecializationDecl *PartialSpec
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
ClassTemplate = PartialSpec->getSpecializedTemplate()->getCanonicalDecl();
-
+
// Walk the current context to find either the record or an instantiation of
// it.
DeclContext *DC = CurContext;
@@ -3614,7 +4096,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// definition, we'll find our own context. We're done.
if (DC->Equals(Record))
return Record;
-
+
if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) {
// Check whether we're in the process of instantiating a class template
// specialization of the template we're mapping.
@@ -3624,13 +4106,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate))
return InstRecord;
}
-
+
// Check whether we're in the process of instantiating a member class.
if (isInstantiationOf(Record, InstRecord))
return InstRecord;
}
-
-
+
// Move to the outer template scope.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
@@ -3638,7 +4119,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
continue;
}
}
-
+
DC = DC->getParent();
}
@@ -3771,9 +4252,13 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
continue;
}
- // Instantiate static data member definitions.
+ // Instantiate variable definitions
VarDecl *Var = cast<VarDecl>(Inst.first);
- assert(Var->isStaticDataMember() && "Not a static data member?");
+
+ assert((Var->isStaticDataMember() ||
+ isa<VarTemplateSpecializationDecl>(Var)) &&
+ "Not a static data member, nor a variable template"
+ " specialization?");
// Don't try to instantiate declarations if the most recent redeclaration
// is invalid.
@@ -3796,14 +4281,15 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
break;
}
- PrettyDeclStackTraceEntry CrashInfo(*this, Var, Var->getLocation(),
- "instantiating static data member "
- "definition");
-
+ PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
+ "instantiating variable definition");
bool DefinitionRequired = Var->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition;
- InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
- DefinitionRequired);
+
+ // Instantiate static data member definitions or variable template
+ // specializations.
+ InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
+ DefinitionRequired);
}
}
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 24b268f36df..79bba0cb94f 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -158,6 +158,8 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::CXXRecord:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
case Decl::Function:
case Decl::CXXMethod:
case Decl::CXXConstructor:
@@ -166,6 +168,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Var:
case Decl::FunctionTemplate:
case Decl::ClassTemplate:
+ case Decl::VarTemplate:
case Decl::TypeAliasTemplate:
case Decl::ObjCProtocol:
case Decl::ObjCInterface:
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 122865b4686..6694192c880 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -239,6 +239,13 @@ namespace clang {
ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
+ RedeclarableResult
+ VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D);
+ void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
+ VisitVarTemplateSpecializationDeclImpl(D);
+ }
+ void VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *VD);
void VisitEnumConstantDecl(EnumConstantDecl *ECD);
@@ -252,13 +259,15 @@ namespace clang {
void VisitFieldDecl(FieldDecl *FD);
void VisitMSPropertyDecl(MSPropertyDecl *FD);
void VisitIndirectFieldDecl(IndirectFieldDecl *FD);
- void VisitVarDecl(VarDecl *VD);
+ RedeclarableResult VisitVarDeclImpl(VarDecl *D);
+ void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); }
void VisitImplicitParamDecl(ImplicitParamDecl *PD);
void VisitParmVarDecl(ParmVarDecl *PD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitVarTemplateDecl(VarTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
@@ -917,7 +926,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx);
}
-void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
+ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
RedeclarableResult Redecl = VisitRedeclarable(VD);
VisitDeclaratorDecl(VD);
@@ -950,6 +959,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
SourceLocation POI = ReadSourceLocation(Record, Idx);
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
}
+
+ return Redecl;
}
void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
@@ -1418,6 +1429,40 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
}
+void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+
+ if (ThisDeclID == Redecl.getFirstID()) {
+ // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
+ // the specializations.
+ SmallVector<serialization::DeclID, 2> SpecIDs;
+ SpecIDs.push_back(0);
+
+ // Specializations.
+ unsigned Size = Record[Idx++];
+ SpecIDs[0] += Size;
+ for (unsigned I = 0; I != Size; ++I)
+ SpecIDs.push_back(ReadDeclID(Record, Idx));
+
+ // Partial specializations.
+ Size = Record[Idx++];
+ SpecIDs[0] += Size;
+ for (unsigned I = 0; I != Size; ++I)
+ SpecIDs.push_back(ReadDeclID(Record, Idx));
+
+ VarTemplateDecl::Common *CommonPtr = D->getCommonPtr();
+ if (SpecIDs[0]) {
+ typedef serialization::DeclID DeclID;
+
+ // FIXME: Append specializations!
+ CommonPtr->LazySpecializations =
+ new (Reader.getContext()) DeclID[SpecIDs.size()];
+ memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
+ SpecIDs.size() * sizeof(DeclID));
+ }
+ }
+}
+
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
ClassTemplateSpecializationDecl *D) {
@@ -1528,6 +1573,89 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
}
}
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
+ VarTemplateSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitVarDeclImpl(D);
+
+ ASTContext &C = Reader.getContext();
+ if (Decl *InstD = ReadDecl(Record, Idx)) {
+ if (VarTemplateDecl *VTD = dyn_cast<VarTemplateDecl>(InstD)) {
+ D->SpecializedTemplate = VTD;
+ } else {
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy(
+ C, TemplArgs.data(), TemplArgs.size());
+ VarTemplateSpecializationDecl::SpecializedPartialSpecialization *PS =
+ new (C)
+ VarTemplateSpecializationDecl::SpecializedPartialSpecialization();
+ PS->PartialSpecialization =
+ cast<VarTemplatePartialSpecializationDecl>(InstD);
+ PS->TemplateArgs = ArgList;
+ D->SpecializedTemplate = PS;
+ }
+ }
+
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ VarTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo =
+ new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ D->TemplateArgs =
+ TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size());
+ D->PointOfInstantiation = ReadSourceLocation(Record, Idx);
+ D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
+
+ bool writtenAsCanonicalDecl = Record[Idx++];
+ if (writtenAsCanonicalDecl) {
+ VarTemplateDecl *CanonPattern = ReadDeclAs<VarTemplateDecl>(Record, Idx);
+ if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(D)) {
+ Partial->SequenceNumber =
+ CanonPattern->getNextPartialSpecSequenceNumber();
+ CanonPattern->getCommonPtr()->PartialSpecializations
+ .GetOrInsertNode(Partial);
+ } else {
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ }
+ }
+
+ return Redecl;
+}
+
+void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
+
+ ASTContext &C = Reader.getContext();
+ D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx);
+
+ unsigned NumArgs = Record[Idx++];
+ if (NumArgs) {
+ D->NumArgsAsWritten = NumArgs;
+ D->ArgsAsWritten = new (C) TemplateArgumentLoc[NumArgs];
+ for (unsigned i = 0; i != NumArgs; ++i)
+ D->ArgsAsWritten[i] = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
+ }
+
+ // These are read/set from/to the first declaration.
+ if (ThisDeclID == Redecl.getFirstID()) {
+ D->InstantiatedFromMember.setPointer(
+ ReadDeclAs<VarTemplatePartialSpecializationDecl>(Record, Idx));
+ D->InstantiatedFromMember.setInt(Record[Idx++]);
+ }
+}
+
void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
VisitTypeDecl(D);
@@ -2178,6 +2306,15 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_VAR_TEMPLATE:
+ D = VarTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE_SPECIALIZATION:
+ D = VarTemplateSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION:
+ D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID);
break;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 08d7f96fadd..142e7b12671 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -946,6 +946,9 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_CLASS_TEMPLATE);
RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION);
RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION);
+ RECORD(DECL_VAR_TEMPLATE);
+ RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION);
+ RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION);
RECORD(DECL_FUNCTION_TEMPLATE);
RECORD(DECL_TEMPLATE_TYPE_PARM);
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
@@ -5235,6 +5238,19 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
Record.push_back(reinterpret_cast<uint64_t>(D));
}
+void ASTWriter::AddedCXXTemplateSpecialization(
+ const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) {
+ // The specializations set is kept in the canonical template.
+ assert(!WritingAST && "Already writing the AST!");
+ TD = TD->getCanonicalDecl();
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
+ return; // Not a source specialization added to a template from PCH.
+
+ UpdateRecord &Record = DeclUpdates[TD];
+ Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
+ Record.push_back(reinterpret_cast<uint64_t>(D));
+}
+
void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {
// The specializations set is kept in the canonical template.
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 87398e99aec..a3e883f057e 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -68,6 +68,9 @@ namespace clang {
ClassTemplateSpecializationDecl *D);
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
+ void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+ void VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
@@ -90,6 +93,7 @@ namespace clang {
void VisitTemplateDecl(TemplateDecl *D);
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitVarTemplateDecl(VarTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
@@ -1184,6 +1188,87 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
}
+void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+
+ if (D->isFirstDeclaration()) {
+ typedef llvm::FoldingSetVector<VarTemplateSpecializationDecl> VTSDSetTy;
+ VTSDSetTy &VTSDSet = D->getSpecializations();
+ Record.push_back(VTSDSet.size());
+ for (VTSDSetTy::iterator I = VTSDSet.begin(), E = VTSDSet.end(); I != E;
+ ++I) {
+ assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
+ Writer.AddDeclRef(&*I, Record);
+ }
+
+ typedef llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
+ VTPSDSetTy;
+ VTPSDSetTy &VTPSDSet = D->getPartialSpecializations();
+ Record.push_back(VTPSDSet.size());
+ for (VTPSDSetTy::iterator I = VTPSDSet.begin(), E = VTPSDSet.end(); I != E;
+ ++I) {
+ assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
+ Writer.AddDeclRef(&*I, Record);
+ }
+ }
+ Code = serialization::DECL_VAR_TEMPLATE;
+}
+
+void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ VisitVarDecl(D);
+
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ InstFrom = D->getSpecializedTemplateOrPartial();
+ if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) {
+ Writer.AddDeclRef(InstFromD, Record);
+ } else {
+ Writer.AddDeclRef(InstFrom.get<VarTemplatePartialSpecializationDecl *>(),
+ Record);
+ Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
+ }
+
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
+ Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
+ Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
+ Record.push_back(D->getSpecializationKind());
+ Record.push_back(D->isCanonicalDecl());
+
+ if (D->isCanonicalDecl()) {
+ // When reading, we'll add it to the folding set of the following template.
+ Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
+ }
+
+ Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ VisitVarTemplateSpecializationDecl(D);
+
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+
+ Record.push_back(D->getNumTemplateArgsAsWritten());
+ for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i)
+ Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record);
+
+ Record.push_back(D->getSequenceNumber());
+
+ // These are read/set from/to the first declaration.
+ if (D->getPreviousDecl() == 0) {
+ Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
+ Record.push_back(D->isMemberSpecialization());
+ }
+
+ Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
+}
+
void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
VisitDecl(D);
OpenPOWER on IntegriCloud