diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 5e00be35d8cebd..4f33ff104ffd60 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -875,15 +875,19 @@ class alignas(8) Decl { return getParentFunctionOrMethod() == nullptr; } - /// Returns true if this declaration is lexically inside a function or inside - /// a variable initializer. It recognizes non-defining declarations as well - /// as members of local classes and lambdas: + /// Determine whether a substitution into this declaration would occur as + /// part of a substitution into a dependent local scope. Such a substitution + /// transitively substitutes into all constructs nested within this + /// declaration. + /// + /// This recognizes non-defining declarations as well as members of local + /// classes and lambdas: /// \code - /// void foo() { void bar(); } - /// void foo2() { class ABC { void bar(); }; } - /// inline int x = [](){ return 0; }(); + /// template void foo() { void bar(); } + /// template void foo2() { class ABC { void bar(); }; } + /// template inline int x = [](){ return 0; }(); /// \endcode - bool isInLocalScope() const; + bool isInLocalScopeForInstantiation() const; /// If this decl is defined inside a function/method/block it returns /// the corresponding DeclContext, otherwise it returns null. diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 3fd27757815e13..da1eadd9d931dc 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -364,8 +364,10 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, } } -bool Decl::isInLocalScope() const { +bool Decl::isInLocalScopeForInstantiation() const { const DeclContext *LDC = getLexicalDeclContext(); + if (!LDC->isDependentContext()) + return false; while (true) { if (LDC->isFunctionOrMethod()) return true; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 8197e7d901e94a..11e03c517d0152 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2426,7 +2426,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { FunctionDecl *OwningFunc = cast(OldParm->getDeclContext()); - if (OwningFunc->isInLocalScope()) { + if (OwningFunc->isInLocalScopeForInstantiation()) { // Instantiate default arguments for methods of local classes (DR1484) // and non-defining declarations. Sema::ContextRAII SavedContext(*this, OwningFunc); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6179d90d54f7f3..85adc4ef2dbde1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4458,7 +4458,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI.ExceptionSpec.Type != EST_None && EPI.ExceptionSpec.Type != EST_DynamicNone && EPI.ExceptionSpec.Type != EST_BasicNoexcept && - !Tmpl->isInLocalScope()) { + !Tmpl->isInLocalScopeForInstantiation()) { FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpec.Type == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate; diff --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp index 02696a80bc0fff..1aa456553599c8 100644 --- a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp +++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s // RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s // expected-no-diagnostics // Test default template arguments for function templates. @@ -132,5 +133,32 @@ namespace lambda { void foo() { bar(); } + +#if __cplusplus >= 202002L + // PR46648: ensure we don't reject this by triggering default argument + // instantiation spuriously. + auto x = [](T x = 123) {}; + void y() { x(nullptr); } + + template struct X { + template constexpr int f() { + auto l = [](int n = A + B + C) { return n; }; + return l.template operator()<3>(); + } + }; + static_assert(X<100>().f<20>() == 123); + + template<> template constexpr int X<200>::f() { + auto l = [](int n = 300 + B + C) { return n; }; + return l.template operator()<1>(); + } + static_assert(X<200>().f<20>() == 321); + + template<> template<> constexpr int X<300>::f<20>() { + auto l = [](int n = 450 + C) { return n; }; + return l.template operator()<6>(); + } + static_assert(X<300>().f<20>() == 456); +#endif } // namespace lambda #endif diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp index 0ce4cb39d3493e..abdb8e9c4a9fdb 100644 --- a/clang/test/SemaTemplate/dependent-expr.cpp +++ b/clang/test/SemaTemplate/dependent-expr.cpp @@ -144,7 +144,7 @@ namespace PR45083 { void h(auto a, void*) {} // expected-error {{redefinition}} void i(auto a) { - [](auto a, int = ({decltype(a) i; i * 2;})){}(a); // expected-error {{no matching function}} expected-note {{substitution failure}} + [](auto a, int = ({decltype(a) i; i * 2;})){}(a); // expected-error {{invalid operands to binary expression ('decltype(a)' (aka 'void *') and 'int')}} expected-note {{in instantiation of}} } void use_i() { i(0);