]> granicus.if.org Git - clang/commitdiff
An explicit instantiation definition only instantiations those class
authorDouglas Gregor <dgregor@apple.com>
Tue, 27 Oct 2009 18:42:08 +0000 (18:42 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 27 Oct 2009 18:42:08 +0000 (18:42 +0000)
members that have a definition. Also, use
CheckSpecializationInstantiationRedecl as part of this instantiation
to make sure that we diagnose the various kinds of problems that can
occur with explicit instantiations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85270 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.spec/temp.explicit/p8.cpp [new file with mode: 0644]

index 214febecf2592aa0357fa1d5d6051353c4872404..8071aba7c5d90225750d1c14f7948473aa6e5bb8 100644 (file)
@@ -605,6 +605,9 @@ public:
   /// \brief Determine whether this is or was instantiated from an out-of-line 
   /// definition of a static data member.
   bool isOutOfLine() const;
+
+  /// \brief If this is a static data member, find its out-of-line definition.
+  VarDecl *getOutOfLineDefinition();
   
   /// \brief If this variable is an instantiated static data member of a
   /// class template specialization, returns the templated static data member
index 903d9438ac3aeae187ed11780a424e618bcf2af4..38eb3371fe7c8fe65837245f27eeb4db25da663a 100644 (file)
@@ -383,6 +383,19 @@ bool VarDecl::isOutOfLine() const {
   return false;
 }
 
+VarDecl *VarDecl::getOutOfLineDefinition() {
+  if (!isStaticDataMember())
+    return 0;
+  
+  for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
+       RD != RDEnd; ++RD) {
+    if (RD->getLexicalDeclContext()->isFileContext())
+      return *RD;
+  }
+  
+  return 0;
+}
+
 VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return cast<VarDecl>(MSI->getInstantiatedFrom());
index a40cdf390c84de91b7c0c990839186cf6ba5cc39..32f4ce07326a37516646b8906cd1a7b5cceb2e92 100644 (file)
@@ -2577,6 +2577,14 @@ public:
                                                     MultiTemplateParamsArg TemplateParameterLists,
                                                     Declarator &D);
 
+  bool
+  CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
+                                         TemplateSpecializationKind NewTSK,
+                                         NamedDecl *PrevDecl,
+                                         TemplateSpecializationKind PrevTSK,
+                                         SourceLocation PrevPointOfInstantiation,
+                                         bool &SuppressNew);
+    
   bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
                                            bool HasExplicitTemplateArgs,
                                            SourceLocation LAngleLoc,
index 4419ad04a2506ec6f021eb8c0011feb0b2e56ee8..638e00cb1dc47c693d13bb2f3a536aaca59f7cd5 100644 (file)
@@ -3073,8 +3073,6 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
 /// for those cases where they are required and determining whether the 
 /// new specialization/instantiation will have any effect.
 ///
-/// \param S the semantic analysis object.
-///
 /// \param NewLoc the location of the new explicit specialization or 
 /// instantiation.
 ///
@@ -3092,14 +3090,13 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
 ///
 /// \returns true if there was an error that should prevent the introduction of
 /// the new declaration into the AST, false otherwise.
