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

Douglas Gregor dgregor at apple.com
Wed Oct 7 15:35:40 PDT 2009


Author: dgregor
Date: Wed Oct  7 17:35:40 2009
New Revision: 83498

URL: http://llvm.org/viewvc/llvm-project?rev=83498&view=rev
Log:
Type checking for specializations of member functions of class
templates. Previously, these weren't handled as specializations at
all. The AST for representing these as specializations is still a work
in progress.

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

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Oct  7 17:35:40 2009
@@ -922,8 +922,8 @@
   "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 @@
   "%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<

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=83498&r1=83497&r2=83498&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct  7 17:35:40 2009
@@ -2433,7 +2433,8 @@
   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 @@
                                            unsigned NumExplicitTemplateArgs,
                                            SourceLocation RAngleLoc,
                                            NamedDecl *&PrevDecl);
+  bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD, 
+                                         NamedDecl *&PrevDecl);
     
   virtual DeclResult
   ActOnExplicitInstantiation(Scope *S,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Oct  7 17:35:40 2009
@@ -2235,12 +2235,15 @@
 
   // 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 @@
         << II
         << SourceRange(TemplateParams->getTemplateLoc(),
                        TemplateParams->getRAngleLoc());
+      
+      isExplicitSpecialization = true;
     }
   }
 
@@ -2660,13 +2665,15 @@
   // 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 @@
     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 @@
     }
   }
   
-  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 @@
   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).

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Oct  7 17:35:40 2009
@@ -933,6 +933,9 @@
 ///
 /// \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 @@
 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 @@
           << SS.getRange()
           << CodeModificationHint::CreateInsertion(FirstTemplateLoc,
                                                    "template<> ");
+        IsExplicitSpecialization = true;
       }
       return 0;
     }
@@ -1031,6 +1038,8 @@
            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 @@
   // 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 @@
           << 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 @@
         << 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 @@
   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 @@
   TemplateParameterList *TemplateParams
     = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
                         (TemplateParameterList**)TemplateParameterLists.get(),
-                                              TemplateParameterLists.size());
+                                              TemplateParameterLists.size(),
+                                              isExplicitSpecialization);
   if (TemplateParams && TemplateParams->size() > 0) {
     isPartialSpecialization = true;
 
@@ -2684,9 +2699,11 @@
         }
       }
     }
-  } 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 @@
   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

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=83498&r1=83497&r2=83498&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 Wed Oct  7 17:35:40 2009
@@ -51,7 +51,7 @@
 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 @@
   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

Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=83498&r1=83497&r2=83498&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Wed Oct  7 17:35:40 2009
@@ -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 @@
 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





More information about the cfe-commits mailing list