[cfe-commits] r83547 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Thu Oct 8 08:14:34 PDT 2009


Author: dgregor
Date: Thu Oct  8 10:14:33 2009
New Revision: 83547

URL: http://llvm.org/viewvc/llvm-project?rev=83547&view=rev
Log:
Improve checking for specializations of member classes of class
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.


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

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Oct  8 10:14:33 2009
@@ -391,8 +391,9 @@
   /// 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 @@
   /// 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 @@
     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);
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Oct  8 10:14:33 2009
@@ -846,6 +846,8 @@
 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<

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Oct  8 10:14:33 2009
@@ -437,6 +437,53 @@
   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);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Oct  8 10:14:33 2009
@@ -4161,11 +4161,14 @@
         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 @@
     }
   }
 
+  // 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();
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Oct  8 10:14:33 2009
@@ -2360,15 +2360,13 @@
   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 @@
   // 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

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Oct  8 10:14:33 2009
@@ -972,20 +972,30 @@
                               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 @@
       
       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(),

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Oct  8 10:14:33 2009
@@ -454,7 +454,7 @@
   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.

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu Oct  8 10:14:33 2009
@@ -1849,10 +1849,11 @@
                  = 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);
       }
     }
   }

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp Thu Oct  8 10:14:33 2009
@@ -55,7 +55,7 @@
     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 @@
   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<> 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<>

Modified: cfe/trunk/test/Parser/cxx-template-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-decl.cpp?rev=83547&r1=83546&r2=83547&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Thu Oct  8 10:14:33 2009
@@ -7,9 +7,12 @@
 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();





More information about the cfe-commits mailing list