From: Serge Pavlov Date: Sun, 23 Aug 2015 10:22:28 +0000 (+0000) Subject: Instantiate function declarations in instantiated functions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3193d2e21f78efbd6d38874783f91fed3b858b95;p=clang Instantiate function declarations in instantiated functions. If a function declaration is found inside a template function as in: template void f() { void g(int x = T::v) except(T::w); } it must be instantiated along with the enclosing template function, including default arguments and exception specification. Together with the patch committed in r240974 this implements DR1484. Differential Revision: http://reviews.llvm.org/D11194 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@245810 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 43d8366f0d..f563a04d06 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -728,6 +728,15 @@ public: return getParentFunctionOrMethod() == nullptr; } + /// \brief Returns true if this declaration lexically is inside a function. + /// It recognizes non-defining declarations as well as members of local + /// classes: + /// \code + /// void foo() { void bar(); } + /// void foo2() { class ABC { void bar(); }; } + /// \endcode + bool isLexicallyWithinFunctionOrMethod() const; + /// \brief If this decl is defined inside a function/method/block it returns /// the corresponding DeclContext, otherwise it returns null. const DeclContext *getParentFunctionOrMethod() const; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 40b135f920..00d7d323b7 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -266,6 +266,18 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, } } +bool Decl::isLexicallyWithinFunctionOrMethod() const { + const DeclContext *LDC = getLexicalDeclContext(); + do { + if (LDC->isFunctionOrMethod()) + return true; + if (!isa(LDC)) + return false; + LDC = LDC->getParent(); + } while (LDC); + return false; +} + bool Decl::isInAnonymousNamespace() const { const DeclContext *DC = getDeclContext(); do { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 12cbd5bd4f..031a2bad5f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1682,11 +1682,10 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } 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); + if (OwningFunc->isLexicallyWithinFunctionOrMethod()) { + // Instantiate default arguments for methods of local classes (DR1484) + // and non-defining declarations. + Sema::ContextRAII SavedContext(*this, OwningFunc); LocalInstantiationScope Local(*this); ExprResult NewArg = SubstExpr(Arg, TemplateArgs); if (NewArg.isUsable()) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index c8a067658b..9899f1e8b1 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3247,16 +3247,11 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, // 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 && - !RequireInstantiation) { + !Tmpl->isLexicallyWithinFunctionOrMethod()) { FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpec.Type == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate; diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp index 38d5d0a6cd..9b0a9ad8c2 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp @@ -26,23 +26,26 @@ struct NonPOD { }; struct NoDefaultCtor { - NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}} + NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}} \ + // expected-note{{candidate constructor not viable: requires 1 argument, but 0 were provided}} ~NoDefaultCtor(); }; template void defargs_in_template_unused(T t) { - auto l1 = [](const T& value = T()) { }; + auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} l1(t); } template void defargs_in_template_unused(NonPOD); -template void defargs_in_template_unused(NoDefaultCtor); +template void defargs_in_template_unused(NoDefaultCtor); // expected-note{{in instantiation of function template specialization 'defargs_in_template_unused' requested here}} template void defargs_in_template_used() { - auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} - l1(); // expected-note{{in instantiation of default function argument expression for 'operator()' required here}} + auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \ + // expected-note{{candidate function not viable: requires single argument 'value', but no arguments were provided}} \ + // expected-note{{conversion candidate of type 'void (*)(const NoDefaultCtor &)'}} + l1(); // expected-error{{no matching function for call to object of type '(lambda at }} } template void defargs_in_template_used(); diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp index 439a303921..0e972522d4 100644 --- a/test/SemaTemplate/default-arguments.cpp +++ b/test/SemaTemplate/default-arguments.cpp @@ -159,3 +159,10 @@ namespace DR1635 { int g() { X::f(0); } // expected-note {{in instantiation of template class 'DR1635::X' requested here}} } + +namespace NondefDecls { + template void f1() { + int g1(int defarg = 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 'NondefDecls::f1' requested here}} +} diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index f62ef61758..6e8323d1ee 100644 --- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -178,3 +178,11 @@ namespace Variadic { } } + +namespace NondefDecls { + template void f1() { + int g1(int) noexcept(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 'NondefDecls::f1' requested here}} +} +