If a function containing a local class is instantiated, instantiate
all of local class member, including default arguments and exception
specifications.

This change fixes PR21332 and thus implements DR1484.

http://reviews.llvm.org/D9990

Files:
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaTemplate/instantiate-local-class.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1819,8 +1819,27 @@
     Method->setLexicalDeclContext(D->getLexicalDeclContext());
 
   // Attach the parameters
-  for (unsigned P = 0; P < Params.size(); ++P)
+  for (unsigned P = 0; P < Params.size(); ++P) {
     Params[P]->setOwningFunction(Method);
+
+    // If this is a method of a local class, as per DR1484 its default arguments
+    // must be instantiated now.
+    CXXRecordDecl *ClassD = cast<CXXRecordDecl>(D->getDeclContext());
+    if (ClassD->isLocalClass() && !ClassD->isLambda()) {
+      ParmVarDecl *OldParm = D->getParamDecl(P);
+      if (Expr *OldDefArg = OldParm->getDefaultArg()) {
+        ExprResult NewDefArg;
+        {
+          Sema::ContextRAII SavedContext(SemaRef, ClassD);
+          LocalInstantiationScope Local(SemaRef);
+          NewDefArg = SemaRef.SubstExpr(OldDefArg, TemplateArgs);
+        }
+        if (NewDefArg.isInvalid())
+          D->setInvalidDecl();
+        Params[P]->setDefaultArg(NewDefArg.get());
+      }
+    }
+  }
   Method->setParams(Params);
 
   if (InitMethodInstantiation(Method, D))
@@ -3246,10 +3265,17 @@
 
     // DR1330: In C++11, defer instantiation of a non-trivial
     // exception specification.
+    // DR1484: Local classes and their members are instantiated along with the
+    // containing function.
+    bool InLocalClass = false;
+    if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Tmpl->getDeclContext()))
+      if (Class->isLocalClass())
+        InLocalClass = true;
     if (SemaRef.getLangOpts().CPlusPlus11 &&
         EPI.ExceptionSpec.Type != EST_None &&
         EPI.ExceptionSpec.Type != EST_DynamicNone &&
-        EPI.ExceptionSpec.Type != EST_BasicNoexcept) {
+        EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
+        !InLocalClass) {
       FunctionDecl *ExceptionSpecTemplate = Tmpl;
       if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
         ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
Index: test/SemaTemplate/instantiate-local-class.cpp
===================================================================
--- test/SemaTemplate/instantiate-local-class.cpp
+++ test/SemaTemplate/instantiate-local-class.cpp
@@ -394,3 +394,52 @@
 
 void g() { f<void>(); }
 }
+
+
+namespace PR21332 {
+  template<typename T> void f1() {
+    struct S {  // expected-note{{in instantiation of member class 'S' requested here}}
+      void g1(int n = T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+    };
+  }
+  template void f1<int>();  // expected-note{{in instantiation of function template specialization 'PR21332::f1<int>' requested here}}
+
+  template<typename T> void f2() {
+    struct S {  // expected-note{{in instantiation of member class 'S' requested here}}
+      void g2() noexcept(T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+    };
+  }
+  template void f2<int>();  // expected-note{{in instantiation of function template specialization 'PR21332::f2<int>' requested here}}
+
+  template<typename T> void f3() {
+    enum S {
+      val = T::error;  // expected-error{{expected '}' or ','}} expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+    };
+  }
+  template void f3<int>();  //expected-note{{in instantiation of function template specialization 'PR21332::f3<int>' requested here}}
+
+  template<typename T> void f4() {
+    enum class S {
+      val = T::error;  // expected-error{{expected '}' or ','}} expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+    };
+  }
+  template void f4<int>();  // expected-note{{in instantiation of function template specialization 'PR21332::f4<int>' requested here}}
+
+  template<typename T> void f5() {
+    class S {  // expected-note {{in instantiation of default member initializer 'PR21332::f5()::S::val' requested here}}
+      int val = T::error;  // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+     };
+  }
+  template void f5<int>();  // expected-note {{in instantiation of function template specialization 'PR21332::f5<int>' requested here}}
+
+  template<typename T> void f6() {
+    class S {  // expected-note {{in instantiation of member function 'PR21332::f6()::S::get' requested here}}
+      void get() {
+        class S2 {  // expected-note {{in instantiation of member class 'S2' requested here}}
+          void g1(int n = T::error);  // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+        };
+      }
+    };
+  }
+  template void f6<int>();  // expected-note{{in instantiation of function template specialization 'PR21332::f6<int>' requested here}}
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to