summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-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
7 files changed, 1774 insertions, 279 deletions
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);
}
}
OpenPOWER on IntegriCloud