[cfe-commits] r80003 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/nested-template.cpp

Douglas Gregor dgregor at apple.com
Tue Aug 25 10:23:05 PDT 2009


Author: dgregor
Date: Tue Aug 25 12:23:04 2009
New Revision: 80003

URL: http://llvm.org/viewvc/llvm-project?rev=80003&view=rev
Log:
Implement out-of-line definitions of nested class templates. Most of
the logic is there for out-of-line definitions with multiple levels of
nested templates, but this is still a work-in-progress: we're having
trouble determining when we should look into a dependent
nested-name-specifier. 

Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/nested-template.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Aug 25 12:23:04 2009
@@ -2258,7 +2258,7 @@
                                 SourceLocation KWLoc, const CXXScopeSpec &SS,
                                 IdentifierInfo *Name, SourceLocation NameLoc,
                                 AttributeList *Attr,
-                                MultiTemplateParamsArg TemplateParameterLists,
+                                TemplateParameterList *TemplateParams,
                                 AccessSpecifier AS);
 
   QualType CheckTemplateIdType(TemplateName Template,
@@ -2378,8 +2378,7 @@
                                       SourceLocation TemplateArgLoc
                                        = SourceLocation());
   
-  bool CheckTemplateDeclScope(Scope *S, 
-                              MultiTemplateParamsArg &TemplateParameterLists);
+  bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
 
   /// \brief Called when the parser has parsed a C++ typename
   /// specifier, e.g., "typename T::type".

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 25 12:23:04 2009
@@ -2106,11 +2106,6 @@
     }
   }
         
-  // Check that we can declare a template here.
-  if (TemplateParamLists.size() && 
-      CheckTemplateDeclScope(S, TemplateParamLists))
-    return 0;
-  
   // Match up the template parameter lists with the scope specifier, then
   // determine whether we have a template or a template specialization.
   if (TemplateParameterList *TemplateParams
@@ -2391,11 +2386,6 @@
     D.setInvalidType();
   }
 
-  // Check that we can declare a template here.
-  if (TemplateParamLists.size() && 
-      CheckTemplateDeclScope(S, TemplateParamLists))
-    return 0;
-  
   bool isVirtualOkay = false;
   FunctionDecl *NewFD;
   if (isFriend) {
@@ -2515,6 +2505,11 @@
                                                   TemplateParamLists.size())) {
     if (TemplateParams->size() > 0) {
       // This is a function template
+      
+      // Check that we can declare a template here.
+      if (CheckTemplateDeclScope(S, TemplateParams))
+        return 0;
+      
       FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
                                                       NewFD->getLocation(),
                                                       Name, TemplateParams,
@@ -3960,8 +3955,9 @@
         OwnedDecl = false;
         DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
                                                SS, Name, NameLoc, Attr,
-                                               move(TemplateParameterLists),
+                                               TemplateParams,
                                                AS);
+        TemplateParameterLists.release();
         return Result.get();
       } else {
         // FIXME: diagnose the extraneous 'template<>', once we recover

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Aug 25 12:23:04 2009
@@ -444,14 +444,15 @@
                          SourceLocation KWLoc, const CXXScopeSpec &SS,
                          IdentifierInfo *Name, SourceLocation NameLoc,
                          AttributeList *Attr,
-                         MultiTemplateParamsArg TemplateParameterLists,
+                         TemplateParameterList *TemplateParams,
                          AccessSpecifier AS) {
-  assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
+  assert(TemplateParams && TemplateParams->size() > 0 && 
+         "No template parameters");
   assert(TUK != TUK_Reference && "Can only declare or define class templates");
   bool Invalid = false;
 
   // Check that we can declare a template here.
-  if (CheckTemplateDeclScope(S, TemplateParameterLists))
+  if (CheckTemplateDeclScope(S, TemplateParams))
     return true;
 
   TagDecl::TagKind Kind;
@@ -469,27 +470,30 @@
   }
 
   // Find any previous declaration with this name.
-  LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
-                                           true);
+  DeclContext *SemanticContext;
+  LookupResult Previous;
+  if (SS.isNotEmpty() && !SS.isInvalid()) {
+    SemanticContext = computeDeclContext(SS, true);
+    if (!SemanticContext) {
+      // FIXME: Produce a reasonable diagnostic here
+      return true;
+    }
+    
+    Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName, 
+                                   true);
+  } else {
+    SemanticContext = CurContext;
+    Previous = LookupName(S, Name, LookupOrdinaryName, true);
+  }
+  
   assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
   NamedDecl *PrevDecl = 0;
   if (Previous.begin() != Previous.end())
     PrevDecl = *Previous.begin();
 
-  if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+  if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
     PrevDecl = 0;
   
-  DeclContext *SemanticContext = CurContext;
-  if (SS.isNotEmpty() && !SS.isInvalid()) {
-    SemanticContext = computeDeclContext(SS);
-
-    // FIXME: need to match up several levels of template parameter lists here.
-  }
-
-  // FIXME: member templates!
-  TemplateParameterList *TemplateParams 
-    = static_cast<TemplateParameterList *>(*TemplateParameterLists.release());
-
   // If there is a previous declaration with the same name, check
   // whether this is a valid redeclaration.
   ClassTemplateDecl *PrevClassTemplate 
@@ -2106,28 +2110,20 @@
 /// If the template declaration is valid in this scope, returns
 /// false. Otherwise, issues a diagnostic and returns true.
 bool 
-Sema::CheckTemplateDeclScope(Scope *S, 
-                             MultiTemplateParamsArg &TemplateParameterLists) {
-  assert(TemplateParameterLists.size() > 0 && "Not a template");
-
+Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
   // Find the nearest enclosing declaration scope.
   while ((S->getFlags() & Scope::DeclScope) == 0 ||
          (S->getFlags() & Scope::TemplateParamScope) != 0)
     S = S->getParent();
   
-  TemplateParameterList *TemplateParams = 
-    static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
-  SourceLocation TemplateLoc = TemplateParams->getTemplateLoc();
-  SourceRange TemplateRange 
-    = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc());
-
   // C++ [temp]p2:
   //   A template-declaration can appear only as a namespace scope or
   //   class scope declaration.
   DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
   if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
       cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
-    return Diag(TemplateLoc, diag::err_template_linkage) << TemplateRange;
+    return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) 
+             << TemplateParams->getSourceRange();
   
   while (Ctx && isa<LinkageSpecDecl>(Ctx))
     Ctx = Ctx->getParent();
@@ -2135,8 +2131,9 @@
   if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
     return false;
 
-  return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
-    << TemplateRange;
+  return Diag(TemplateParams->getTemplateLoc(), 
+              diag::err_template_outside_namespace_or_class_scope)
+    << TemplateParams->getSourceRange();
 }
 
 /// \brief Check whether a class template specialization or explicit
@@ -2369,57 +2366,47 @@
 
   // Check the validity of the template headers that introduce this
   // template.
-  // FIXME: Once we have member templates, we'll need to check
-  // C++ [temp.expl.spec]p17-18, where we could have multiple levels of
-  // template<> headers.
-  if (TemplateParameterLists.size() == 0)
-    Diag(KWLoc, diag::err_template_spec_needs_header)
-      << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
-  else {
-    TemplateParameterList *TemplateParams 
-      = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
-    if (TemplateParameterLists.size() > 1) {
-      Diag(TemplateParams->getTemplateLoc(),
-           diag::err_template_spec_extra_headers);
-      return true;
-    }
-
-    if (TemplateParams->size() > 0) {
-      isPartialSpecialization = true;
-
-      // C++ [temp.class.spec]p10:
-      //   The template parameter list of a specialization shall not
-      //   contain default template argument values.
-      for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
-        Decl *Param = TemplateParams->getParam(I);
-        if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
-          if (TTP->hasDefaultArgument()) {
-            Diag(TTP->getDefaultArgumentLoc(), 
-                 diag::err_default_arg_in_partial_spec);
-            TTP->setDefaultArgument(QualType(), SourceLocation(), false);
-          }
-        } else if (NonTypeTemplateParmDecl *NTTP
-                     = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-          if (Expr *DefArg = NTTP->getDefaultArgument()) {
-            Diag(NTTP->getDefaultArgumentLoc(), 
-                 diag::err_default_arg_in_partial_spec)
-              << DefArg->getSourceRange();
-            NTTP->setDefaultArgument(0);
-            DefArg->Destroy(Context);
-          }
-        } else {
-          TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
-          if (Expr *DefArg = TTP->getDefaultArgument()) {
-            Diag(TTP->getDefaultArgumentLoc(), 
-                 diag::err_default_arg_in_partial_spec)
-              << DefArg->getSourceRange();
-            TTP->setDefaultArgument(0);
-            DefArg->Destroy(Context);
-          }
+  TemplateParameterList *TemplateParams
+    = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, 
+                        (TemplateParameterList**)TemplateParameterLists.get(), 
+                                              TemplateParameterLists.size());
+  if (TemplateParams && TemplateParams->size() > 0) {
+    isPartialSpecialization = true;
+
+    // C++ [temp.class.spec]p10:
+    //   The template parameter list of a specialization shall not
+    //   contain default template argument values.
+    for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+      Decl *Param = TemplateParams->getParam(I);
+      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+        if (TTP->hasDefaultArgument()) {
+          Diag(TTP->getDefaultArgumentLoc(), 
+               diag::err_default_arg_in_partial_spec);
+          TTP->setDefaultArgument(QualType(), SourceLocation(), false);
+        }
+      } else if (NonTypeTemplateParmDecl *NTTP
+                   = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+        if (Expr *DefArg = NTTP->getDefaultArgument()) {
+          Diag(NTTP->getDefaultArgumentLoc(), 
+               diag::err_default_arg_in_partial_spec)
+            << DefArg->getSourceRange();
+          NTTP->setDefaultArgument(0);
+          DefArg->Destroy(Context);
+        }
+      } else {
+        TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
+        if (Expr *DefArg = TTP->getDefaultArgument()) {
+          Diag(TTP->getDefaultArgumentLoc(), 
+               diag::err_default_arg_in_partial_spec)
+            << DefArg->getSourceRange();
+          TTP->setDefaultArgument(0);
+          DefArg->Destroy(Context);
         }
       }
     }
-  }
+  } else if (!TemplateParams)
+    Diag(KWLoc, diag::err_template_spec_needs_header)
+      << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
 
   // Check that the specialization uses the same tag kind as the
   // original template.
@@ -2482,7 +2469,7 @@
                                 ClassTemplate->getIdentifier(),
                                 TemplateNameLoc,
                                 Attr,
-                                move(TemplateParameterLists),
+                                TemplateParams,
                                 AS_none);
     }
 

Modified: cfe/trunk/test/SemaTemplate/nested-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-template.cpp?rev=80003&r1=80002&r2=80003&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-template.cpp Tue Aug 25 12:23:04 2009
@@ -15,16 +15,55 @@
 S::A<int>::Nested::type *ip = &i;
 
 template<typename T>
-struct X0 {
-  template<typename U> void f0(T, U);
+struct Outer {
+  template<typename U>
+  class Inner0;
   
   template<typename U>
-  struct Inner0 {
-    void f1(T, U);
+  class Inner1 {
+    struct ReallyInner;
+    
+    T foo(U);
+    template<typename V> T bar(V);
   };
 };
 
-template<typename X> template<typename Y> void X0<X>::f0(X, Y) { }
+template<typename X>
+template<typename Y>
+class Outer<X>::Inner0 {
+public:
+  void f(X, Y);
+};
+
+#if 0
+// FIXME: These don't parse properly because we can't handle the template-name
+// "Inner0" or "Inner1" after the dependent type Outer<X>. 
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner0<Y>::f(X, Y) {
+}
+
+template<typename X>
+template<typename Y>
+struct Outer<X>::Inner1<Y>::ReallyInner {
+  void g(X, Y);
+};
+
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner1<Y>::ReallyInner::g(X, Y) {
+}
+
+template<typename X>
+template<typename Y>
+X Outer<X>::Inner1<Y>::foo(Y) {
+  return X();
+}
 
-// FIXME:
-// template<typename X> template<typename Y> void X0<X>::Inner0<Y>::f1(X, Y) { }
+template<typename X>
+template<typename Y>
+template<typename Z>
+X Outer<X>::Inner1<Y>::bar(Z) {
+  return X();
+}
+#endif
\ No newline at end of file





More information about the cfe-commits mailing list