From 3ed0799f0e98f05a349218b215a0e10c193109c3 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Mon, 29 Jun 2015 17:50:19 +0000 Subject: [PATCH] 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@240974 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Parse/ParseDeclCXX.cpp | 9 ++-- lib/Sema/SemaTemplateInstantiate.cpp | 23 ++++++-- lib/Sema/SemaTemplateInstantiateDecl.cpp | 10 +++- test/SemaTemplate/instantiate-local-class.cpp | 54 +++++++++++++++++++ 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 47778b856d..6531f7b902 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 178a14e9ec..7d58017a9b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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(OldParm->getDeclContext()); + CXXRecordDecl *ClassD = dyn_cast(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()); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index f35d1aaf77..e240c70508 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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(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; diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp index f58d7a4962..c0ea6a0bc8 100644 --- a/test/SemaTemplate/instantiate-local-class.cpp +++ b/test/SemaTemplate/instantiate-local-class.cpp @@ -394,3 +394,57 @@ void f() { void g() { f(); } } + + +namespace PR21332 { + template 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(); // expected-note{{in instantiation of function template specialization 'PR21332::f1' requested here}} + + template 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(); // expected-note{{in instantiation of function template specialization 'PR21332::f2' requested here}} + + template 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(); //expected-note{{in instantiation of function template specialization 'PR21332::f3' requested here}} + + template 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(); // expected-note{{in instantiation of function template specialization 'PR21332::f4' requested here}} + + template 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(); // expected-note {{in instantiation of function template specialization 'PR21332::f5' requested here}} + + template 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(); // expected-note{{in instantiation of function template specialization 'PR21332::f6' requested here}} + + template void f7() { + struct S { void g() noexcept(undefined_val); }; // expected-error{{use of undeclared identifier 'undefined_val'}} + } + template void f7(); +} -- 2.50.1