]> granicus.if.org Git - clang/commitdiff
Implement support for out-of-line definitions of the class members of class
authorDouglas Gregor <dgregor@apple.com>
Wed, 22 Jul 2009 23:48:44 +0000 (23:48 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 22 Jul 2009 23:48:44 +0000 (23:48 +0000)
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.

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

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 [new file with mode: 0644]
test/Parser/cxx-template-decl.cpp

index df62573e8cda08b0c4494144127c011b64753fec..76d069fd8a2368936010c409f4db0685dd946d67 100644 (file)
@@ -733,10 +733,11 @@ def note_template_param_prev_default_arg : Note<
   "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 "
index 23c5428ef6876dfdd2ddc14586070be9c9567afc..92f38ede895588b2631b48acd890f5e5994bf0fe 100644 (file)
@@ -422,6 +422,18 @@ public:
                              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();
   }
   
index 930d58dd26247c694e7475a49dc428160596568c..f28ffe350940219896b2d2f1d2957f9e23e76d3b 100644 (file)
@@ -673,15 +673,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
                                  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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
 
     // 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).
index 57a09fbc737fc0ead2e883b6fce035ea4ede39a7..df7c22cf265270318b7222d52b02e8e79a8a6256 100644 (file)
@@ -96,9 +96,15 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
     // 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 @@ Parser::ParseSingleDeclarationAfterTemplate(
 /// 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 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
   // 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 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
   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 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
   SourceLocation LAngleLoc, RAngleLoc;
   {
     ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
-    if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
-                                RAngleLoc)) {
+    if(ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
+                               RAngleLoc)) {
       return DeclPtrTy();
     }
   }
index 7daf3f90a86e9aa0e790b2cbe3b6b3c65d46dec2..78d64b53c099e02bca47c8fb8f4ce4483623f4f2 100644 (file)
@@ -522,6 +522,7 @@ public:
                              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,
index cf73725e7f36536579d6604feed19114d188160b..be1a1103b3d459a0a468608b25e2bf6a58023f26 100644 (file)
@@ -213,7 +213,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
   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.
index 2e280f58cb5b49646739b4f0b4833d9a0b0af853..d9c1224b435fcdc59de0699b4633470a77eebb86 100644 (file)
@@ -1866,14 +1866,14 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     } 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 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                                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 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
   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;
index 5f772bc22c06f5fd6ee7dc48a7b031fa68b6e214..981b8508c565e0274cd57bfbdb139f02c3e8cbee 100644 (file)
@@ -2895,7 +2895,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
 
   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;
 
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
new file mode 100644 (file)
index 0000000..9bafacc
--- /dev/null
@@ -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
index b7117cd8d62010a85b17a5778f4ae6d1b3844653..5f49fb15d7cfd4f23b148791e96bdf0d408b7521 100644 (file)
@@ -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 '>'}}