]> granicus.if.org Git - clang/commitdiff
Type checking for specializations of member functions of class
authorDouglas Gregor <dgregor@apple.com>
Wed, 7 Oct 2009 22:35:40 +0000 (22:35 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 7 Oct 2009 22:35:40 +0000 (22:35 +0000)
templates. Previously, these weren't handled as specializations at
all. The AST for representing these as specializations is still a work
in progress.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
test/SemaTemplate/class-template-spec.cpp

index 6c8b631e391fcdc61d71d8bf77d1a4a6542fedde..a93955be77154e14f50b765c114da5413ffe8350 100644 (file)
@@ -922,8 +922,8 @@ def err_template_spec_unknown_kind : Error<
   "instantiation|instantiation}0 for a class template, function template, or "
   "a member function, static data member, or member class of a class template">;
 def note_specialized_entity : Note<
-  "explicit %select{<error>|<error>|specialized|instantiated|instantiated}0 is "
-  "here">;
+  "explicitly %select{<error>|<error>|specialized|instantiated|instantiated}0 "
+  "declaration is here">;
 def err_template_spec_decl_function_scope : Error<
   "explicit %select{<error>|<error>|specialization|instantiation|"
   "instantiation}0 of %1 in function scope">;
@@ -946,6 +946,10 @@ def err_template_spec_redecl_global_scope : Error<
   "%select{class template|class template partial|function template|member "
   "function|static data member|member class}0 specialization of %1 must occur "
   "at global scope">;
+def err_function_spec_not_instantiated : Error<
+  "specialization of member function %q0 does not specialize an instantiated "
+  "member function">;
+def note_specialized_decl : Note<"attempt to specialize declaration here">;
 
 // C++ class template specializations and out-of-line definitions
 def err_template_spec_needs_header : Error<
index 2056d39132e215f0827355e02d6c97ee6b17f2d9..6142eacd57feaf0e43ba6f40eafbdb58bc86e5a0 100644 (file)
@@ -2433,7 +2433,8 @@ public:
   MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
                                           const CXXScopeSpec &SS,
                                           TemplateParameterList **ParamLists,
-                                          unsigned NumParamLists);
+                                          unsigned NumParamLists,
+                                          bool &IsExplicitSpecialization);
 
   DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
                                 SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -2518,6 +2519,8 @@ public:
                                            unsigned NumExplicitTemplateArgs,
                                            SourceLocation RAngleLoc,
                                            NamedDecl *&PrevDecl);
+  bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD, 
+                                         NamedDecl *&PrevDecl);
     
   virtual DeclResult
   ActOnExplicitInstantiation(Scope *S,
index a1fcf89c546ae7e05ffe6ba30ba743a41e978d40..4743720c62f980c0d2a2b5c42697bc76a2930926 100644 (file)
@@ -2235,12 +2235,15 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
 
   // Match up the template parameter lists with the scope specifier, then
   // determine whether we have a template or a template specialization.
+  // FIXME: Actually record when this is an explicit specialization!
+  bool isExplicitSpecialization = false;
   if (TemplateParameterList *TemplateParams
-      = MatchTemplateParametersToScopeSpecifier(
+        = MatchTemplateParametersToScopeSpecifier(
                                   D.getDeclSpec().getSourceRange().getBegin(),
-                                                D.getCXXScopeSpec(),
+                                                  D.getCXXScopeSpec(),
                         (TemplateParameterList**)TemplateParamLists.get(),
-                                                 TemplateParamLists.size())) {
+                                                   TemplateParamLists.size(),
+                                                  isExplicitSpecialization)) {
     if (TemplateParams->size() > 0) {
       // There is no such thing as a variable template.
       Diag(D.getIdentifierLoc(), diag::err_template_variable)
@@ -2256,6 +2259,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
         << II
         << SourceRange(TemplateParams->getTemplateLoc(),
                        TemplateParams->getRAngleLoc());
+      
+      isExplicitSpecialization = true;
     }
   }
 
@@ -2660,13 +2665,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   // Match up the template parameter lists with the scope specifier, then
   // determine whether we have a template or a template specialization.
   FunctionTemplateDecl *FunctionTemplate = 0;
+  bool isExplicitSpecialization = false;
   bool isFunctionTemplateSpecialization = false;
   if (TemplateParameterList *TemplateParams
         = MatchTemplateParametersToScopeSpecifier(
                                   D.getDeclSpec().getSourceRange().getBegin(),
                                   D.getCXXScopeSpec(),
                            (TemplateParameterList**)TemplateParamLists.get(),
-                                                  TemplateParamLists.size())) {
+                                                  TemplateParamLists.size(),
+                                                  isExplicitSpecialization)) {
     if (TemplateParams->size() > 0) {
       // This is a function template
 
@@ -2847,7 +2854,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     RAngleLoc = TemplateId->RAngleLoc;
     
     if (FunctionTemplate) {
-      // FIXME: Diagnostic function template with explicit template
+      // FIXME: Diagnose function template with explicit template
       // arguments.
       HasExplicitTemplateArgs = false;
     } else if (!isFunctionTemplateSpecialization && 
@@ -2865,13 +2872,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     }
   }
   
-  if (isFunctionTemplateSpecialization &&
-      CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
-                                          LAngleLoc, TemplateArgs.data(),
-                                          TemplateArgs.size(), RAngleLoc,
-                                          PrevDecl))
+  if (isFunctionTemplateSpecialization) {
+      if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
+                                              LAngleLoc, TemplateArgs.data(),
+                                              TemplateArgs.size(), RAngleLoc,
+                                              PrevDecl))
+        NewFD->setInvalidDecl();
+  } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
+             CheckMemberFunctionSpecialization(cast<CXXMethodDecl>(NewFD),
+                                               PrevDecl))
     NewFD->setInvalidDecl();
-  
+           
   // Perform semantic checking on the function declaration.
   bool OverloadableAttrRequired = false; // FIXME: HACK!
   CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
@@ -4161,11 +4172,14 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
   OwnedDecl = false;
   TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
 
+  // FIXME: Check explicit specializations more carefully.
+  bool isExplicitSpecialization = false;
   if (TUK != TUK_Reference) {
     if (TemplateParameterList *TemplateParams
           = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
                         (TemplateParameterList**)TemplateParameterLists.get(),
-                                              TemplateParameterLists.size())) {
+                                              TemplateParameterLists.size(),
+                                                    isExplicitSpecialization)) {
       if (TemplateParams->size() > 0) {
         // This is a declaration or definition of a class template (which may
         // be a member of another template).
index 6792b28d1c830229052f9c858e2b13ab19300fb5..f3cd2e41fbd3f63f35238d27a1b8427b5a25839b 100644 (file)
@@ -933,6 +933,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
 ///
 /// \param NumParamLists the number of template parameter lists in ParamLists.
 ///
+/// \param IsExplicitSpecialization will be set true if the entity being
+/// declared is an explicit specialization, false otherwise.
+///
 /// \returns the template parameter list, if any, that corresponds to the
 /// name that is preceded by the scope specifier @p SS. This template
 /// parameter list may be have template parameters (if we're declaring a
@@ -943,7 +946,10 @@ TemplateParameterList *
 Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
                                               const CXXScopeSpec &SS,
                                           TemplateParameterList **ParamLists,
-                                              unsigned NumParamLists) {
+                                              unsigned NumParamLists,
+                                              bool &IsExplicitSpecialization) {
+  IsExplicitSpecialization = false;
+  
   // Find the template-ids that occur within the nested-name-specifier. These
   // template-ids will match up with the template parameter lists.
   llvm::SmallVector<const TemplateSpecializationType *, 4>
@@ -1000,6 +1006,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
           << SS.getRange()
           << CodeModificationHint::CreateInsertion(FirstTemplateLoc,
                                                    "template<> ");
+        IsExplicitSpecialization = true;
       }
       return 0;
     }
@@ -1031,6 +1038,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
            diag::err_template_param_list_matches_nontemplate)
         << TemplateId
         << ParamLists[Idx]->getSourceRange();
+    else
+      IsExplicitSpecialization = true;
   }
 
   // If there were at least as many template-ids as there were template
@@ -2399,11 +2408,14 @@ static bool CheckTemplateSpecializationScope(Sema &S,
   // Keep these "kind" numbers in sync with the %select statements in the
   // various diagnostics emitted by this routine.
   int EntityKind = 0;
-  if (isa<ClassTemplateDecl>(Specialized))
+  bool isTemplateSpecialization = false;
+  if (isa<ClassTemplateDecl>(Specialized)) {
     EntityKind = IsPartialSpecialization? 1 : 0;
-  else if (isa<FunctionTemplateDecl>(Specialized))
+    isTemplateSpecialization = true;
+  } else if (isa<FunctionTemplateDecl>(Specialized)) {
     EntityKind = 2;
-  else if (isa<CXXMethodDecl>(Specialized))
+    isTemplateSpecialization = true;
+  } else if (isa<CXXMethodDecl>(Specialized))
     EntityKind = 3;
   else if (isa<VarDecl>(Specialized))
     EntityKind = 4;
@@ -2464,7 +2476,8 @@ static bool CheckTemplateSpecializationScope(Sema &S,
           << EntityKind << Specialized
           << cast<NamedDecl>(SpecializedContext);
         
-        S.Diag(Specialized->getLocation(), diag::note_template_decl_here);
+        S.Diag(Specialized->getLocation(), diag::note_specialized_entity) 
+          << TSK;
         ComplainedAboutScope = true;
       }
     }
@@ -2492,7 +2505,7 @@ static bool CheckTemplateSpecializationScope(Sema &S,
         << EntityKind << Specialized
         << cast<NamedDecl>(SpecializedContext);
   
-    S.Diag(Specialized->getLocation(), diag::note_template_decl_here);
+    S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
   }
   
   // FIXME: check for specialization-after-instantiation errors and such.
@@ -2640,6 +2653,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
   ClassTemplateDecl *ClassTemplate
     = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
 
+  bool isExplicitSpecialization = false;
   bool isPartialSpecialization = false;
 
   // Check the validity of the template headers that introduce this
@@ -2649,7 +2663,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
   TemplateParameterList *TemplateParams
     = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
                         (TemplateParameterList**)TemplateParameterLists.get(),
-                                              TemplateParameterLists.size());
+                                              TemplateParameterLists.size(),
+                                              isExplicitSpecialization);
   if (TemplateParams && TemplateParams->size() > 0) {
     isPartialSpecialization = true;
 
@@ -2684,9 +2699,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
         }
       }
     }
-  } else if (!TemplateParams && TUK != TUK_Friend)
+  } else if (!TemplateParams && TUK != TUK_Friend) {
     Diag(KWLoc, diag::err_template_spec_needs_header)
       << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+    isExplicitSpecialization = true;
+  }
 
   // Check that the specialization uses the same tag kind as the
   // original template.
@@ -3101,6 +3118,70 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
   return false;
 }
 
