/// 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,
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
+ friend class VarDecl;
static VarTemplateSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
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
// 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;
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,
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 =
// 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);
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;
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
D->PointOfInstantiation = ReadSourceLocation();
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
+ D->IsCompleteDefinition = Record.readInt();
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {
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()) {
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
// 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.