diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9782,6 +9782,9 @@ SmallVectorImpl &ParamTypes, SmallVectorImpl *OutParams, ExtParameterInfoBuilder &ParamInfos); + bool SubstDefaultArgument(SourceLocation Loc, ParmVarDecl *Param, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool ForCallExpr = false); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -252,12 +252,12 @@ bool Decl::isTemplated() const { // A declaration is templated if it is a template or a template pattern, or - // is within (lexcially for a friend, semantically otherwise) a dependent - // context. - // FIXME: Should local extern declarations be treated like friends? + // is within (lexcially for a friend or local function declaration, + // semantically otherwise) a dependent context. if (auto *AsDC = dyn_cast(this)) return AsDC->isDependentContext(); - auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext(); + auto *DC = getFriendObjectKind() || isLocalExternDecl() + ? getLexicalDeclContext() : getDeclContext(); return DC->isDependentContext() || isTemplateDecl() || getDescribedTemplateParams(); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -174,11 +174,11 @@ "Outer template not instantiated?"); } - // If this is a friend declaration and it declares an entity at + // If this is a friend or local declaration and it declares an entity at // namespace scope, take arguments from its lexical parent // instead of its semantic parent, unless of course the pattern we're // instantiating actually comes from the file's context! - if (Function->getFriendObjectKind() && + if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && Function->getNonTransparentDeclContext()->isFileContext() && (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { Ctx = Function->getLexicalDeclContext(); @@ -1183,8 +1183,30 @@ ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); Sema::ConstraintEvalRAII RAII(*this); - ExprResult Res = inherited::TransformLambdaExpr(E); - return Res; + ExprResult Result = inherited::TransformLambdaExpr(E); + if (Result.isInvalid()) + return Result; + + CXXMethodDecl *MD = Result.getAs()->getCallOperator(); + for (ParmVarDecl *PVD : MD->parameters()) { + if (!PVD->hasDefaultArg()) + continue; + Expr *UninstExpr = PVD->getUninstantiatedDefaultArg(); + // FIXME: Obtain the source location for the '=' token. + SourceLocation EqualLoc = UninstExpr->getBeginLoc(); + if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + PVD->setDefaultArg(ErrorResult.get()); + } + } + + return Result; } ExprResult TransformRequiresExpr(RequiresExpr *E) { @@ -2508,29 +2530,17 @@ NewParm->setUnparsedDefaultArg(); UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { - FunctionDecl *OwningFunc = cast(OldParm->getDeclContext()); - if (OwningFunc->isInLocalScopeForInstantiation()) { - // Instantiate default arguments for methods of local classes (DR1484) - // and non-defining declarations. - Sema::ContextRAII SavedContext(*this, OwningFunc); - LocalInstantiationScope Local(*this, true); - ExprResult NewArg = SubstExpr(Arg, TemplateArgs); - if (NewArg.isUsable()) { - // It would be nice if we still had this. - SourceLocation EqualLoc = NewArg.get()->getBeginLoc(); - ExprResult Result = - ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc); - if (Result.isInvalid()) - return nullptr; - - SetParamDefaultArgument(NewParm, Result.getAs(), EqualLoc); - } - } 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); - } + // Default arguments cannot be substituted until the declaration context + // for the associated function or lambda capture class is available. + // This is necessary for cases like the following where construction of + // the lambda capture class for the outer lambda is dependent on the + // parameter types but where the default argument is dependent on the + // outer lambda's declaration context. + // template + // auto f() { + // return [](T = []{ return T{}; }()) { return 0; }; + // } + NewParm->setUninstantiatedDefaultArg(Arg); } NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); @@ -2575,6 +2585,88 @@ Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos); } +/// Substitute the given template arguments into the default argument. +bool Sema::SubstDefaultArgument( + SourceLocation Loc, + ParmVarDecl *Param, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool ForCallExpr) { + FunctionDecl *FD = cast(Param->getDeclContext()); + Expr *PatternExpr = Param->getUninstantiatedDefaultArg(); + + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + + InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost()); + if (Inst.isInvalid()) + return true; + if (Inst.isAlreadyInstantiating()) { + Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; + Param->setInvalidDecl(); + return true; + } + + ExprResult Result; + { + // C++ [dcl.fct.default]p5: + // The names in the [default argument] expression are bound, and + // the semantic constraints are checked, at the point where the + // default argument expression appears. + ContextRAII SavedContext(*this, FD); + std::unique_ptr LIS; + + if (ForCallExpr) { + // When instantiating a default argument due to use in a call expression, + // an instantiation scope that includes the parameters of the callee is + // required to satisfy references from the default argument. For example: + // template void f(T a, int = decltype(a)()); + // void g() { f(0); } + LIS = std::make_unique(*this); + FunctionDecl *PatternFD = FD->getTemplateInstantiationPattern( + /*ForDefinition*/ false); + if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs)) + return true; + } + + runWithSufficientStackSpace(Loc, [&] { + Result = SubstInitializer(PatternExpr, TemplateArgs, + /*DirectInit*/false); + }); + } + if (Result.isInvalid()) + return true; + + if (ForCallExpr) { + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, Param); + InitializationKind Kind = InitializationKind::CreateCopy( + Param->getLocation(), + /*FIXME:EqualLoc*/ PatternExpr->getBeginLoc()); + Expr *ResultE = Result.getAs(); + + InitializationSequence InitSeq(*this, Entity, Kind, ResultE); + Result = InitSeq.Perform(*this, Entity, Kind, ResultE); + if (Result.isInvalid()) + return true; + + Result = + ActOnFinishFullExpr(Result.getAs(), Param->getOuterLocStart(), + /*DiscardedValue*/ false); + } else { + // FIXME: Obtain the source location for the '=' token. + SourceLocation EqualLoc = PatternExpr->getBeginLoc(); + Result = ConvertParamDefaultArgument(Param, Result.getAs(), EqualLoc); + } + if (Result.isInvalid()) + return true; + + // Remember the instantiated default argument. + Param->setDefaultArg(Result.getAs()); + + return false; +} + /// Perform substitution on the base class specifiers of the /// given class template specialization. /// diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2003,7 +2003,7 @@ /// Normal class members are of more specific types and therefore /// don't make it here. This function serves three purposes: /// 1) instantiating function templates -/// 2) substituting friend declarations +/// 2) substituting friend and local function declarations /// 3) substituting deduction guide declarations for nested class templates Decl *TemplateDeclInstantiator::VisitFunctionDecl( FunctionDecl *D, TemplateParameterList *TemplateParams, @@ -2133,6 +2133,9 @@ assert(D->getDeclContext()->isFileContext()); LexicalDC = D->getDeclContext(); } + else if (D->isLocalExternDecl()) { + LexicalDC = SemaRef.CurContext; + } Function->setLexicalDeclContext(LexicalDC); @@ -2275,6 +2278,37 @@ QualifierLoc.hasQualifier()); } + // Per [temp.inst], default arguments in function declarations at local scope + // are instantiated along with the enclosing declaration. For example: + // + // template + // void ft() { + // void f(int = []{ return T::value; }()); + // } + // template void ft(); // error: type 'int' cannot be used prior + // to '::' because it has no members + // + // The error is issued during instantiation of ft() because substitution + // into the default argument fails; the default argument is instantiated even + // though it is never used. + if (Function->isLocalExternDecl()) { + for (ParmVarDecl *PVD : Function->parameters()) { + if (!PVD->hasDefaultArg()) + continue; + if (SemaRef.SubstDefaultArgument(D->getInnerLocStart(), PVD, TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + Expr *UninstExpr = PVD->getUninstantiatedDefaultArg(); + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + PVD->setDefaultArg(ErrorResult.get()); + } + } + } + SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous, IsExplicitSpecialization, Function->isThisDeclarationADefinition()); @@ -2628,6 +2662,39 @@ Previous.clear(); } + // Per [temp.inst], default arguments in member functions of local classes + // are instantiated along with the member function declaration. For example: + // + // template + // void ft() { + // struct lc { + // int operator()(int p = []{ return T::value; }()); + // }; + // } + // template void ft(); // error: type 'int' cannot be used prior + // to '::'because it has no members + // + // The error is issued during instantiation of ft()::lc::operator() + // because substitution into the default argument fails; the default argument + // is instantiated even though it is never used. + if (D->isInLocalScopeForInstantiation()) { + for (unsigned P = 0; P < Params.size(); ++P) { + if (!Params[P]->hasDefaultArg()) + continue; + if (SemaRef.SubstDefaultArgument(StartLoc, Params[P], TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + Expr *UninstExpr = Params[P]->getUninstantiatedDefaultArg(); + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + Params[P]->setDefaultArg(ErrorResult.get()); + } + } + } + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, IsExplicitSpecialization, Method->isThisDeclarationADefinition()); @@ -4458,10 +4525,6 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { assert(Param->hasUninstantiatedDefaultArg()); - Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); - - EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); // Instantiate the expression. // @@ -4483,59 +4546,9 @@ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); - InstantiatingTemplate Inst(*this, CallLoc, Param, - TemplateArgs.getInnermost()); - if (Inst.isInvalid()) - return true; - if (Inst.isAlreadyInstantiating()) { - Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; - Param->setInvalidDecl(); - return true; - } - - ExprResult Result; - { - // C++ [dcl.fct.default]p5: - // The names in the [default argument] expression are bound, and - // the semantic constraints are checked, at the point where the - // default argument expression appears. - ContextRAII SavedContext(*this, FD); - LocalInstantiationScope Local(*this); - - FunctionDecl *Pattern = FD->getTemplateInstantiationPattern( - /*ForDefinition*/ false); - if (addInstantiatedParametersToScope(FD, Pattern, Local, TemplateArgs)) - return true; - - runWithSufficientStackSpace(CallLoc, [&] { - Result = SubstInitializer(UninstExpr, TemplateArgs, - /*DirectInit*/false); - }); - } - if (Result.isInvalid()) - return true; - - // Check the expression as an initializer for the parameter. - InitializedEntity Entity - = InitializedEntity::InitializeParameter(Context, Param); - InitializationKind Kind = InitializationKind::CreateCopy( - Param->getLocation(), - /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc()); - Expr *ResultE = Result.getAs(); - - InitializationSequence InitSeq(*this, Entity, Kind, ResultE); - Result = InitSeq.Perform(*this, Entity, Kind, ResultE); - if (Result.isInvalid()) - return true; - - Result = - ActOnFinishFullExpr(Result.getAs(), Param->getOuterLocStart(), - /*DiscardedValue*/ false); - if (Result.isInvalid()) + if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true)) return true; - // Remember the instantiated default argument. - Param->setDefaultArg(Result.getAs()); if (ASTMutationListener *L = getASTMutationListener()) L->DefaultArgumentInstantiated(Param); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp @@ -34,7 +34,8 @@ template void defargs_in_template_unused(T t) { - auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} + auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \ + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} l1(t); } @@ -44,13 +45,8 @@ template void defargs_in_template_used() { 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}} -#if defined(_WIN32) && !defined(_WIN64) - // expected-note@46{{conversion candidate of type 'void (*)(const NoDefaultCtor &) __attribute__((thiscall))'}} -#else - // expected-note@46{{conversion candidate of type 'void (*)(const NoDefaultCtor &)'}} -#endif - l1(); // expected-error{{no matching function for call to object of type '(lambda at }} + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} + l1(); } template void defargs_in_template_used(); diff --git a/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp b/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s + +template +auto ft1() { + return [](int p = [] { return 0; } ()) { return p; }; +} +void test_ft1() { + // CHECK: call noundef i32 @_ZZZ3ft1IiEDavENKUliE_clEiEd_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZ3ft1IiEDavENKUliE_clEi + ft1<>()(); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft1IiEDavENKUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft1IiEDavENKUliE_clEiEd_NKUlvE_clEv + +template +auto ft2() { + struct S { + T operator()(T p = []{ return 0; }()) const { return p; } + }; + return S{}; +} +void test_ft2() { + // CHECK: call noundef i32 @_ZZZ3ft2IiEDavENK1SclEiEd_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZ3ft2IiEDavENK1SclEi + ft2()(); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft2IiEDavENK1SclEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft2IiEDavENK1SclEiEd_NKUlvE_clEv + +template +auto vt1 = [](int p = [] { return 0; } ()) { return p; }; +void test_vt1() { + // CHECK: call noundef i32 @_ZZNK3vt1IiEMUliE_clEiEd_NKUlvE_clEv + // CHECK: call noundef i32 @_ZNK3vt1IiEMUliE_clEi + vt1(); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZNK3vt1IiEMUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZNK3vt1IiEMUliE_clEiEd_NKUlvE_clEv diff --git a/clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp b/clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -no-opaque-pointers -std=c++20 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s + +template +auto ft1() { + return [](T p1 = [] { return T{}; } (), + U p2 = [] { return U{}; } ()) { return p1+p2; }; +} +void test_ft1() { + // CHECK: call noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed0_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_ + ft1()(); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_ +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed0_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft1IiEDavENKUlTyiT_E_clIiEEDaiS0_Ed_NKUlvE_clEv + +template +auto vt1 = [](T p1 = [] { return T{}; } (), + U p2 = [] { return U{}; } ()) { return p1+p2; }; +void test_vt1() { + // CHECK: call noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed0_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed_NKUlvE_clEv + // CHECK: call noundef i32 @_ZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_ + vt1(); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_ +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed0_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZNK3vt1IiEMUlTyiT_E_clIiEEDaiS1_Ed_NKUlvE_clEv diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp b/clang/test/CodeGenCXX/mangle-lambdas.cpp --- a/clang/test/CodeGenCXX/mangle-lambdas.cpp +++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp @@ -210,6 +210,84 @@ } int k = testVarargsLambdaNumbering(); + +template +void ft1(int = [](int p = [] { return 42; } ()) { + return p; + } ()); +void test_ft1() { + // CHECK: call noundef i32 @"_ZZZ3ft1IiEviENK3$_4clEiEd_NKUlvE_clEv" + // CHECK: call noundef i32 @"_ZZ3ft1IiEviENK3$_4clEi" + ft1(); +} +// CHECK-LABEL: define internal noundef i32 @"_ZZ3ft1IiEviENK3$_4clEi" +// CHECK-LABEL: define internal noundef i32 @"_ZZZ3ft1IiEviENK3$_4clEiEd_NKUlvE_clEv" + +struct c1 { + template + void mft1(int = [](int p = [] { return 42; } ()) { + return p; + } ()); +}; +void test_c1_mft1() { + // CHECK: call noundef i32 @_ZZZN2c14mft1IiEEviEd_NKUliE_clEiEd_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZN2c14mft1IiEEviEd_NKUliE_clEi + c1{}.mft1(); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZN2c14mft1IiEEviEd_NKUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZN2c14mft1IiEEviEd_NKUliE_clEiEd_NKUlvE_clEv + +template +struct ct1 { + void mf1(int = [](int p = [] { return 42; } ()) { + return p; + } ()); + friend void ff(ct1, int = [](int p = [] { return 0; }()) { return p; }()) {} +}; +void test_ct1_mft1() { + // CHECK: call noundef i32 @_ZZZN3ct1IiE3mf1EiEd_NKUliE_clEiEd_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZN3ct1IiE3mf1EiEd_NKUliE_clEi + ct1<>{}.mf1(); + // CHECK: call noundef i32 @_ZZZ2ff3ct1IiEiEd_NKUliE_clEiEd_NKUlvE_clEv + // CHECK: call noundef i32 @_ZZ2ff3ct1IiEiEd_NKUliE_clEi + ff(ct1<>{}); +} +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZN3ct1IiE3mf1EiEd_NKUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZN3ct1IiE3mf1EiEd_NKUliE_clEiEd_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ2ff3ct1IiEiEd_NKUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ2ff3ct1IiEiEd_NKUliE_clEiEd_NKUlvE_clEv + +template +void ft2() { + [](int p = [] { return 42; } ()) { return p; } (); +} +template void ft2<>(); +// CHECK: call noundef i32 @_ZZZ3ft2IiEvvENKUliE_clEiEd_NKUlvE_clEv +// CHECK: call noundef i32 @_ZZ3ft2IiEvvENKUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft2IiEvvENKUliE_clEi +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft2IiEvvENKUliE_clEiEd_NKUlvE_clEv + +template +void ft3() { + void f(int = []{ return 0; }()); + f(); +} +template void ft3(); +// CHECK: call noundef i32 @"_ZZ1fiENK3$_5clEv" +// CHECK-LABEL: define internal noundef i32 @"_ZZ1fiENK3$_5clEv" + +template +void ft4() { + struct lc { + void mf(int = []{ return 0; }()) {} + }; + lc().mf(); +} +template void ft4(); +// CHECK: call noundef i32 @_ZZZ3ft4IiEvvEN2lc2mfEiEd_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft4IiEvvEN2lc2mfEiEd_NKUlvE_clEv + + // Check linkage of the various lambdas. // CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ11inline_funciENKUlvE_clEv // CHECK: ret i32 1 diff --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp --- a/clang/test/SemaCXX/vartemplate-lambda.cpp +++ b/clang/test/SemaCXX/vartemplate-lambda.cpp @@ -6,7 +6,8 @@ template auto fn1 = [](auto a) { return a + T(1); }; template auto v1 = [](int a = T()) { return a; }(); // expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} -// expected-note@-2{{passing argument to parameter 'a' here}} +// expected-note@-2{{in instantiation of default function argument expression for 'operator()' required here}} +// expected-note@-3{{passing argument to parameter 'a' here}} struct S { template diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp --- a/clang/test/SemaTemplate/default-arguments.cpp +++ b/clang/test/SemaTemplate/default-arguments.cpp @@ -169,7 +169,8 @@ 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}} + int g1(int defarg = T::error); // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} \ + // expected-note {{in instantiation of default function argument expression for 'g1' required here}} } template void f1(); // expected-note{{in instantiation of function template specialization 'NondefDecls::f1' requested here}} } diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp --- a/clang/test/SemaTemplate/instantiate-local-class.cpp +++ b/clang/test/SemaTemplate/instantiate-local-class.cpp @@ -401,7 +401,8 @@ 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}} + void g1(int n = T::error); // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} \ + // expected-note {{in instantiation of default function argument expression for 'g1' required here}} }; } template void f1(); // expected-note{{in instantiation of function template specialization 'PR21332::f1' requested here}} @@ -438,7 +439,8 @@ 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}} + void g1(int n = T::error); // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} \ + // expected-note {{in instantiation of default function argument expression for 'g1' required here}} }; } }; @@ -460,16 +462,18 @@ template void foo() { struct Inner { // expected-note {{in instantiation}} - void operator()(T a = "") {} // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} - // expected-note@-1 {{passing argument to parameter 'a' here}} + void operator()(T a = "") {} // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \ + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ + // expected-note {{passing argument to parameter 'a' here}} }; - Inner()(); // expected-error {{type 'Inner' does not provide a call operator}} + Inner()(); } - template void foo(); // expected-note 2 {{in instantiation}} + template void foo(); // expected-note {{in instantiation}} template void bar() { - auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} - // expected-note@-1 {{passing argument to parameter 'a' here}} + auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \ + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ + // expected-note {{passing argument to parameter 'a' here}} lambda(); } template void bar(); // expected-note {{in instantiation}} @@ -490,7 +494,8 @@ template 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 'std::nullptr_t'}} - // expected-note@-2 {{passing argument to parameter 'x' here}} + // expected-note@-2 {{in instantiation of default function argument expression for 'operator()' required here}} + // expected-note@-3 {{passing argument to parameter 'x' here}} void g() { f(); } // expected-note@-1 {{in instantiation of default function argument expression for 'f' required here}}