[clang] 4409a83 - [clang] Correct handling of lambdas in lambda default arguments in dependent contexts.
Tom Honermann via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 4 09:09:02 PDT 2022
Author: Tom Honermann
Date: 2022-10-04T09:04:54-07:00
New Revision: 4409a83c293537e22da046b54e9f69454cdd3dca
URL: https://github.com/llvm/llvm-project/commit/4409a83c293537e22da046b54e9f69454cdd3dca
DIFF: https://github.com/llvm/llvm-project/commit/4409a83c293537e22da046b54e9f69454cdd3dca.diff
LOG: [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 <typename T>
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
Added:
clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp
clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp
Modified:
clang/include/clang/Sema/Sema.h
clang/lib/AST/DeclBase.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
clang/test/CodeGenCXX/mangle-lambdas.cpp
clang/test/SemaCXX/vartemplate-lambda.cpp
clang/test/SemaTemplate/default-arguments.cpp
clang/test/SemaTemplate/instantiate-local-class.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 74735fb8d07c1..ce6f67ad19af6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9782,6 +9782,9 @@ class Sema final {
SmallVectorImpl<QualType> &ParamTypes,
SmallVectorImpl<ParmVarDecl *> *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 a9ac441092be0..763fc1d9f17fb 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<DeclContext>(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 c6eb034e43708..21b141f96a695 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<TemplateInstantiator> RAII(*this);
- ExprResult Res = inherited::TransformLambdaExpr(E);
- return Res;
+ ExprResult Result = inherited::TransformLambdaExpr(E);
+ if (Result.isInvalid())
+ return Result;
+
+ CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->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<FunctionDecl>(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<Expr>(), 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 <typename T>
+ // 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<FunctionDecl>(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<LocalInstantiationScope> 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<typename T> void f(T a, int = decltype(a)());
+ // void g() { f(0); }
+ LIS = std::make_unique<LocalInstantiationScope>(*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<Expr>();
+
+ InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
+ Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
+ if (Result.isInvalid())
+ return true;
+
+ Result =
+ ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
+ /*DiscardedValue*/ false);
+ } else {
+ // FIXME: Obtain the source location for the '=' token.
+ SourceLocation EqualLoc = PatternExpr->getBeginLoc();
+ Result = ConvertParamDefaultArgument(Param, Result.getAs<Expr>(), EqualLoc);
+ }
+ if (Result.isInvalid())
+ return true;
+
+ // Remember the instantiated default argument.
+ Param->setDefaultArg(Result.getAs<Expr>());
+
+ 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 9fcc165e8dc7e..b50ed6478e4b4 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<typename T>
+ // void ft() {
+ // void f(int = []{ return T::value; }());
+ // }
+ // template void ft<int>(); // error: type 'int' cannot be used prior
+ // to '::' because it has no members
+ //
+ // The error is issued during instantiation of ft<int>() 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<typename T>
+ // void ft() {
+ // struct lc {
+ // int operator()(int p = []{ return T::value; }());
+ // };
+ // }
+ // template void ft<int>(); // error: type 'int' cannot be used prior
+ // to '::'because it has no members
+ //
+ // The error is issued during instantiation of ft<int>()::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<Expr>();
-
- InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
- Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
- if (Result.isInvalid())
- return true;
-
- Result =
- ActOnFinishFullExpr(Result.getAs<Expr>(), 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<Expr>());
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 3e28288fb82ad..72265d77700aa 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<typename T>
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()<NoDefaultCtor>' required here}}
l1(t);
}
@@ -44,13 +45,8 @@ template void defargs_in_template_unused(NoDefaultCtor); // expected-note{{in i
template<typename T>
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 at 46{{conversion candidate of type 'void (*)(const NoDefaultCtor &) __attribute__((thiscall))'}}
-#else
- // expected-note at 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()<NoDefaultCtor>' required here}}
+ l1();
}
template void defargs_in_template_used<NonPOD>();
diff --git a/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp b/clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp
new file mode 100644
index 0000000000000..5049356bd7356
--- /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<typename T = int>
+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 <typename T>
+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<int>()();
+}
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ3ft2IiEDavENK1SclEi
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft2IiEDavENK1SclEiEd_NKUlvE_clEv
+
+template <typename>
+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<int>();
+}
+// 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 0000000000000..0e080e789948c
--- /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 <typename T>
+auto ft1() {
+ return []<typename U = T>(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<int>()();
+}
+// 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 <typename T>
+auto vt1 = []<typename U = T>(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<int>();
+}
+// 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 ab6c90a6a531a..063b9890b0578 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<typename = int>
+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<typename = int>
+ 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<typename = int>
+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<typename = int>
+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<typename>
+void ft3() {
+ void f(int = []{ return 0; }());
+ f();
+}
+template void ft3<int>();
+// CHECK: call noundef i32 @"_ZZ1fiENK3$_5clEv"
+// CHECK-LABEL: define internal noundef i32 @"_ZZ1fiENK3$_5clEv"
+
+template<typename>
+void ft4() {
+ struct lc {
+ void mf(int = []{ return 0; }()) {}
+ };
+ lc().mf();
+}
+template void ft4<int>();
+// 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 3546193c67d34..8b232abe976b6 100644
--- a/clang/test/SemaCXX/vartemplate-lambda.cpp
+++ b/clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -6,7 +6,8 @@ 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()) { return a; }();
// expected-error at -1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
-// expected-note at -2{{passing argument to parameter 'a' here}}
+// expected-note at -2{{in instantiation of default function argument expression for 'operator()<int *>' required here}}
+// expected-note at -3{{passing argument to parameter 'a' here}}
struct S {
template<class T>
diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp
index 882b279de1d08..a850d273ccba5 100644
--- a/clang/test/SemaTemplate/default-arguments.cpp
+++ b/clang/test/SemaTemplate/default-arguments.cpp
@@ -169,7 +169,8 @@ namespace DR1635 {
namespace NondefDecls {
template<typename T> 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<int>' required here}}
}
template void f1<int>(); // expected-note{{in instantiation of function template specialization 'NondefDecls::f1<int>' requested here}}
}
diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp
index e51c7116ee74d..f0f3d2b146b67 100644
--- a/clang/test/SemaTemplate/instantiate-local-class.cpp
+++ b/clang/test/SemaTemplate/instantiate-local-class.cpp
@@ -401,7 +401,8 @@ void g() { f<void>(); }
namespace PR21332 {
template<typename T> 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<int>' required here}}
};
}
template void f1<int>(); // expected-note{{in instantiation of function template specialization 'PR21332::f1<int>' 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<int>' required here}}
};
}
};
@@ -460,16 +462,18 @@ namespace rdar23721638 {
template <typename T> 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 at -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()<rdar23721638::A>' 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<A>(); // expected-note 2 {{in instantiation}}
+ template void foo<A>(); // expected-note {{in instantiation}}
template <typename T> void bar() {
- auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}}
- // expected-note at -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()<rdar23721638::A>' required here}} \
+ // expected-note {{passing argument to parameter 'a' here}}
lambda();
}
template void bar<A>(); // expected-note {{in instantiation}}
@@ -490,7 +494,8 @@ namespace PR45000 {
template <typename T>
void f(int x = [](T x = nullptr) -> int { return x; }());
// expected-error at -1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}}
- // expected-note at -2 {{passing argument to parameter 'x' here}}
+ // expected-note at -2 {{in instantiation of default function argument expression for 'operator()<int>' required here}}
+ // expected-note at -3 {{passing argument to parameter 'x' here}}
void g() { f<int>(); }
// expected-note at -1 {{in instantiation of default function argument expression for 'f<int>' required here}}
More information about the cfe-commits
mailing list