]> granicus.if.org Git - clang/commitdiff
PR35456: Track definedness of variable template specializations separately from
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 2 Dec 2017 02:48:42 +0000 (02:48 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 2 Dec 2017 02:48:42 +0000 (02:48 +0000)
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

include/clang/AST/DeclTemplate.h
lib/AST/Decl.cpp
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/CodeGenCXX/cxx1y-variable-template.cpp
test/CodeGenCXX/dllexport.cpp

index 991f07360659185ae75be8e630d556c6d3b960a2..96493fc78bd7321907e21581b95da1b58905817d 100644 (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
index 41c4fd0e6c0bc81efb5d3e248d5bd91ca539f208..29846b61010138337b682e326fd724eadc133cdb 100644 (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;
index f5a2ab07bf76e91ac75c0a150db50a71519f6acc..54e8dd866243fe7e6bafeb84a056c2331a26ad8e 100644 (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,
index 5b528fa9c2e8063c02ae69d2933a9f4a4cacae64..eacb325642e9a2838dc9d3966cb7d7d8a6a8f9c1 100644 (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;
index 126738b6173817cbb190554d85be7c8d6ef3cfb8..eb7c1777ac63b98375197286e9d28a77ffaf51ff 100644 (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) {
index fcf78e850b2a0d8dd05ab5ee149ca1ab65d5a919..041ccd47d03efe25aef778a288361d72062f03b0 100644 (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()) {
index cd73817d8508eeff00a4ecc4ac6f2823724a348c..dd8f28e42992c39e9fb683bc71b178da315a57c3 100644 (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
 
index d79a19420acb5a744bf00c2f47c07d26ce37da6b..a446147b6cdc6b8d73b1797cbf8b1b03315abf88 100644 (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.