PR35456: Track definedness of variable template specializations separately from

whether they have an initializer.

We cannot distinguish between a declaration of a variable template
specialization and a definition of one that lacks an initializer without this,
and would previously mistake the latter for the former.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@319605 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2017-12-02 02:48:42 +00:00
parent 37dd25ad0c
commit e9089c9a34
8 changed files with 35 additions and 12 deletions

View File

@ -2540,6 +2540,12 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Really a value of type TemplateSpecializationKind.
unsigned SpecializationKind : 3;
/// \brief Whether this declaration is a complete definition of the
/// variable template specialization. We can't otherwise tell apart
/// an instantiated declaration from an instantiated definition with
/// no initializer.
unsigned IsCompleteDefinition : 1;
protected:
VarTemplateSpecializationDecl(Kind DK, ASTContext &Context, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
@ -2553,6 +2559,7 @@ protected:
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class VarDecl;
static VarTemplateSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
@ -2616,6 +2623,8 @@ public:
PointOfInstantiation = Loc;
}
void setCompleteDefinition() { IsCompleteDefinition = true; }
/// \brief If this variable template specialization is an instantiation of
/// a template (rather than an explicit specialization), return the
/// variable template or variable template partial specialization from which

View File

@ -2029,9 +2029,12 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const {
// A variable template specialization (other than a static data member
// template or an explicit specialization) is a declaration until we
// instantiate its initializer.
if (isa<VarTemplateSpecializationDecl>(this) &&
getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
return DeclarationOnly;
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(this)) {
if (VTSD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
!isa<VarTemplatePartialSpecializationDecl>(VTSD) &&
!VTSD->IsCompleteDefinition)
return DeclarationOnly;
}
if (hasExternalStorage())
return DeclarationOnly;

View File

@ -1043,13 +1043,13 @@ VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(
SpecializedTemplate->getIdentifier(), T, TInfo, S),
SpecializedTemplate(SpecializedTemplate),
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)),
SpecializationKind(TSK_Undeclared) {}
SpecializationKind(TSK_Undeclared), IsCompleteDefinition(false) {}
VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK,
ASTContext &C)
: VarDecl(DK, C, nullptr, SourceLocation(), SourceLocation(), nullptr,
QualType(), nullptr, SC_None),
SpecializationKind(TSK_Undeclared) {}
SpecializationKind(TSK_Undeclared), IsCompleteDefinition(false) {}
VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,

View File

@ -4021,6 +4021,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl,
const MultiLevelTemplateArgumentList &TemplateArgs) {
assert(PatternDecl->isThisDeclarationADefinition() &&
"don't have a definition to instantiate from");
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
@ -4032,6 +4034,9 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
// Update the type of this variable template specialization.
VarSpec->setType(DI->getType());
// Convert the declaration into a definition now.
VarSpec->setCompleteDefinition();
// Instantiate the initializer.
InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs);
@ -4225,6 +4230,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
if (Var->isInvalidDecl())
return;
// FIXME: We're missing ASTMutationListener notifications for all of the work
// done here. (Some of our callers notify the listeners for the static data
// member case, but not in general.)
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
VarDecl *PatternDecl = nullptr, *Def = nullptr;

View File

@ -2198,6 +2198,7 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
D->PointOfInstantiation = ReadSourceLocation();
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->IsCompleteDefinition = Record.readInt();
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {

View File

@ -1494,6 +1494,7 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
Record.AddTemplateArgumentList(&D->getTemplateArgs());
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->IsCompleteDefinition);
Record.push_back(D->isCanonicalDecl());
if (D->isCanonicalDecl()) {

View File

@ -18,6 +18,12 @@ int init_arr();
template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() };
int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>;
namespace PR35456 {
// CHECK: @_ZN7PR354561nILi0EEE = linkonce_odr global i32 0
template<int> int n;
int *p = &n<0>;
}
// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = linkonce_odr global [123 x i32] zeroinitializer
// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = linkonce_odr global

View File

@ -102,15 +102,9 @@ inline int __declspec(dllexport) inlineStaticLocalsFunc() {
// Declarations are not exported.
// dllexport implies a definition.
// MSC-NOT: @"\01??$VarTmplDef@UExplicitInst_Exported@@@@3HA"
// GNU-NOT: @_Z10VarTmplDefI21ExplicitInst_ExportedE
template<typename T> __declspec(dllexport) int VarTmplDef;
INSTVAR(VarTmplDef<ExplicitInst_Exported>)
// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = external global
// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = external global
template<typename T> __declspec(dllexport) int VarTmplImplicitDef;
template<typename T> __declspec(dllexport) extern int VarTmplImplicitDef;
USEVAR(VarTmplImplicitDef<ImplicitInst_Exported>)
// Export definition.