[cfe-commits] r76820 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Action.h lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp test/Parser/cxx-template-decl.cpp

Douglas Gregor dgregor at apple.com
Wed Jul 22 16:48:47 PDT 2009


Author: dgregor
Date: Wed Jul 22 18:48:44 2009
New Revision: 76820

URL: http://llvm.org/viewvc/llvm-project?rev=76820&view=rev
Log:
Implement support for out-of-line definitions of the class members of class
templates, e.g.,

  template<typename T>
  struct Outer {
    struct Inner;
  };

  template<typename T>
  struct Outer<T>::Inner {
    // ...
  };

Implementing this feature required some extensions to ActOnTag, which
now takes a set of template parameter lists, and is the precursor to
removing the ActOnClassTemplate function from the parser Action
interface. The reason for this approach is simple: the parser cannot
tell the difference between a class template definition and the
definition of a member of a class template; both have template
parameter lists, and semantic analysis determines what that template
parameter list means.

There is still some cleanup to do with ActOnTag and
ActOnClassTemplate. This commit provides the basic functionality we
need, however.


Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/Parser/cxx-template-decl.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jul 22 18:48:44 2009
@@ -733,10 +733,11 @@
   "previous default template argument defined here">;
 def err_template_param_default_arg_missing : Error<
   "template parameter missing a default argument">;
-
+  
 def err_template_variable : Error<"variable %0 declared as a template">;
 def err_template_variable_noparams : Error<
   "extraneous 'template<>' in declaration of variable %0">;
+
 // C++ Template Argument Lists
 def err_template_arg_list_different_arity : Error<
   "%select{too few|too many}0 template arguments for "

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=76820&r1=76819&r2=76820&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Jul 22 18:48:44 2009
@@ -422,6 +422,18 @@
                              bool &OwnedDecl) {
     // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
     // is (struct/union/enum/class).
+    return ActOnTag(S, TagSpec, TK, KWLoc, SS, Name, NameLoc, Attr, AS,
+                    MultiTemplateParamsArg(*this, 0, 0), OwnedDecl);
+  }
+
+  virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+                             SourceLocation KWLoc, const CXXScopeSpec &SS,
+                             IdentifierInfo *Name, SourceLocation NameLoc,
+                             AttributeList *Attr, AccessSpecifier AS,
+                             MultiTemplateParamsArg TemplateParameterLists,
+                             bool &OwnedDecl) {
+    // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
+    // is (struct/union/enum/class).
     return DeclPtrTy();
   }
   

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=76820&r1=76819&r2=76820&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed Jul 22 18:48:44 2009
@@ -673,15 +673,6 @@
                                  TemplateParams? TemplateParams->size() : 0));
     }
     TemplateId->Destroy();
-  } else if (TemplateParams && TK != Action::TK_Reference) {
-    // Class template declaration or definition.
-    TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK, 
-                                                 StartLoc, SS, Name, NameLoc, 
-                                                 Attr,
-                       Action::MultiTemplateParamsArg(Actions, 
-                                                      &(*TemplateParams)[0],
-                                                      TemplateParams->size()),
-                                                 AS);
   } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
              TK == Action::TK_Declaration) {
     // Explicit instantiation of a member of a class template
@@ -702,7 +693,11 @@
 
     // Declaration or definition of a class type
     TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, 
-                                       Name, NameLoc, Attr, AS, Owned);
+                                       Name, NameLoc, Attr, AS,
+                                  Action::MultiTemplateParamsArg(Actions, 
+                                    TemplateParams? &(*TemplateParams)[0] : 0,
+                                    TemplateParams? TemplateParams->size() : 0),
+                                       Owned);
   }
 
   // Parse the optional base clause (C++ only).

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=76820&r1=76819&r2=76820&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Wed Jul 22 18:48:44 2009
@@ -96,9 +96,15 @@
     // Parse the '<' template-parameter-list '>'
     SourceLocation LAngleLoc, RAngleLoc;
     TemplateParameterList TemplateParams;
-    ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, 
-                            RAngleLoc);
-
+    if (ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, 
+                                RAngleLoc)) {
+      // Skip until the semi-colon or a }.
+      SkipUntil(tok::r_brace, true, true);
+      if (Tok.is(tok::semi))
+        ConsumeToken();
+      return DeclPtrTy();      
+    }
+      
     if (!TemplateParams.empty())
       isSpecialiation = false;
 
@@ -219,6 +225,8 @@
 /// The template parameter we parse will be added to this list. LAngleLoc and
 /// RAngleLoc will receive the positions of the '<' and '>', respectively, 
 /// that enclose this template parameter list.
+///
+/// \returns true if an error occurred, false otherwise.
 bool Parser::ParseTemplateParameters(unsigned Depth,
                                      TemplateParameterList &TemplateParams,
                                      SourceLocation &LAngleLoc,
@@ -226,7 +234,7 @@
   // Get the template parameter list.
   if(!Tok.is(tok::less)) {
     Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
-    return false;
+    return true;
   }
   LAngleLoc = ConsumeToken();
   
@@ -236,11 +244,11 @@
   else if(ParseTemplateParameterList(Depth, TemplateParams)) {
     if(!Tok.is(tok::greater)) {
       Diag(Tok.getLocation(), diag::err_expected_greater);
-      return false;
+      return true;
     }
     RAngleLoc = ConsumeToken();
   }
-  return true;
+  return false;
 }
 
 /// ParseTemplateParameterList - Parse a template parameter list. If
@@ -392,8 +400,8 @@
   SourceLocation LAngleLoc, RAngleLoc;
   {
     ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
-    if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
-                                RAngleLoc)) {
+    if(ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
+                               RAngleLoc)) {
       return DeclPtrTy();
     }
   }

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jul 22 18:48:44 2009
@@ -522,6 +522,7 @@
                              SourceLocation KWLoc, const CXXScopeSpec &SS,
                              IdentifierInfo *Name, SourceLocation NameLoc,
                              AttributeList *Attr, AccessSpecifier AS,
+                             MultiTemplateParamsArg TemplateParameterLists,
                              bool &OwnedDecl);
   
   virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Jul 22 18:48:44 2009
@@ -213,7 +213,7 @@
   if (!SS.isSet() || SS.isInvalid())
     return false;
   
-  DeclContext *DC = computeDeclContext(SS);
+  DeclContext *DC = computeDeclContext(SS, true);
   if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
     // If we're currently defining this type, then lookup into the
     // type is okay: don't complain that it isn't complete yet.

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jul 22 18:48:44 2009
@@ -1866,14 +1866,14 @@
     } else {
       // There is an extraneous 'template<>' for this variable. Complain
       // about it, but allow the declaration of the variable.
-      Diag(TemplateParams->getTemplateLoc(), diag::err_template_variable)
+      Diag(TemplateParams->getTemplateLoc(), 
+           diag::err_template_variable_noparams)
         << II
         << SourceRange(TemplateParams->getTemplateLoc(),
                        TemplateParams->getRAngleLoc());          
     }
   }        
   
-  // The variable can not 
   NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), 
                           II, R, SC, 
                           // FIXME: Move to DeclGroup...
@@ -3522,6 +3522,7 @@
                                SourceLocation KWLoc, const CXXScopeSpec &SS,
                                IdentifierInfo *Name, SourceLocation NameLoc,
                                AttributeList *Attr, AccessSpecifier AS,
+                               MultiTemplateParamsArg TemplateParameterLists,
                                bool &OwnedDecl) {
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TK == TK_Definition) &&
@@ -3537,6 +3538,28 @@
   case DeclSpec::TST_enum:   Kind = TagDecl::TK_enum; break;
   }
   
+  if (TK != TK_Reference) {
+    if (TemplateParameterList *TemplateParams
+          = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
+                        (TemplateParameterList**)TemplateParameterLists.get(),
+                                              TemplateParameterLists.size())) {
+      if (TemplateParams->size() > 0) {
+        // This is a declaration or definition of a class template (which may
+        // be a member of another template).
+        OwnedDecl = false;
+        DeclResult Result = ActOnClassTemplate(S, TagSpec, TK, KWLoc,
+                                               SS, Name, NameLoc, Attr,
+                                               move(TemplateParameterLists),
+                                               AS);
+        return Result.get();
+      } else {
+        // FIXME: diagnose the extraneous 'template<>', once we recover
+        // slightly better in ParseTemplate.cpp from bogus template
+        // parameters.
+      }
+    }        
+  }  
+  
   DeclContext *SearchDC = CurContext;
   DeclContext *DC = CurContext;
   NamedDecl *PrevDecl = 0;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jul 22 18:48:44 2009
@@ -2895,7 +2895,8 @@
 
   bool Owned = false;
   DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference,
-                            KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned);
+                            KWLoc, SS, Name, NameLoc, Attr, AS_none,
+                            MultiTemplateParamsArg(*this, 0, 0), Owned);
   if (!TagD)
     return true;
 

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp?rev=76820&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp Wed Jul 22 18:48:44 2009
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct X0 {
+  struct Inner;
+};
+
+template<typename T, typename U>
+struct X0<T, U>::Inner {
+  T x;
+  U y;
+  
+  void f() { x = y; } // expected-error{{incompatible}}
+};
+
+
+void test(int i, float f) {
+  X0<int, float>::Inner inner;
+  inner.x = 5;
+  inner.y = 3.4;
+  inner.f();
+  
+  X0<int*, float *>::Inner inner2;
+  inner2.x = &i;
+  inner2.y = &f;
+  inner2.f(); // expected-note{{instantiation}}
+}
\ No newline at end of file

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=76820&r1=76819&r2=76820&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Wed Jul 22 18:48:44 2009
@@ -3,12 +3,8 @@
 // Errors
 export class foo { };   // expected-error {{expected template}}
 template  x;            // expected-error {{C++ requires a type specifier for all declarations}}
-export template x;      // expected-error {{expected '<' after 'template'}} \
-                        // expected-note {{exported templates are unsupported}} \
-// expected-error {{C++ requires a type specifier for all declarations}} \
-// expected-error {{declared as a template}}
-// See Sema::ParsedFreeStandingDeclSpec about the double diagnostic. This is
-// because ParseNonTypeTemplateParameter starts parsing a DeclSpec.
+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 '>'}}





More information about the cfe-commits mailing list