+/// \brief Perform semantic analysis for the given member function
+/// specialization.
+///
+/// This routine performs all of the semantic analysis required for an 
+/// explicit member function specialization. On successful completion,
+/// the function declaration \p FD will become a member function
+/// specialization.
+///
+/// \param FD the function declaration, which will be updated to become a
+/// function template specialization.
+///
+/// \param PrevDecl the set of declarations, one of which may be specialized
+/// by this function specialization.
+bool 
+Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
+                                        NamedDecl *&PrevDecl) {
+  // Try to find the member function we are instantiating.
+  CXXMethodDecl *Instantiation = 0;
+  for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
+      if (Context.hasSameType(FD->getType(), Method->getType())) {
+        Instantiation = Method;
+        break;
+      }
+    }
+  }
+  
+  if (!Instantiation) {
+    // There is no previous declaration that matches. Since member function
+    // specializations are always out-of-line, the caller will complain about
+    // this mismatch later.
+    return false;
+  }
+  
+  // FIXME: Check if the prior declaration has a point of instantiation.
+  // If so, we have run afoul of C++ [temp.expl.spec]p6.
+  
+  // Make sure that this is a specialization of a member function.
+  FunctionDecl *FunctionInTemplate
+    = Instantiation->getInstantiatedFromMemberFunction();
+  if (!FunctionInTemplate) {
+    Diag(FD->getLocation(), diag::err_function_spec_not_instantiated)
+      << FD;
+    Diag(Instantiation->getLocation(), diag::note_specialized_decl);
+    return true;
+  }
+  
+  // Check the scope of this explicit specialization.
+  if (CheckTemplateSpecializationScope(*this, 
+                                       FunctionInTemplate,
+                                       Instantiation, FD->getLocation(), 
+                                       false, TSK_ExplicitSpecialization))
+    return true;
+  
+  // FIXME: Mark the new declaration as a member function specialization.
+  // We may also want to mark the original instantiation as having been
+  // explicitly specialized.
+  
+  // Save the caller the trouble of having to figure out which declaration
+  // this specialization matches.
+  PrevDecl = Instantiation;
+  return false;
+}
+
 // Explicit instantiation of a class template specialization
 // FIXME: Implement extern template semantics
 Sema::DeclResult
index 77df60a25d3447268921b47c57bd55f1874f36ca..553d62c9e5e8a1d34919ed5a1939af2f22d1aa4d 100644 (file)
@@ -51,7 +51,7 @@ template<typename T>
 struct X0 { // expected-note 2{{here}}
   static T member;
   
-  void f1(T t) {
+  void f1(T t) { // expected-note{{explicitly specialized declaration is here}}
     t = 17;
   }
   
@@ -85,17 +85,21 @@ namespace N0 {
   template<> struct X0<volatile void>;
 }
 
-template<> struct N0::X0<volatile void> { };
+template<> struct N0::X0<volatile void> { 
+  void f1(void *);
+};
 
 //     -- member function of a class template
-// FIXME: this should complain about the scope of f1, but we don't seem
-// to recognize it as a specialization. Hrm?
-template<> void N0::X0<void*>::f1(void *) { }
+template<> void N0::X0<void*>::f1(void *) { } // expected-error{{member function specialization}}
 
 void test_spec(N0::X0<void*> xvp, void *vp) {
   xvp.f1(vp);
 }
 
+namespace N0 {
+  template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}}
+}
+
 #if 0
 // FIXME: update the remainder of this test to check for scopes properly.
 //     -- static data member of a class template
index e4d917f7756d5f2a9925e87c161e930934322ec1..05ddb05325971f3826226b7c9a9bab8982661111 100644 (file)
@@ -1,5 +1,6 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-template<typename T, typename U = int> struct A; // expected-note 2{{template is declared here}}
+template<typename T, typename U = int> struct A; // expected-note {{template is declared here}} \
+                                                 // expected-note{{explicitly specialized}}
 
 template<> struct A<double, double>; // expected-note{{forward declaration}}
 
@@ -74,7 +75,7 @@ struct A<double> { }; // expected-error{{template specialization requires 'templ
 template<> struct ::A<double>;
 
 namespace N {
-  template<typename T> struct B; // expected-note 2{{template is declared here}}
+  template<typename T> struct B; // expected-note 2{{explicitly specialized}}
 
   template<> struct ::N::B<char>; // okay
   template<> struct ::N::B<short>; // okay