Author: Aaron Puchert Date: 2020-04-22T22:37:21+02:00 New Revision: f43859a099fa3587123717be941fa63ba8d0d4f2
URL: https://github.com/llvm/llvm-project/commit/f43859a099fa3587123717be941fa63ba8d0d4f2 DIFF: https://github.com/llvm/llvm-project/commit/f43859a099fa3587123717be941fa63ba8d0d4f2.diff LOG: PR45000: Let Sema::SubstParmVarDecl handle default args of lambdas in initializers Summary: We extend the behavior for local functions and methods of local classes to lambdas in variable initializers. The initializer is not a separate scope, but we treat it as such. We also remove the (faulty) instantiation of default arguments in TreeTransform::TransformLambdaExpr, because it doesn't do proper initialization, and if it did, we would do it twice (and thus also emit eventual errors twice). Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D76038 Added: Modified: clang/include/clang/AST/DeclBase.h clang/lib/AST/DeclBase.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Sema/TreeTransform.h clang/test/SemaCXX/vartemplate-lambda.cpp clang/test/SemaTemplate/instantiate-local-class.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index b48f7e4f9308..91875377679d 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -869,14 +869,15 @@ class alignas(8) Decl { return getParentFunctionOrMethod() == nullptr; } - /// Returns true if this declaration lexically is inside a function. - /// It recognizes non-defining declarations as well as members of local - /// classes: + /// 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: /// \code /// void foo() { void bar(); } /// void foo2() { class ABC { void bar(); }; } + /// inline int x = [](){ return 0; }; /// \endcode - bool isLexicallyWithinFunctionOrMethod() const; + bool isInLocalScope() 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 8a18de1e8248..2aab53f4fa90 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -332,13 +332,16 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, } } -bool Decl::isLexicallyWithinFunctionOrMethod() const { +bool Decl::isInLocalScope() const { const DeclContext *LDC = getLexicalDeclContext(); while (true) { if (LDC->isFunctionOrMethod()) return true; if (!isa<TagDecl>(LDC)) return false; + if (const auto *CRD = dyn_cast<CXXRecordDecl>(LDC)) + if (CRD->isLambda()) + return true; LDC = LDC->getLexicalParent(); } return false; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index e2b3ebba6bbe..4b6b92ccab2c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2380,7 +2380,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext()); - if (OwningFunc->isLexicallyWithinFunctionOrMethod()) { + if (OwningFunc->isInLocalScope()) { // 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 551517581063..a6541dabe6b2 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4363,7 +4363,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI.ExceptionSpec.Type != EST_None && EPI.ExceptionSpec.Type != EST_DynamicNone && EPI.ExceptionSpec.Type != EST_BasicNoexcept && - !Tmpl->isLexicallyWithinFunctionOrMethod()) { + !Tmpl->isInLocalScope()) { FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpec.Type == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index abde968bed8c..da6ff8e5cea8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12219,19 +12219,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { LSI->CallOperator = NewCallOperator; - for (unsigned I = 0, NumParams = NewCallOperator->getNumParams(); - I != NumParams; ++I) { - auto *P = NewCallOperator->getParamDecl(I); - if (P->hasUninstantiatedDefaultArg()) { - EnterExpressionEvaluationContext Eval( - getSema(), - Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P); - ExprResult R = getDerived().TransformExpr( - E->getCallOperator()->getParamDecl(I)->getDefaultArg()); - P->setDefaultArg(R.get()); - } - } - getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); diff --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp index 6744968bcc4d..b17c9bb8dcb9 100644 --- a/clang/test/SemaCXX/vartemplate-lambda.cpp +++ b/clang/test/SemaCXX/vartemplate-lambda.cpp @@ -4,7 +4,12 @@ template <class> auto fn0 = [] {}; template <typename> void foo0() { fn0<char>(); } template<typename T> auto fn1 = [](auto a) { return a + T(1); }; -template<typename T> auto v1 = [](int a = T(1)) { return a; }(); +template<typename T> auto v1 = [](int a = T()) { return a; }(); +// expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} +// expected-error@-2{{no matching function for call}} +// expected-note@-3{{passing argument to parameter 'a' here}} +// expected-note@-4{{candidate function not viable}} +// expected-note@-5{{conversion candidate of type 'int (*)(int)'}} struct S { template<class T> @@ -16,6 +21,7 @@ int foo2() { X a = 0x61; fn1<char>(a); (void)v1<int>; + (void)v1<int *>; // expected-note{{in instantiation of variable template specialization 'v1' requested here}} (void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}} return 0; } diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp index eaff4c4bbc8d..550c59d61778 100644 --- a/clang/test/SemaTemplate/instantiate-local-class.cpp +++ b/clang/test/SemaTemplate/instantiate-local-class.cpp @@ -486,3 +486,16 @@ namespace anon_union_default_member_init { } void g() { f<int>(); } } + +namespace PR45000 { + template <typename T> + void f(int x = [](T x = nullptr) -> int { return x; }()); + // expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'nullptr_t'}} + // expected-note@-2 {{passing argument to parameter 'x' here}} + // expected-error@-3 {{no matching function for call}} + // expected-note@-4 {{candidate function not viable: requires single argument 'x', but no arguments were provided}} + // expected-note@-5 {{conversion candidate of type 'auto (*)(int) -> int'}} + + void g() { f<int>(); } + // expected-note@-1 {{in instantiation of default function argument expression for 'f<int>' required here}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits