[PATCH] -fdelayed-template-parsing: handle cases where a late-parsed function is not a direct member of a template, but rather nested inside a class that's a member of a template (PR19613)

Hans Wennborg hans at chromium.org
Thu May 1 10:27:40 PDT 2014


Thanks for the review! New patch coming up.

================
Comment at: include/clang/Sema/Sema.h:4887-4889
@@ -4886,4 +4886,5 @@
   void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param);
   void ActOnReenterTemplateScope(Scope *S, Decl *Template);
   void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D);
+  void ActOnReenterRecordTemplateScope(Scope *S, CXXRecordDecl *RD);
   void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record);
----------------
Richard Smith wrote:
> Can we fold these three functions together, so we can just say 'reenter the scope of this declaration' and enter all its template parameter lists at once? It's a bit strange that 'ActOnReenterDeclaratorTemplateScope' doesn't actually enter the innermost template scope if the declarator is itself declaring a template.
Done. I've folded them into one function.

================
Comment at: lib/Parse/ParseTemplate.cpp:1254-1256
@@ -1253,5 +1253,5 @@
             dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) {
       TemplateParamScopeStack.push_back(
           new ParseScope(this, Scope::TemplateParamScope));
       Actions.ActOnReenterTemplateScope(getCurScope(), MD);
       ++CurTemplateDepthTracker;
----------------
Richard Smith wrote:
> This side also might have surrounding template parameter lists, if a partial specialization is defined out of line:
> 
>   template<typename T> struct S {
>     template<typename U> struct X;
>     template<typename U> struct X<U*>;
>   };
>   template<typename T> template<typename U> struct S<T>::X<U*> {
>     void f() {}
>   };
Thanks! Added this to the battery of tests.

================
Comment at: lib/Parse/ParseTemplate.cpp:1262-1272
@@ -1260,7 +1261,13 @@
+              Scope::TemplateParamScope, /*EnteredScope*/true));
+        Actions.ActOnReenterTemplateScope(getCurScope(), CTD);
+        ++CurTemplateDepthTracker;
+      }
+
+      bool HasTemplateParams = RD->getNumTemplateParameterLists() > 0;
+
       TemplateParamScopeStack.push_back(
-          new ParseScope(this, Scope::TemplateParamScope, 
-                        /*ManageScope*/IsClassTemplate));
-      Actions.ActOnReenterTemplateScope(getCurScope(),
-                                        MD->getDescribedClassTemplate());
-      if (IsClassTemplate) 
+          new ParseScope(this, Scope::TemplateParamScope,
+                         /*EnteredScope*/HasTemplateParams));
+      if (HasTemplateParams) {
+        Actions.ActOnReenterRecordTemplateScope(getCurScope(), RD);
         ++CurTemplateDepthTracker;
----------------
Richard Smith wrote:
> These steps seem backwards: we should reenter the surrounding template scopes for the class template before we reenter the class template itself.
You're right. I've changed the order.

================
Comment at: lib/Parse/ParseTemplate.cpp:1272
@@ -1266,1 +1271,3 @@
+      if (HasTemplateParams) {
+        Actions.ActOnReenterRecordTemplateScope(getCurScope(), RD);
         ++CurTemplateDepthTracker;
----------------
Richard Smith wrote:
> Why 'record' rather than 'class'? We're pretty consistent in using 'ClassTemplate' (even though we use the unfortunate name 'CXXRecordDecl').
ActOnReenterRecordTemplateScope has gone away now.

================
Comment at: lib/Sema/SemaDeclCXX.cpp:5983-6000
@@ -5982,20 +5982,20 @@
 
 void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) {
   if (!D)
     return;
 
-  int NumParamList = D->getNumTemplateParameterLists();
-  for (int i = 0; i < NumParamList; i++) {
-    TemplateParameterList* Params = D->getTemplateParameterList(i);
+  unsigned NumParamList = D->getNumTemplateParameterLists();
+  for (unsigned i = 0; i < NumParamList; i++) {
+    TemplateParameterList *Params = D->getTemplateParameterList(i);
     for (TemplateParameterList::iterator Param = Params->begin(),
                                       ParamEnd = Params->end();
           Param != ParamEnd; ++Param) {
       NamedDecl *Named = cast<NamedDecl>(*Param);
       if (Named->getDeclName()) {
         S->AddDecl(Named);
         IdResolver.AddDecl(Named);
       }
     }
   }
 }
 
----------------
Richard Smith wrote:
> Maybe factor this out into a static helper template rather than essentially duplicating it?
Since I baked the three ActOnReenter*TemplateScope together, I think the code became simpler.

http://reviews.llvm.org/D3555






More information about the cfe-commits mailing list