-static bool 
-CheckSpecializationInstantiationRedecl(Sema &S,
-                                       SourceLocation NewLoc,
-                                       TemplateSpecializationKind NewTSK,
-                                       NamedDecl *PrevDecl,
-                                       TemplateSpecializationKind PrevTSK,
-                                       SourceLocation PrevPointOfInstantiation,
-                                       bool &SuppressNew) {
+bool
+Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
+                                             TemplateSpecializationKind NewTSK,
+                                             NamedDecl *PrevDecl,
+                                             TemplateSpecializationKind PrevTSK,
+                                        SourceLocation PrevPointOfInstantiation,
+                                             bool &SuppressNew) {
   SuppressNew = false;
   
   switch (NewTSK) {
@@ -3137,9 +3134,9 @@ CheckSpecializationInstantiationRedecl(Sema &S,
       //   before the first use of that specialization that would cause an 
       //   implicit instantiation to take place, in every translation unit in
       //   which such a use occurs; no diagnostic is required.
-      S.Diag(NewLoc, diag::err_specialization_after_instantiation)
+      Diag(NewLoc, diag::err_specialization_after_instantiation)
         << PrevDecl;
-      S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
+      Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
         << (PrevTSK != TSK_ImplicitInstantiation);
       
       return true;
@@ -3172,10 +3169,10 @@ CheckSpecializationInstantiationRedecl(Sema &S,
       //   If an entity is the subject of both an explicit instantiation 
       //   declaration and an explicit instantiation definition in the same 
       //   translation unit, the definition shall follow the declaration.
-      S.Diag(NewLoc, 
-             diag::err_explicit_instantiation_declaration_after_definition);
-      S.Diag(PrevPointOfInstantiation, 
-             diag::note_explicit_instantiation_definition_here);
+      Diag(NewLoc, 
+           diag::err_explicit_instantiation_declaration_after_definition);
+      Diag(PrevPointOfInstantiation, 
+           diag::note_explicit_instantiation_definition_here);
       assert(PrevPointOfInstantiation.isValid() &&
              "Explicit instantiation without point of instantiation?");
       SuppressNew = true;
@@ -3201,10 +3198,10 @@ CheckSpecializationInstantiationRedecl(Sema &S,
       // In C++98/03 mode, we only give an extension warning here, because it 
       // is not not harmful to try to explicitly instantiate something that
       // has been explicitly specialized.
-      if (!S.getLangOptions().CPlusPlus0x) {
-        S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
+      if (!getLangOptions().CPlusPlus0x) {
+        Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
           << PrevDecl;
-        S.Diag(PrevDecl->getLocation(),
+        Diag(PrevDecl->getLocation(),
              diag::note_previous_template_specialization);
       }
       SuppressNew = true;
@@ -3220,10 +3217,10 @@ CheckSpecializationInstantiationRedecl(Sema &S,
       //   For a given template and a given set of template-arguments,
       //     - an explicit instantiation definition shall appear at most once
       //       in a program,
-      S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
+      Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
         << PrevDecl;
-      S.Diag(PrevPointOfInstantiation, 
-             diag::note_previous_explicit_instantiation);
+      Diag(PrevPointOfInstantiation, 
+           diag::note_previous_explicit_instantiation);
       SuppressNew = true;
       return false;        
     }
@@ -3336,7 +3333,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
 
   // C++ [temp.expl.spec]p6:
   //   If a template, a member template or the member of a class template is
-  //   explicitly specialized then that specialization shall be declared 
+  //   explicitly specialized then that specialization shall be declared 
   //   before the first use of that specialization that would cause an implicit
   //   instantiation to take place, in every translation unit in which such a 
   //   use occurs; no diagnostic is required.
@@ -3662,7 +3659,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
 
   if (PrevDecl) {
     bool SuppressNew = false;
-    if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK,
+    if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK,
                                                PrevDecl, 
                                               PrevDecl->getSpecializationKind(), 
                                             PrevDecl->getPointOfInstantiation(),
@@ -3738,7 +3735,11 @@ Sema::ActOnExplicitInstantiation(Scope *S,
                                         Specialization->getDefinition(Context));
   if (!Def)
     InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
-  else // Instantiate the members of this class template specialization.
+  
+  // Instantiate the members of this class template specialization.
+  Def = cast_or_null<ClassTemplateSpecializationDecl>(
+                                       Specialization->getDefinition(Context));
+  if (Def)
     InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
 
   return DeclPtrTy::make(Specialization);
@@ -3820,7 +3821,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
     MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo();
     bool SuppressNew = false;
     assert(MSInfo && "No member specialization information?");
-    if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK, 
+    if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, 
                                                PrevDecl,
                                         MSInfo->getTemplateSpecializationKind(),
                                              MSInfo->getPointOfInstantiation(), 
@@ -3844,13 +3845,21 @@ Sema::ActOnExplicitInstantiation(Scope *S,
       Diag(Pattern->getLocation(), diag::note_forward_declaration)
         << Pattern;
       return true;
-    } else if (InstantiateClass(NameLoc, Record, Def,
-                                getTemplateInstantiationArgs(Record),
-                                TSK))
-      return true;
-  } else // Instantiate all of the members of the class.
-    InstantiateClassMembers(NameLoc, RecordDef,
-                            getTemplateInstantiationArgs(Record), TSK);
+    } else {
+      if (InstantiateClass(NameLoc, Record, Def,
+                           getTemplateInstantiationArgs(Record),
+                           TSK))
+        return true;
+
+      RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+      if (!RecordDef)
+        return true;
+    }
+  } 
+  
+  // Instantiate all of the members of the class.
+  InstantiateClassMembers(NameLoc, RecordDef,
+                          getTemplateInstantiationArgs(Record), TSK);
 
   // FIXME: We don't have any representation for explicit instantiations of
   // member classes. Such a representation is not needed for compilation, but it
@@ -3969,8 +3978,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
     assert(MSInfo && "Missing static data member specialization info?");
     bool SuppressNew = false;
-    if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, 
-                                               Prev,
+    if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
                                         MSInfo->getTemplateSpecializationKind(),
                                               MSInfo->getPointOfInstantiation(), 
                                                SuppressNew))
@@ -4069,7 +4077,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
 
   if (PrevDecl) {
     bool SuppressNew = false;
-    if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK,
+    if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK,
                                                PrevDecl, 
                                      PrevDecl->getTemplateSpecializationKind(), 
                                           PrevDecl->getPointOfInstantiation(),
index 22d1e165f0e4d3ecbd94a8dd812552085529ebde..14930134dad615f056113b50d004946b48d9bd24 100644 (file)
@@ -914,13 +914,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
   if (!Invalid)
     Consumer.HandleTagDeclDefinition(Instantiation);
 
-  // If this is an explicit instantiation, instantiate our members, too.
-  if (!Invalid && TSK != TSK_ImplicitInstantiation) {
-    Inst.Clear();
-    InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs,
-                            TSK);
-  }
-
   return Invalid;
 }
 
@@ -944,9 +937,6 @@ Sema::InstantiateClassTemplateSpecialization(
       // declaration (C++0x [temp.explicit]p10); go ahead and perform the
       // explicit instantiation.
       ClassTemplateSpec->setSpecializationKind(TSK);
-      InstantiateClassTemplateSpecializationMembers(PointOfInstantiation,
-                                                    ClassTemplateSpec,
-                                                    TSK);
       return false;
     }
     
@@ -1089,48 +1079,112 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
   for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
                                DEnd = Instantiation->decls_end();
        D != DEnd; ++D) {
+    bool SuppressNew = false;
     if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
-      if (Function->getInstantiatedFromMemberFunction()) {
-        // If this member was explicitly specialized, do nothing.
-        if (Function->getTemplateSpecializationKind() ==
-              TSK_ExplicitSpecialization)
+      if (FunctionDecl *Pattern
+            = Function->getInstantiatedFromMemberFunction()) {
+        MemberSpecializationInfo *MSInfo 
+          = Function->getMemberSpecializationInfo();
+        assert(MSInfo && "No member specialization information?");
+        if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, 
+                                                   Function, 
+                                        MSInfo->getTemplateSpecializationKind(),
+                                              MSInfo->getPointOfInstantiation(), 
+                                                   SuppressNew) ||
+            SuppressNew)
           continue;
         
-        Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+        if (Function->getBody())
+          continue;
+
+        if (TSK == TSK_ExplicitInstantiationDefinition) {
+          // C++0x [temp.explicit]p8:
+          //   An explicit instantiation definition that names a class template
+          //   specialization explicitly instantiates the class template 
+          //   specialization and is only an explicit instantiation definition 
+          //   of members whose definition is visible at the point of 
+          //   instantiation.
+          if (!Pattern->getBody())
+            continue;
+        
+          Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+                      
+          InstantiateFunctionDefinition(PointOfInstantiation, Function);
+        } else {
+          Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+        }
       }
-      
-      if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition)
-        InstantiateFunctionDefinition(PointOfInstantiation, Function);
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
       if (Var->isStaticDataMember()) {
-        // If this member was explicitly specialized, do nothing.
-        if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+        assert(MSInfo && "No member specialization information?");
+        if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, 
+                                                   Var, 
+                                        MSInfo->getTemplateSpecializationKind(),
+                                              MSInfo->getPointOfInstantiation(), 
+                                                   SuppressNew) ||
+            SuppressNew)
           continue;
         
-        Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-        
-        if (TSK == TSK_ExplicitInstantiationDefinition)
+        if (TSK == TSK_ExplicitInstantiationDefinition) {
+          // C++0x [temp.explicit]p8:
+          //   An explicit instantiation definition that names a class template
+          //   specialization explicitly instantiates the class template 
+          //   specialization and is only an explicit instantiation definition 
+          //   of members whose definition is visible at the point of 
+          //   instantiation.
+          if (!Var->getInstantiatedFromStaticDataMember()
+                                                     ->getOutOfLineDefinition())
+            continue;
+          
+          Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
           InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
-      }        
+        } else {
+          Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+        }
+      }      
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
       if (Record->isInjectedClassName())
         continue;
       
-      assert(Record->getInstantiatedFromMemberClass() &&
-             "Missing instantiated-from-template information");
-      
-      // If this member was explicitly specialized, do nothing.
-      if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+      MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
+      assert(MSInfo && "No member specialization information?");
+      if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, 
+                                                 Record, 
+                                        MSInfo->getTemplateSpecializationKind(),
+                                              MSInfo->getPointOfInstantiation(), 
+                                                 SuppressNew) ||
+          SuppressNew)
         continue;
       
-      if (!Record->getDefinition(Context))
-        InstantiateClass(PointOfInstantiation, Record,
-                         Record->getInstantiatedFromMemberClass(),
+      CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
+      assert(Pattern && "Missing instantiated-from-template information");
+      
+      if (!Record->getDefinition(Context)) {
+        if (!Pattern->getDefinition(Context)) {
+          // C++0x [temp.explicit]p8:
+          //   An explicit instantiation definition that names a class template
+          //   specialization explicitly instantiates the class template 
+          //   specialization and is only an explicit instantiation definition 
+          //   of members whose definition is visible at the point of 
+          //   instantiation.
+          if (TSK == TSK_ExplicitInstantiationDeclaration) {
+            MSInfo->setTemplateSpecializationKind(TSK);
+            MSInfo->setPointOfInstantiation(PointOfInstantiation);
+          }
+          
+          continue;
+        }
+        
+        InstantiateClass(PointOfInstantiation, Record, Pattern,
                          TemplateArgs,
                          TSK);
+      }
       
-      InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, 
-                              TSK);
+      Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+      if (Pattern)
+        InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, 
+                                TSK);
     }
   }
 }
index 422a7bc04d7c7bda0caf81d4f295cf892f83d493..c9319c58aefb7594bcdb329a5916ff43fb2a71d0 100644 (file)
@@ -1231,24 +1231,17 @@ void Sema::InstantiateStaticDataMemberDefinition(
 
   // Find the out-of-line definition of this static data member.
   VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
-  bool FoundOutOfLineDef = false;
   assert(Def && "This data member was not instantiated from a template?");
-  assert(Def->isStaticDataMember() && "Not a static data member?");
-  for (VarDecl::redecl_iterator RD = Def->redecls_begin(),
-                             RDEnd = Def->redecls_end();
-       RD != RDEnd; ++RD) {
-    if (RD->getLexicalDeclContext()->isFileContext()) {
-      Def = *RD;
-      FoundOutOfLineDef = true;
-    }
-  }
+  assert(Def->isStaticDataMember() && "Not a static data member?");  
+  Def = Def->getOutOfLineDefinition();
 
-  if (!FoundOutOfLineDef) {
+  if (!Def) {
     // We did not find an out-of-line definition of this static data member,
     // so we won't perform any instantiation. Rather, we rely on the user to
     // instantiate this definition (or provide a specialization for it) in
     // another translation unit.
     if (DefinitionRequired) {
+      Def = Var->getInstantiatedFromStaticDataMember();
       Diag(PointOfInstantiation, 
            diag::err_explicit_instantiation_undefined_member)
         << 2 << Var->getDeclName() << Var->getDeclContext();
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p8.cpp b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp
new file mode 100644 (file)
index 0000000..9a5bd32
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+  struct MemberClass;
+  
+  T* f0(T* ptr);
+  
+  static T* static_member;
+};
+
+template class X0<int>; // okay
+template class X0<int(int)>; // okay; nothing gets instantiated.
+
+template<typename T>
+struct X0<T>::MemberClass {
+  T member;
+};
+
+template<typename T>
+T* X0<T>::f0(T* ptr) {
+  return ptr + 1;
+}
+
+template<typename T>
+T* X0<T>::static_member = 0;
+