mirror of https://github.com/microsoft/clang.git
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:
parent
37dd25ad0c
commit
e9089c9a34
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue