]> granicus.if.org Git - clang/commitdiff
Improve checking for specializations of member classes of class
authorDouglas Gregor <dgregor@apple.com>
Thu, 8 Oct 2009 15:14:33 +0000 (15:14 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 8 Oct 2009 15:14:33 +0000 (15:14 +0000)
templates, and keep track of how those member classes were
instantiated or specialized.

Make sure that we don't try to instantiate an explicitly-specialized
member class of a class template, when that explicit specialization
was a declaration rather than a definition.

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

include/clang/AST/DeclCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/DeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/SemaType.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
test/Parser/cxx-template-decl.cpp

index ee6314cc36466f49102670f9cea005317da52323..85c678acd227d7e81213f1fc264ba030a3db9b39 100644 (file)
@@ -391,8 +391,9 @@ class CXXRecordDecl : public RecordDecl {
   /// declarations that describe a class template, this will be a
   /// pointer to a ClassTemplateDecl. For member
   /// classes of class template specializations, this will be the
-  /// RecordDecl from which the member class was instantiated.
-  llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*>
+  /// MemberSpecializationInfo referring to the member class that was 
+  /// instantiated or specialized.
+  llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
     TemplateOrInstantiation;
   
   void getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
@@ -703,15 +704,12 @@ public:
   /// the CXXRecordDecl X<T>::A. When a complete definition of
   /// X<int>::A is required, it will be instantiated from the
   /// declaration returned by getInstantiatedFromMemberClass().
-  CXXRecordDecl *getInstantiatedFromMemberClass() const {
-    return TemplateOrInstantiation.dyn_cast<CXXRecordDecl*>();
-  }
-
+  CXXRecordDecl *getInstantiatedFromMemberClass() const;
+  
   /// \brief Specify that this record is an instantiation of the
   /// member class RD.
-  void setInstantiationOfMemberClass(CXXRecordDecl *RD) {
-    TemplateOrInstantiation = RD;
-  }
+  void setInstantiationOfMemberClass(CXXRecordDecl *RD,
+                                     TemplateSpecializationKind TSK);
 
   /// \brief Retrieves the class template that is described by this
   /// class declaration.
@@ -732,6 +730,14 @@ public:
     TemplateOrInstantiation = Template;
   }
 
+  /// \brief Determine whether this particular class is a specialization or
+  /// instantiation of a class template or member class of a class template,
+  /// and how it was instantiated or specialized.
+  TemplateSpecializationKind getTemplateSpecializationKind();
+  
+  /// \brief Set the kind of specialization or template instantiation this is.
+  void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+  
   /// getDefaultConstructor - Returns the default constructor for this class
   CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
 
index 09f39513b47c2cae27058fbd19c85ee66f29ca07..0a267091f577550c1659100cd3515bfec9c21bce 100644 (file)
@@ -846,6 +846,8 @@ def err_template_param_default_arg_missing : Error<
 def err_template_variable : Error<"variable %0 declared as a template">;
 def err_template_variable_noparams : Error<
   "extraneous 'template<>' in declaration of variable %0">;
+def err_template_tag_noparams : Error<
+  "extraneous 'template<>' in declaration of %0 %1">;
 
 // C++ Template Argument Lists
 def err_template_arg_list_different_arity : Error<
index 7408f2fc60783b0d3cf86ac09908f80cfbc2bd15..2d35117a50ba5c7c08093509aea98c118d3c773b 100644 (file)
@@ -437,6 +437,53 @@ void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
   Conversions.addOverload(ConvDecl);
 }
 
+CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
+  if (MemberSpecializationInfo *MSInfo
+        = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>())
+    return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
+  
+  return 0;
+}
+
+void 
+CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
+                                             TemplateSpecializationKind TSK) {
+  assert(TemplateOrInstantiation.isNull() && 
+         "Previous template or instantiation?");
+  assert(!isa<ClassTemplateSpecializationDecl>(this));
+  TemplateOrInstantiation 
+    = new (getASTContext()) MemberSpecializationInfo(RD, TSK);
+}
+
+TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() {
+  if (ClassTemplateSpecializationDecl *Spec
+        = dyn_cast<ClassTemplateSpecializationDecl>(this))
+    return Spec->getSpecializationKind();
+  
+  if (MemberSpecializationInfo *MSInfo
+      = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>())
+    return MSInfo->getTemplateSpecializationKind();
+  
+  return TSK_Undeclared;
+}
+
+void 
+CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+  if (ClassTemplateSpecializationDecl *Spec
+      = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
+    Spec->setSpecializationKind(TSK);
+    return;
+  }
+  
+  if (MemberSpecializationInfo *MSInfo
+        = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>()) {
+    MSInfo->setTemplateSpecializationKind(TSK);
+    return;
+  }
+  
+  assert(false && "Not a class template or member class specialization");
+}
+
 CXXConstructorDecl *
 CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
   QualType ClassType = Context.getTypeDeclType(this);
