From 4409a83c293537e22da046b54e9f69454cdd3dca Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Fri, 6 May 2022 13:55:05 -0700 Subject: [PATCH] [clang] Correct handling of lambdas in lambda default arguments in dependent contexts. Previously, a lambda expression in a dependent context with a default argument containing an immediately invoked lambda expression would produce a closure class object that, if invoked such that the default argument was used, resulted in a compiler crash or one of the following assertion failures during code generation. The failures occurred regardless of whether the lambda expressions were dependent. clang/lib/CodeGen/CGCall.cpp: Assertion `(isGenericMethod || Ty->isVariablyModifiedType() || Ty.getNonReferenceType()->isObjCRetainableType() || getContext() .getCanonicalType(Ty.getNonReferenceType()) .getTypePtr() == getContext().getCanonicalType((*Arg)->getType()).getTypePtr()) && "type mismatch in call argument!"' failed. clang/lib/AST/Decl.cpp: Assertion `!Init->isValueDependent()' failed. Default arguments in declarations in local context are instantiated along with their enclosing function or variable template (since such declarations can't be explicitly specialized). Previously, such instantiations were performed at the same time that their associated parameters were instantiated. However, that approach fails in cases like the following in which the context for the inner lambda is the outer lambda, but construction of the outer lambda is dependent on the parameters of the inner lambda. This change resolves this dependency by delyaing instantiation of default arguments in local contexts until after construction of the enclosing context. template auto f() { return [](T = []{ return T{}; }()) { return 0; }; } Refactoring included with this change results in the same code now being used to instantiate default arguments that appear in local context and those that are only instantiated when used at a call site; previously, such code was duplicated and out of sync. Fixes https://github.com/llvm/llvm-project/issues/49178 Reviewed By: erichkeane Differential Revision: https://reviews.llvm.org/D133500 --- clang/include/clang/Sema/Sema.h | 3 + clang/lib/AST/DeclBase.cpp | 8 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 146 +++++++++++++++++---- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 125 ++++++++++-------- .../expr.prim.lambda/default-arguments.cpp | 12 +- clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp | 38 ++++++ clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp | 29 ++++ clang/test/CodeGenCXX/mangle-lambdas.cpp | 78 +++++++++++ clang/test/SemaCXX/vartemplate-lambda.cpp | 3 +- clang/test/SemaTemplate/default-arguments.cpp | 3 +- .../test/SemaTemplate/instantiate-local-class.cpp | 23 ++-- 11 files changed, 362 insertions(+), 106 deletions(-) create mode 100644 clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp create mode 100644 clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 74735fb..ce6f67a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9782,6 +9782,9 @@ public: 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 index a9ac441..763fc1d 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -261,12 +261,12 @@ const TemplateParameterList *Decl::getDescribedTemplateParams() const { 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 index c6eb034..21b141f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -179,11 +179,11 @@ Response HandleFunction(const FunctionDecl *Function, (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && "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())) { return Response::ChangeDecl(Function->getLexicalDeclContext()); @@ -1270,8 +1270,30 @@ namespace { 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) { @@ -2595,29 +2617,17 @@ Sema::SubstParmVarDecl(ParmVarDecl *OldParm, 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()); @@ -2662,6 +2672,88 @@ bool Sema::SubstParmTypes( 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 index 9fcc165..b50ed64 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2003,7 +2003,7 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context, /// 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 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( assert(D->getDeclContext()->isFileContext()); LexicalDC = D->getDeclContext(); } + else if (D->isLocalExternDecl()) { + LexicalDC = SemaRef.CurContext; + } Function->setLexicalDeclContext(LexicalDC); @@ -2275,6 +2278,37 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( 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 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( 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::addInstantiatedParametersToScope( 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 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, 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 index 3e28288..72265d7 100644 --- 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 @@ struct NoDefaultCtor { 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_unused(NoDefaultCtor); // expected-note{{in i 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 index 0000000..5049356 --- /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 index 0000000..0e080e7 --- /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 index ab6c90a..063b989 100644 --- a/clang/test/CodeGenCXX/mangle-lambdas.cpp +++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp @@ -210,6 +210,84 @@ inline int testVarargsLambdaNumbering() { } 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 index 3546193..8b232ab 100644 --- a/clang/test/SemaCXX/vartemplate-lambda.cpp +++ b/clang/test/SemaCXX/vartemplate-lambda.cpp @@ -6,7 +6,8 @@ template void foo0() { fn0(); } 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 index 882b279..a850d27 100644 --- a/clang/test/SemaTemplate/default-arguments.cpp +++ b/clang/test/SemaTemplate/default-arguments.cpp @@ -169,7 +169,8 @@ namespace DR1635 { 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 index e51c711..f0f3d2b 100644 --- a/clang/test/SemaTemplate/instantiate-local-class.cpp +++ b/clang/test/SemaTemplate/instantiate-local-class.cpp @@ -401,7 +401,8 @@ 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}} + 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 @@ namespace PR21332 { 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 @@ namespace rdar23721638 { 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 @@ namespace PR45000 { 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}} -- 2.7.4