r240974 - Instantiation of local class members.
Serge Pavlov
sepavloff at gmail.com
Mon Jun 29 10:50:19 PDT 2015
Author: sepavloff
Date: Mon Jun 29 12:50:19 2015
New Revision: 240974
URL: http://llvm.org/viewvc/llvm-project?rev=240974&view=rev
Log:
Instantiation of local class members.
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
Modified:
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=240974&r1=240973&r2=240974&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jun 29 12:50:19 2015
@@ -3317,13 +3317,16 @@ Parser::tryParseExceptionSpecification(b
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;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=240974&r1=240973&r2=240974&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Jun 29 12:50:19 2015
@@ -1680,11 +1680,24 @@ ParmVarDecl *Sema::SubstParmVarDecl(Parm
} 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());
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=240974&r1=240973&r2=240974&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jun 29 12:50:19 2015
@@ -3246,10 +3246,18 @@ TemplateDeclInstantiator::InitFunctionIn
// 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;
Modified: cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp?rev=240974&r1=240973&r2=240974&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp Mon Jun 29 12:50:19 2015
@@ -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>();
+}
More information about the cfe-commits
mailing list