]> granicus.if.org Git - clang/commitdiff
Instantiation of local class members.
authorSerge Pavlov <sepavloff@gmail.com>
Mon, 29 Jun 2015 17:50:19 +0000 (17:50 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Mon, 29 Jun 2015 17:50:19 +0000 (17:50 +0000)
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.

Differential Revision: http://reviews.llvm.org/D9990

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

lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaTemplate/instantiate-local-class.cpp

index 47778b856ddaf85a34ad94e51f21ef78020717f6..6531f7b902d0f5ae7f33c5535ead7fdad14c2701 100644 (file)
@@ -3317,13 +3317,16 @@ Parser::tryParseExceptionSpecification(bool Delayed,
     T.consumeOpen();
     NoexceptType = EST_ComputedNoexcept;
     NoexceptExpr = ParseConstantExpression();
+    T.consumeClose();
     // The argument must be contextually convertible to bool. We use
     // ActOnBooleanCondition for this purpose.
-    if (!NoexceptExpr.isInvalid())
+    if (!NoexceptExpr.isInvalid()) {
       NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc,
                                                    NoexceptExpr.get());
-    T.consumeClose();
-    NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
+      NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
+    } else {
+      NoexceptType = EST_None;
+    }
   } else {
     // There is no argument.
     NoexceptType = EST_BasicNoexcept;
index 178a14e9ecc00dc85554910482cbbefcf6888b7b..7d58017a9bf04204281b79974f5bf9a72ec2347e 100644 (file)
@@ -1680,11 +1680,24 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
   } else if (OldParm->hasUnparsedDefaultArg()) {
     NewParm->setUnparsedDefaultArg();
     UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
-  } else if (Expr *Arg = OldParm->getDefaultArg())
-    // FIXME: if we non-lazily instantiated non-dependent default args for
-    // non-dependent parameter types we could remove a bunch of duplicate
-    // conversion warnings for such arguments.
-    NewParm->setUninstantiatedDefaultArg(Arg);
+  } else if (Expr *Arg = OldParm->getDefaultArg()) {
+    FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
+    CXXRecordDecl *ClassD = dyn_cast<CXXRecordDecl>(OwningFunc->getDeclContext());
+    if (ClassD && ClassD->isLocalClass() && !ClassD->isLambda()) {
+      // If this is a method of a local class, as per DR1484 its default
+      // arguments must be instantiated.
+      Sema::ContextRAII SavedContext(*this, ClassD);
+      LocalInstantiationScope Local(*this);
+      ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
+      if (NewArg.isUsable())
+        NewParm->setDefaultArg(NewArg.get());
+    } else {
+      // FIXME: if we non-lazily instantiated non-dependent default args for
+      // non-dependent parameter types we could remove a bunch of duplicate
+      // conversion warnings for such arguments.
+      NewParm->setUninstantiatedDefaultArg(Arg);
+    }
+  }
 
   NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
   
index f35d1aaf77e9a77c3a8711d4dc7754f81fbeb904..e240c70508267fb86807be8d1f0e85050865a803 100644 (file)
@@ -3246,10 +3246,18 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
 
     // 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 RequireInstantiation = false;
+    if (CXXRecordDecl *Cls = dyn_cast<CXXRecordDecl>(Tmpl->getDeclContext())) {
+      if (Cls->isLocalClass())
+        RequireInstantiation = 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 &&
+        !RequireInstantiation) {
       FunctionDecl *ExceptionSpecTemplate = Tmpl;
       if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
         ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
index f58d7a49622539388f0cd229f37cb285f99c8b16..c0ea6a0bc870bf9803a2266a2443e31a3923fe5a 100644 (file)
@@ -394,3 +394,57 @@ void f() {
 
 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}}
+
+  template<typename T> void f7() {
+    struct S { void g() noexcept(undefined_val); };  // expected-error{{use of undeclared identifier 'undefined_val'}}
+  }
+  template void f7<int>();
+}