index 2070335a6146de00b014e646b11f53a54b28cf08..267eea8a1bca5df05420a356d76a5e5aee9d163a 100644 (file)
@@ -4161,11 +4161,14 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
         TemplateParameterLists.release();
         return Result.get();
       } else {
-        // FIXME: diagnose the extraneous 'template<>', once we recover
-        // slightly better in ParseTemplate.cpp from bogus template
-        // parameters.
+        // The "template<>" header is extraneous.
+        Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
+          << ElaboratedType::getNameForTagKind(Kind) << Name;
+        isExplicitSpecialization = true;
       }
     }
+             
+    TemplateParameterLists.release();
   }
 
   DeclContext *SearchDC = CurContext;
@@ -4493,6 +4496,11 @@ CreateNewDecl:
     }
   }
 
+  // If this is a specialization of a member class (of a class template),
+  // check the specialization.
+  if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl))
+    Invalid = true;
+      
   if (Invalid)
     New->setInvalidDecl();
 
index 5c6ec0004af22c8a45e548796aaca852fa1522ce..219d73146ea39f75e1d3ba4b6cea25c361fb76a9 100644 (file)
@@ -2360,15 +2360,13 @@ static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
   if (!D)
     return TSK_Undeclared;
   
-  if (ClassTemplateSpecializationDecl *CTS 
-        = dyn_cast<ClassTemplateSpecializationDecl>(D))
-    return CTS->getSpecializationKind();
+  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+    return Record->getTemplateSpecializationKind();
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
     return Function->getTemplateSpecializationKind();
   if (VarDecl *Var = dyn_cast<VarDecl>(D))
     return Var->getTemplateSpecializationKind();
   
-  // FIXME: member classes of class templates!
   return TSK_Undeclared;
 }
 
@@ -3192,23 +3190,46 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) {
   // FIXME: Check for specialization-after-instantiation errors and such.
   
   // Note that this is an explicit instantiation of a member.
+  // the original declaration to note that it is an explicit specialization
+  // (if it was previously an implicit instantiation). This latter step
+  // makes bookkeeping easier.
   if (isa<FunctionDecl>(Member)) {
-    // FIXME: We're also setting the original instantiation we found to be
-    // an explicit specialization, although I'd rather not have to do this.
-    cast<FunctionDecl>(Instantiation)->setTemplateSpecializationKind(
-                                                    TSK_ExplicitSpecialization);
+    FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
+    if (InstantiationFunction->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationFunction->setTemplateSpecializationKind(
+                                                  TSK_ExplicitSpecialization);
+      InstantiationFunction->setLocation(Member->getLocation());
+    }
+    
     cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
                                         cast<CXXMethodDecl>(InstantiatedFrom),
                                                   TSK_ExplicitSpecialization);
   } else if (isa<VarDecl>(Member)) {
+    VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
+    if (InstantiationVar->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationVar->setTemplateSpecializationKind(
+                                                  TSK_ExplicitSpecialization);
+      InstantiationVar->setLocation(Member->getLocation());
+    }
+    
     Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
                                                 cast<VarDecl>(InstantiatedFrom),
                                                 TSK_ExplicitSpecialization);
   } else {
     assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
-    // FIXME: Record TSK_ExplicitSpecialization.
+    CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
+    if (InstantiationClass->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationClass->setTemplateSpecializationKind(
+                                                   TSK_ExplicitSpecialization);
+      InstantiationClass->setLocation(Member->getLocation());
+    }
+    
     cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
-                                        cast<CXXRecordDecl>(InstantiatedFrom));
+                                        cast<CXXRecordDecl>(InstantiatedFrom),
+                                                   TSK_ExplicitSpecialization);
   }
              
   // Save the caller the trouble of having to figure out which declaration
index 2f7af60e05d0a5a0fc837a76cede67c019c3a724..ec00d9805c095715286776f107b4a38be8d7fed0 100644 (file)
@@ -972,20 +972,30 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
                               CXXRecordDecl *Instantiation,
                         const MultiLevelTemplateArgumentList &TemplateArgs,
                               TemplateSpecializationKind TSK) {
-  // FIXME: extern templates
   for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
                                DEnd = Instantiation->decls_end();
        D != DEnd; ++D) {
     if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
-      if (Function->getInstantiatedFromMemberFunction())
+      if (Function->getInstantiatedFromMemberFunction()) {
+        // If this member was explicitly specialized, do nothing.
+        if (Function->getTemplateSpecializationKind() ==
+              TSK_ExplicitSpecialization)
+          continue;
+        
         Function->setTemplateSpecializationKind(TSK);
-      if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
+      }
+      
+      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)
+          continue;
+        
         Var->setTemplateSpecializationKind(TSK);
         
