Hi rsmith,
1. The basic test cases on static data member templates of class templates are
now working.
More test cases are underway...
2. A bit of FIXME clean-up...
http://llvm-reviews.chandlerc.com/D1448
Files:
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/cxx1y-variable-templates_in_class.cpp
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1472,8 +1472,7 @@
MultiTemplateParamsArg TemplateParamLists,
bool &AddToScope);
// Returns true if the variable declaration is a redeclaration
- bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
- bool IsVariableTemplate = false);
+ bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckVariableDeclarationType(VarDecl *NewVD);
void CheckCompleteVariableDeclaration(VarDecl *var);
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@@ -1869,7 +1868,7 @@
Scope *S, bool MergeTypeWithOld);
void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
void MergeVarDecl(VarDecl *New, LookupResult &Previous,
- bool IsVariableTemplate, bool MergeTypeWithPrevious);
+ bool MergeTypeWithPrevious);
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2887,7 +2887,7 @@
/// definitions here, since the initializer hasn't been attached.
///
void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
- bool IsVariableTemplate, bool MergeTypeWithPrevious) {
+ bool MergeTypeWithPrevious) {
// If the new decl is already invalid, don't do any other checking.
if (New->isInvalidDecl())
return;
@@ -2896,7 +2896,7 @@
VarDecl *Old = 0;
if (Previous.isSingleResult() &&
(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
- if (IsVariableTemplate)
+ if (New->getDescribedVarTemplate())
Old = Old->getDescribedVarTemplate() ? Old : 0;
else
Old = Old->getDescribedVarTemplate() ? 0 : Old;
@@ -4893,10 +4893,9 @@
bool IsVariableTemplateSpecialization = false;
bool IsPartialSpecialization = false;
bool IsVariableTemplate = false;
- bool Invalid = false; // TODO: Can we remove this (error-prone)?
- TemplateParameterList *TemplateParams = 0;
VarTemplateDecl *PrevVarTemplate = 0;
- VarDecl *NewVD;
+ VarDecl *NewVD = 0;
+ VarTemplateDecl *NewTemplate = 0;
if (!getLangOpts().CPlusPlus) {
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
@@ -4905,6 +4904,8 @@
if (D.isInvalidType())
NewVD->setInvalidDecl();
} else {
+ bool Invalid = false;
+
if (DC->isRecord() && !CurContext->isRecord()) {
// This is an out-of-line definition of a static data member.
switch (SC) {
@@ -4963,10 +4964,11 @@
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
- TemplateParams = MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateParamLists,
- /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+ TemplateParameterList *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) {
@@ -5090,13 +5092,24 @@
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II, R, TInfo, SC);
+ // If this is supposed to be a variable template, create it as such.
+ if (IsVariableTemplate) {
+ NewTemplate =
+ VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
+ TemplateParams, NewVD, PrevVarTemplate);
+ NewVD->setDescribedVarTemplate(NewTemplate);
+ }
+
// 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.
if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
ParsingInitForAutoVars.insert(NewVD);
- if (D.isInvalidType() || Invalid)
+ if (D.isInvalidType() || Invalid) {
NewVD->setInvalidDecl();
+ if (NewTemplate)
+ NewTemplate->setInvalidDecl();
+ }
SetNestedNameSpecifier(NewVD, D);
@@ -5120,6 +5133,8 @@
// Set the lexical context. If the declarator has a C++ scope specifier, the
// lexical context will be different from the semantic context.
NewVD->setLexicalDeclContext(CurContext);
+ if (NewTemplate)
+ NewTemplate->setLexicalDeclContext(CurContext);
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
if (NewVD->hasLocalStorage()) {
@@ -5178,8 +5193,11 @@
<< 0 << NewVD->getDeclName()
<< SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
<< FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
- else
+ else {
NewVD->setModulePrivate();
+ if (NewTemplate)
+ NewTemplate->setModulePrivate();
+ }
}
// Handle attributes prior to checking for duplicates in MergeVarDecl
@@ -5188,6 +5206,13 @@
if (NewVD->hasAttrs())
CheckAlignasUnderalignment(NewVD);
+ if (IsVariableTemplate) {
+ if (PrevVarTemplate)
+ mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl());
+
+ AddPushedVisibilityAttribute(NewVD);
+ }
+
if (getLangOpts().CUDA) {
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
// storage [duration]."
@@ -5285,11 +5310,9 @@
LookupResult PrevDecl(*this, GetNameForDeclarator(D),
LookupOrdinaryName, ForRedeclaration);
PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
- D.setRedeclaration(
- CheckVariableDeclaration(NewVD, PrevDecl, IsVariableTemplate));
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
} else
- D.setRedeclaration(
- CheckVariableDeclaration(NewVD, Previous, IsVariableTemplate));
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
}
// This is an explicit specialization of a static data member. Check it.
@@ -5317,45 +5340,21 @@
}
}
- // If this is not a variable template, return it now.
- if (!IsVariableTemplate)
- 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();
+ PrevVarTemplate->setMemberSpecialization();
- // Set the lexical context of this template
- NewTemplate->setLexicalDeclContext(CurContext);
- if (NewVD->isStaticDataMember() && NewVD->isOutOfLine())
- NewTemplate->setAccess(NewVD->getAccess());
+ if (NewTemplate) {
+ ActOnDocumentableDecl(NewTemplate);
- if (PrevVarTemplate)
- mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl());
+ if (NewVD->isStaticDataMember() && NewVD->isOutOfLine())
+ NewTemplate->setAccess(NewVD->getAccess());
- AddPushedVisibilityAttribute(NewVD);
-
- PushOnScopeChains(NewTemplate, S);
- AddToScope = false;
-
- if (Invalid) {
- NewTemplate->setInvalidDecl();
- NewVD->setInvalidDecl();
+ return NewTemplate;
}
- ActOnDocumentableDecl(NewTemplate);
-
- return NewTemplate;
+ return NewVD;
}
/// \brief Diagnose variable or built-in function shadowing. Implements
@@ -5721,9 +5720,7 @@
/// Sets NewVD->isInvalidDecl() if an error was encountered.
///
/// Returns true if the variable declaration is a redeclaration.
-bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
- LookupResult &Previous,
- bool IsVariableTemplate) {
+bool Sema::CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous) {
CheckVariableDeclarationType(NewVD);
// If the decl is already known invalid, don't check it.
@@ -5773,7 +5770,7 @@
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
if (!Previous.empty()) {
- MergeVarDecl(NewVD, Previous, IsVariableTemplate, MergeTypeWithPrevious);
+ MergeVarDecl(NewVD, Previous, MergeTypeWithPrevious);
return true;
}
return false;
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -2391,7 +2391,7 @@
// If we are providing an explicit specialization of a member variable
// template specialization, make a note of that.
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
- Partial->setMemberSpecialization();
+ PrevPartial->setMemberSpecialization();
// Check that all of the template parameters of the variable template
// partial specialization are deducible from the template
@@ -2477,6 +2477,9 @@
ForRedeclaration);
PrevSpec.addDecl(PrevDecl);
D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
+ } else if (Specialization->isStaticDataMember() &&
+ Specialization->isOutOfLine()) {
+ Specialization->setAccess(VarTemplate->getAccess());
}
// Link instantiations of static data members back to the template from
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -2254,12 +2254,10 @@
};
}
-bool
-Sema::InstantiateClassTemplateSpecialization(
- SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec,
- TemplateSpecializationKind TSK,
- bool Complain) {
+bool Sema::InstantiateClassTemplateSpecialization(
+ SourceLocation PointOfInstantiation,
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK, bool Complain) {
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl());
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -952,7 +952,6 @@
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.
@@ -1028,7 +1027,6 @@
VarTemplatePartialSpecializationDecl *D) {
assert(D->isStaticDataMember() &&
"Only static data member templates are allowed.");
- // FIXME: Also only when instantiating a class?
VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
@@ -2668,12 +2666,17 @@
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);
+
+ // Set the initializer, to use as pattern for initialization.
+ if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext()))
+ PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def);
+ SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
+ LateAttrs, StartingScope);
+ InstPartialSpec->setInit(PartialSpec->getInit());
+
return InstPartialSpec;
}
@@ -3303,9 +3306,12 @@
const MultiLevelTemplateArgumentList &TemplateArgs) {
// Do substitution on the type of the declaration
- TypeSourceInfo *DI =
- SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
- PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
+ ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
+ TypeSourceInfo *DI = SubstType(
+ PatternDecl->getTypeSourceInfo(),
+ MultiLevelTemplateArgumentList(*TemplateArgumentList::CreateCopy(
+ Context, Innermost.begin(), Innermost.size())),
+ PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
if (!DI)
return 0;
@@ -3364,8 +3370,7 @@
} else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
OldVar->hasLinkage())
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
-
- CheckVariableDeclaration(NewVar, Previous, ForVarTemplate);
+ CheckVariableDeclaration(NewVar, Previous);
if (OldVar->isOutOfLine()) {
OldVar->getLexicalDeclContext()->addDecl(NewVar);
Index: test/SemaCXX/cxx1y-variable-templates_in_class.cpp
===================================================================
--- test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -127,13 +127,13 @@
};
namespace in_class_template {
- // FIXME: member data templates of class templates are not well supported yet.
template<typename T>
class D0 {
template<typename U> static U Data;
template<typename U> static const U Data<U*> = U();
};
+ template const int D0<float>::Data<int*>;
template<typename T>
class D1 {
@@ -142,14 +142,41 @@
};
template<typename T>
template<typename U> U* D1<T>::Data<U*> = (U*)(0);
-
- namespace to_be_fixed {
- // FIXME: The following generate runtime exceptions!
+ template int* D1<float>::Data<int*>;
+
+ template<typename T>
+ class D2 {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U*>;
+ };
+ template<>
+ template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1;
+ template int* D1<float>::Data<int*>;
- //template<>
- //template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1;
- //template const int D0<float>::Data<int*>;
- //template int* D1<float>::Data<int*>;
+ namespace bug_files {
+ // FIXME: A bug has been filed addressing an issue similar to these.
+ // No error diagnosis should be produced, because an
+ // explicit specialization of a member templates of class
+ // template specialization should not inherit the partial
+ // specializations from the class template specialization.
+
+ template<typename T>
+ class D0 {
+ template<typename U> static U Data;
+ template<typename U> static const U Data<U*> = U(10); // expected-note {{previous definition is here}}
+ };
+ template<>
+ template<typename U> U D0<float>::Data<U*> = U(100); // expected-error{{redefinition of 'Data'}}
+
+ template<typename T>
+ class D1 {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U*>; // expected-note {{previous definition is here}}
+ };
+ template<typename T>
+ template<typename U> U* D1<T>::Data<U*> = (U*)(0);
+ template<>
+ template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1; // expected-error{{redefinition of 'Data'}}
}
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits