forked from OSchip/llvm-project
Bug fix: disallow a variable template to be redeclared as a non-templated variable
llvm-svn: 188350
This commit is contained in:
parent
db2162903e
commit
d8dd97c0a2
|
@ -1472,7 +1472,8 @@ public:
|
||||||
MultiTemplateParamsArg TemplateParamLists,
|
MultiTemplateParamsArg TemplateParamLists,
|
||||||
bool &AddToScope);
|
bool &AddToScope);
|
||||||
// Returns true if the variable declaration is a redeclaration
|
// Returns true if the variable declaration is a redeclaration
|
||||||
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
|
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
|
||||||
|
bool IsVariableTemplate = false);
|
||||||
void CheckVariableDeclarationType(VarDecl *NewVD);
|
void CheckVariableDeclarationType(VarDecl *NewVD);
|
||||||
void CheckCompleteVariableDeclaration(VarDecl *var);
|
void CheckCompleteVariableDeclaration(VarDecl *var);
|
||||||
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
||||||
|
@ -1868,9 +1869,8 @@ public:
|
||||||
Scope *S, bool MergeTypeWithOld);
|
Scope *S, bool MergeTypeWithOld);
|
||||||
void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
|
void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
|
||||||
void MergeVarDecl(VarDecl *New, LookupResult &Previous,
|
void MergeVarDecl(VarDecl *New, LookupResult &Previous,
|
||||||
bool MergeTypeWithPrevious);
|
bool IsVariableTemplate, bool MergeTypeWithPrevious);
|
||||||
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
|
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
|
||||||
bool MergeTypeWithOld);
|
|
||||||
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
|
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
|
||||||
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
|
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
|
||||||
|
|
||||||
|
|
|
@ -2920,15 +2920,21 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
|
||||||
/// definitions here, since the initializer hasn't been attached.
|
/// definitions here, since the initializer hasn't been attached.
|
||||||
///
|
///
|
||||||
void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
|
void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
|
||||||
bool MergeTypeWithPrevious) {
|
bool IsVariableTemplate, bool MergeTypeWithPrevious) {
|
||||||
// If the new decl is already invalid, don't do any other checking.
|
// If the new decl is already invalid, don't do any other checking.
|
||||||
if (New->isInvalidDecl())
|
if (New->isInvalidDecl())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Verify the old decl was also a variable.
|
// Verify the old decl was also a variable or variable template.
|
||||||
VarDecl *Old = 0;
|
VarDecl *Old = 0;
|
||||||
if (!Previous.isSingleResult() ||
|
if (Previous.isSingleResult() &&
|
||||||
!(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
|
(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
|
||||||
|
if (IsVariableTemplate)
|
||||||
|
Old = Old->getDescribedVarTemplate() ? Old : 0;
|
||||||
|
else
|
||||||
|
Old = Old->getDescribedVarTemplate() ? 0 : Old;
|
||||||
|
}
|
||||||
|
if (!Old) {
|
||||||
Diag(New->getLocation(), diag::err_redefinition_different_kind)
|
Diag(New->getLocation(), diag::err_redefinition_different_kind)
|
||||||
<< New->getDeclName();
|
<< New->getDeclName();
|
||||||
Diag(Previous.getRepresentativeDecl()->getLocation(),
|
Diag(Previous.getRepresentativeDecl()->getLocation(),
|
||||||
|
@ -4919,6 +4925,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
bool IsExplicitSpecialization = false;
|
bool IsExplicitSpecialization = false;
|
||||||
bool IsVariableTemplateSpecialization = false;
|
bool IsVariableTemplateSpecialization = false;
|
||||||
bool IsPartialSpecialization = false;
|
bool IsPartialSpecialization = false;
|
||||||
|
bool IsVariableTemplate = false;
|
||||||
bool Invalid = false; // TODO: Can we remove this (error-prone)?
|
bool Invalid = false; // TODO: Can we remove this (error-prone)?
|
||||||
TemplateParameterList *TemplateParams = 0;
|
TemplateParameterList *TemplateParams = 0;
|
||||||
VarTemplateDecl *PrevVarTemplate = 0;
|
VarTemplateDecl *PrevVarTemplate = 0;
|
||||||
|
@ -5019,6 +5026,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
|
|
||||||
} else { // if (TemplateParams->size() > 0)
|
} else { // if (TemplateParams->size() > 0)
|
||||||
// This is a template declaration.
|
// This is a template declaration.
|
||||||
|
IsVariableTemplate = true;
|
||||||
|
|
||||||
// Check that we can declare a template here.
|
// Check that we can declare a template here.
|
||||||
if (CheckTemplateDeclScope(S, TemplateParams))
|
if (CheckTemplateDeclScope(S, TemplateParams))
|
||||||
|
@ -5310,9 +5318,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
LookupResult PrevDecl(*this, GetNameForDeclarator(D),
|
LookupResult PrevDecl(*this, GetNameForDeclarator(D),
|
||||||
LookupOrdinaryName, ForRedeclaration);
|
LookupOrdinaryName, ForRedeclaration);
|
||||||
PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
|
PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
|
||||||
D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
|
D.setRedeclaration(
|
||||||
|
CheckVariableDeclaration(NewVD, PrevDecl, IsVariableTemplate));
|
||||||
} else
|
} else
|
||||||
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
|
D.setRedeclaration(
|
||||||
|
CheckVariableDeclaration(NewVD, Previous, IsVariableTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an explicit specialization of a static data member. Check it.
|
// This is an explicit specialization of a static data member. Check it.
|
||||||
|
@ -5340,8 +5350,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is not a variable template, return it now
|
// If this is not a variable template, return it now.
|
||||||
if (!TemplateParams || IsVariableTemplateSpecialization)
|
if (!IsVariableTemplate)
|
||||||
return NewVD;
|
return NewVD;
|
||||||
|
|
||||||
// If this is supposed to be a variable template, create it as such.
|
// If this is supposed to be a variable template, create it as such.
|
||||||
|
@ -5745,7 +5755,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
|
||||||
///
|
///
|
||||||
/// Returns true if the variable declaration is a redeclaration.
|
/// Returns true if the variable declaration is a redeclaration.
|
||||||
bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
LookupResult &Previous) {
|
LookupResult &Previous,
|
||||||
|
bool IsVariableTemplate) {
|
||||||
CheckVariableDeclarationType(NewVD);
|
CheckVariableDeclarationType(NewVD);
|
||||||
|
|
||||||
// If the decl is already known invalid, don't check it.
|
// If the decl is already known invalid, don't check it.
|
||||||
|
@ -5795,7 +5806,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
|
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
|
||||||
|
|
||||||
if (!Previous.empty()) {
|
if (!Previous.empty()) {
|
||||||
MergeVarDecl(NewVD, Previous, MergeTypeWithPrevious);
|
MergeVarDecl(NewVD, Previous, IsVariableTemplate, MergeTypeWithPrevious);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2280,32 +2280,6 @@ static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
|
||||||
bool IsPartialSpecialization);
|
bool IsPartialSpecialization);
|
||||||
|
|
||||||
static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
|
static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
|
||||||
/*
|
|
||||||
// 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(
|
DeclResult Sema::ActOnVarTemplateSpecialization(
|
||||||
Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
|
Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
|
||||||
|
@ -2359,13 +2333,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
|
||||||
if (!ExpectedDI)
|
if (!ExpectedDI)
|
||||||
return true;
|
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
|
// Find the variable template (partial) specialization declaration that
|
||||||
// corresponds to these arguments.
|
// corresponds to these arguments.
|
||||||
if (IsPartialSpecialization) {
|
if (IsPartialSpecialization) {
|
||||||
|
|
|
@ -3365,7 +3365,7 @@ void Sema::BuildVariableInstantiation(
|
||||||
OldVar->hasLinkage())
|
OldVar->hasLinkage())
|
||||||
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
|
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
|
||||||
|
|
||||||
CheckVariableDeclaration(NewVar, Previous);
|
CheckVariableDeclaration(NewVar, Previous, ForVarTemplate);
|
||||||
|
|
||||||
if (OldVar->isOutOfLine()) {
|
if (OldVar->isOutOfLine()) {
|
||||||
OldVar->getLexicalDeclContext()->addDecl(NewVar);
|
OldVar->getLexicalDeclContext()->addDecl(NewVar);
|
||||||
|
|
|
@ -943,7 +943,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
|
||||||
VD->setCachedLinkage(Linkage(Record[Idx++]));
|
VD->setCachedLinkage(Linkage(Record[Idx++]));
|
||||||
|
|
||||||
// Only true variables (not parameters or implicit parameters) can be merged.
|
// Only true variables (not parameters or implicit parameters) can be merged.
|
||||||
if (VD->getKind() == Decl::Var)
|
if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
|
||||||
mergeRedeclarable(VD, Redecl);
|
mergeRedeclarable(VD, Redecl);
|
||||||
|
|
||||||
if (uint64_t Val = Record[Idx++]) {
|
if (uint64_t Val = Record[Idx++]) {
|
||||||
|
@ -955,11 +955,22 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Record[Idx++]) { // HasMemberSpecializationInfo.
|
enum VarKind {
|
||||||
|
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
|
||||||
|
};
|
||||||
|
switch ((VarKind)Record[Idx++]) {
|
||||||
|
case VarNotTemplate:
|
||||||
|
break;
|
||||||
|
case VarTemplate:
|
||||||
|
VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
|
||||||
|
break;
|
||||||
|
case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
|
||||||
VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
|
VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
|
||||||
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
|
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
|
||||||
SourceLocation POI = ReadSourceLocation(Record, Idx);
|
SourceLocation POI = ReadSourceLocation(Record, Idx);
|
||||||
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
|
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redecl;
|
return Redecl;
|
||||||
|
@ -1433,7 +1444,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
|
||||||
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
|
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
|
||||||
|
|
||||||
if (ThisDeclID == Redecl.getFirstID()) {
|
if (ThisDeclID == Redecl.getFirstID()) {
|
||||||
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
|
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
|
||||||
// the specializations.
|
// the specializations.
|
||||||
SmallVector<serialization::DeclID, 2> SpecIDs;
|
SmallVector<serialization::DeclID, 2> SpecIDs;
|
||||||
SpecIDs.push_back(0);
|
SpecIDs.push_back(0);
|
||||||
|
|
|
@ -712,14 +712,21 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
||||||
} else {
|
} else {
|
||||||
Record.push_back(0);
|
Record.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberSpecializationInfo *SpecInfo
|
enum {
|
||||||
= D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0;
|
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
|
||||||
Record.push_back(SpecInfo != 0);
|
};
|
||||||
if (SpecInfo) {
|
if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) {
|
||||||
|
Record.push_back(VarTemplate);
|
||||||
|
Writer.AddDeclRef(TemplD, Record);
|
||||||
|
} else if (MemberSpecializationInfo *SpecInfo
|
||||||
|
= D->getMemberSpecializationInfo()) {
|
||||||
|
Record.push_back(StaticDataMemberSpecialization);
|
||||||
Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record);
|
Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record);
|
||||||
Record.push_back(SpecInfo->getTemplateSpecializationKind());
|
Record.push_back(SpecInfo->getTemplateSpecializationKind());
|
||||||
Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
|
Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
|
||||||
|
} else {
|
||||||
|
Record.push_back(VarNotTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!D->hasAttrs() &&
|
if (!D->hasAttrs() &&
|
||||||
|
@ -739,7 +746,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
||||||
!isa<VarTemplateSpecializationDecl>(D) &&
|
!isa<VarTemplateSpecializationDecl>(D) &&
|
||||||
!D->isConstexpr() &&
|
!D->isConstexpr() &&
|
||||||
!D->isPreviousDeclInSameBlockScope() &&
|
!D->isPreviousDeclInSameBlockScope() &&
|
||||||
!SpecInfo)
|
!D->getMemberSpecializationInfo())
|
||||||
AbbrevToUse = Writer.getDeclVarAbbrev();
|
AbbrevToUse = Writer.getDeclVarAbbrev();
|
||||||
|
|
||||||
Code = serialization::DECL_VAR;
|
Code = serialization::DECL_VAR;
|
||||||
|
|
|
@ -20,7 +20,7 @@ template<typename T>
|
||||||
T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}}
|
T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}}
|
||||||
|
|
||||||
template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \
|
template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \
|
||||||
expected-error{{redefinition of 'pi0' with a different type: 'int' vs 'T'}}
|
expected-error{{redefinition of 'pi0' as different kind of symbol}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -163,8 +163,7 @@ namespace PR9877 {
|
||||||
template<> struct X<1>::Y { static const int Z = 1; };
|
template<> struct X<1>::Y { static const int Z = 1; };
|
||||||
|
|
||||||
const int X<0>::Y::Z;
|
const int X<0>::Y::Z;
|
||||||
template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}} \
|
template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
|
||||||
// expected-error{{forward declaration of variable template cannot have a nested name specifier}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PR9913 {
|
namespace PR9913 {
|
||||||
|
|
|
@ -168,5 +168,4 @@ namespace spec_join1 {
|
||||||
int* intpb = vd<int>;
|
int* intpb = vd<int>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace odr_tmpl {
|
||||||
}
|
}
|
||||||
namespace pvt_cv {
|
namespace pvt_cv {
|
||||||
template<typename T> T v; // expected-note {{previous definition is here}}
|
template<typename T> T v; // expected-note {{previous definition is here}}
|
||||||
int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}}
|
int v; // expected-error {{redefinition of 'v' as different kind of symbol}}
|
||||||
}
|
}
|
||||||
namespace pvt_cvt {
|
namespace pvt_cvt {
|
||||||
template<typename T> T v0; // expected-note {{previous definition is here}}
|
template<typename T> T v0; // expected-note {{previous definition is here}}
|
||||||
|
@ -107,6 +107,9 @@ namespace odr_tmpl {
|
||||||
#ifdef CXX11
|
#ifdef CXX11
|
||||||
template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
|
template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template<typename T> T var = T(); // expected-note {{previous definition is here}}
|
||||||
|
extern int var; // expected-error {{redefinition of 'var' as different kind of symbol}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CXX11
|
#ifdef CXX11
|
||||||
|
|
Loading…
Reference in New Issue