-        if (TSK != TSK_ExplicitInstantiationDeclaration)
+        if (TSK == TSK_ExplicitInstantiationDefinition)
           InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
       }        
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
@@ -994,6 +1004,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
       
       assert(Record->getInstantiatedFromMemberClass() &&
              "Missing instantiated-from-template information");
+      
+      // If this member was explicitly specialized, do nothing.
+      if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        continue;
+      
       if (!Record->getDefinition(Context))
         InstantiateClass(PointOfInstantiation, Record,
                          Record->getInstantiatedFromMemberClass(),
index bafcea054e1143f4bf710886038f0346c25dc1ab..b354827e016c0f9b327c552248c638a9b68f1861 100644 (file)
@@ -454,7 +454,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
   if (D->getAccess() != AS_none)
     Record->setAccess(D->getAccess());
   if (!D->isInjectedClassName())
-    Record->setInstantiationOfMemberClass(D);
+    Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
 
   // If the original function was part of a friend declaration,
   // inherit its namespace state.
index 402bc9db0880c65716db9341364eee4850eec618..da72197f0ca1ebb006c0ec3a72f66a2ea0134317 100644 (file)
@@ -1849,10 +1849,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
                  = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
       if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
         // This record was instantiated from a class within a template.
-        return InstantiateClass(Loc, Rec, Pattern,
-                                getTemplateInstantiationArgs(Rec),
-                                TSK_ImplicitInstantiation,
-                                /*Complain=*/diag != 0);
+        if (Rec->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+          return InstantiateClass(Loc, Rec, Pattern,
+                                  getTemplateInstantiationArgs(Rec),
+                                  TSK_ImplicitInstantiation,
+                                  /*Complain=*/diag != 0);
       }
     }
   }
index 438c41159ad76a24a09eda5ecc6f9e4809472d75..0ba95d875ad7d60a7dc51f23952b779f9e5d27cc 100644 (file)
@@ -55,7 +55,7 @@ struct X0 { // expected-note 2{{here}}
     t = 17;
   }
   
-  struct Inner : public T { };
+  struct Inner : public T { }; // expected-note 3{{here}}
   
   template<typename U>
   struct InnerTemplate : public T { };
@@ -115,6 +115,8 @@ namespace N0 {
   template<> long X0<long>::member = 17;
 
   template<> float X0<float>::member;
+  
+  template<> double X0<double>::member;
 }
 
 NonDefaultConstructible &get_static_member() {
@@ -125,14 +127,51 @@ template<> int N0::X0<int>::member;  // expected-error{{originally}}
 
 template<> float N0::X0<float>::member = 3.14f;
 
-#if 0
-// FIXME: update the remainder of this test to check for scopes properly.
+namespace N1 {
+  template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+}
+
 //    -- member class of a class template
+namespace N0 {
+  
+  template<>
+  struct X0<void*>::Inner { };
+
+  template<>
+  struct X0<int>::Inner { };
+
+  template<>
+  struct X0<unsigned>::Inner;
+
+  template<>
+  struct X0<float>::Inner;
+
+  template<>
+  struct X0<double>::Inner; // expected-note{{forward declaration}}
+}
+
 template<>
-struct X0<void*>::Inner { };
+struct N0::X0<long>::Inner { }; // expected-error{{originally}}
 
-X0<void*>::Inner inner0;
+template<>
+struct N0::X0<float>::Inner { };
+
+namespace N1 {
+  template<>
+  struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}}
 
+  template<>
+  struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}}
+};
+
+N0::X0<void*>::Inner inner0;
+N0::X0<int>::Inner inner1;
+N0::X0<long>::Inner inner2;
+N0::X0<float>::Inner inner3;
+N0::X0<double>::Inner inner4; // expected-error{{incomplete}}
+
+#if 0
+// FIXME: update the remainder of this test to check for scopes properly.
 //    -- member class template of a class template
 template<>
 template<>
index 7f1ff3dc316c4aed81782888089f85336c99a61d..9309b72a556e39caa19c21c61ba001931d0886dd 100644 (file)
@@ -7,9 +7,12 @@ template  x;            // expected-error {{C++ requires a type specifier for al
 export template x;      // expected-error {{expected '<' after 'template'}}
 export template<class T> class x0; // expected-note {{exported templates are unsupported}}
 template < ;            // expected-error {{parse error}} expected-error {{declaration does not declare anything}}
-template <template X> struct Err1; // expected-error {{expected '<' after 'template'}}
-template <template <typename> > struct Err2;       // expected-error {{expected 'class' before '>'}}
-template <template <typename> Foo> struct Err3;    // expected-error {{expected 'class' before 'Foo'}}
+template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
+// expected-error{{extraneous}}
+template <template <typename> > struct Err2;       // expected-error {{expected 'class' before '>'}} \
+// expected-error{{extraneous}}
+template <template <typename> Foo> struct Err3;    // expected-error {{expected 'class' before 'Foo'}} \
+// expected-error{{extraneous}}
 
 // Template function declarations
 template <typename T> void foo();