@@ -978,34 +978,56 @@ void CodeGenerator::InsertArg(const VarDecl* stmt)
978978
979979bool CodeGenerator::InsertLambdaStaticInvoker (const CXXMethodDecl* cxxMethodDecl)
980980{
981- if (cxxMethodDecl && cxxMethodDecl->isLambdaStaticInvoker ()) {
982- mOutputFormatHelper .AppendNewLine ();
981+ if (not (cxxMethodDecl and cxxMethodDecl->isLambdaStaticInvoker ())) {
982+ return false ;
983+ }
983984
984- const auto * lambda = cxxMethodDecl->getParent ();
985- const auto * callOp = lambda->getLambdaCallOperator ();
986- if (lambda->isGenericLambda () && cxxMethodDecl->isFunctionTemplateSpecialization ()) {
987- const TemplateArgumentList* tal = cxxMethodDecl->getTemplateSpecializationArgs ();
988- FunctionTemplateDecl* callOpTemplate = callOp->getDescribedFunctionTemplate ();
989- void * insertPos = nullptr ;
990- FunctionDecl* correspondingCallOpSpecialization =
991- callOpTemplate->findSpecialization (tal->asArray (), insertPos);
992- callOp = cast<CXXMethodDecl>(correspondingCallOpSpecialization);
993- }
985+ // A special case for a lambda with a static invoker. The standard says, that in such a case invoking the call
986+ // operator gives the same result as invoking the function pointer (see [expr.prim.lambda.closure] p9). When it
987+ // comes to block local statics having a body for both functions reveals a difference. This special code
988+ // generates a forwarding call from the call operator to the static invoker. However, the compiler does better
989+ // here. As this way we end up with copies of the parameters which is hard to avoid.
994990
995- InsertArg (callOp-> getBody () );
996- mOutputFormatHelper .AppendNewLine ();
991+ mOutputFormatHelper . AppendNewLine ( );
992+ mOutputFormatHelper .OpenScope ();
997993
998- return true ;
994+ if (not cxxMethodDecl->getReturnType ()->isVoidType ()) {
995+ mOutputFormatHelper .Append (kwReturn, " " sv);
999996 }
1000997
1001- return false ;
998+ mOutputFormatHelper .Append (GetName (*cxxMethodDecl->getParent ()), " {}.operator()" );
999+
1000+ if (cxxMethodDecl->isFunctionTemplateSpecialization ()) {
1001+ InsertTemplateArgs (*dyn_cast_or_null<FunctionDecl>(cxxMethodDecl));
1002+ }
1003+
1004+ if (cxxMethodDecl->isTemplated ()) {
1005+ if (cxxMethodDecl->getDescribedTemplate ()) {
1006+ InsertTemplateParameters (*cxxMethodDecl->getDescribedTemplate ()->getTemplateParameters (),
1007+ TemplateParamsOnly::Yes);
1008+ }
1009+ /* else if(decl.isFunctionTemplateSpecialization()) {
1010+ InsertTemplateSpecializationHeader();
1011+ }*/
1012+ }
1013+
1014+ WrapInParens ([&] {
1015+ mOutputFormatHelper .AppendParameterList (cxxMethodDecl->parameters (),
1016+ OutputFormatHelper::NameOnly::Yes,
1017+ OutputFormatHelper::GenMissingParamName::Yes);
1018+ });
1019+
1020+ mOutputFormatHelper .AppendSemiNewLine ();
1021+ mOutputFormatHelper .CloseScope (OutputFormatHelper::NoNewLineBefore::Yes);
1022+ mOutputFormatHelper .AppendNewLine ();
1023+
1024+ return true ;
10021025}
10031026// -----------------------------------------------------------------------------
10041027
10051028// / \brief Inserts the instantiation point of a template.
10061029//
10071030// This reveals at which place the template is first used.
1008-
10091031void CodeGenerator::InsertInstantiationPoint (const SourceManager& sm,
10101032 const SourceLocation& instLoc,
10111033 std::string_view text)
@@ -1172,9 +1194,16 @@ static std::string GetTypeConstraintAsString(const TypeConstraint* typeConstrain
11721194}
11731195// -----------------------------------------------------------------------------
11741196
1175- void CodeGenerator::InsertTemplateParameters (const TemplateParameterList& list)
1197+ void CodeGenerator::InsertTemplateParameters (const TemplateParameterList& list,
1198+ const TemplateParamsOnly templateParamsOnly)
11761199{
1177- mOutputFormatHelper .Append (kwTemplate, " <" sv);
1200+ const bool full{TemplateParamsOnly::No == templateParamsOnly};
1201+
1202+ if (full) {
1203+ mOutputFormatHelper .Append (kwTemplate);
1204+ }
1205+
1206+ mOutputFormatHelper .Append (" <" sv);
11781207
11791208 OnceFalse needsComma{};
11801209 for (const auto * param : list) {
@@ -1183,18 +1212,24 @@ void CodeGenerator::InsertTemplateParameters(const TemplateParameterList& list)
11831212 const auto & typeName = GetName (*param);
11841213
11851214 if (const auto * tt = dyn_cast_or_null<TemplateTypeParmDecl>(param)) {
1186- if (tt->wasDeclaredWithTypename ()) {
1187- mOutputFormatHelper .Append (kwTypeNameSpace);
1188- } else if (not tt->hasTypeConstraint ()) {
1189- mOutputFormatHelper .Append (kwClassSpace);
1190- }
1215+ if (full) {
1216+ if (tt->wasDeclaredWithTypename ()) {
1217+ mOutputFormatHelper .Append (kwTypeNameSpace);
1218+ } else if (not tt->hasTypeConstraint ()) {
1219+ mOutputFormatHelper .Append (kwClassSpace);
1220+ }
11911221
1192- if (tt->isParameterPack ()) {
1193- mOutputFormatHelper .Append (kwElipsisSpace);
1222+ if (tt->isParameterPack ()) {
1223+ mOutputFormatHelper .Append (kwElipsisSpace);
1224+ }
11941225 }
11951226
11961227 if (0 == typeName.size () || tt->isImplicit () /* fixes class container:auto*/ ) {
1197- AppendTemplateTypeParamName (mOutputFormatHelper , tt, false );
1228+ AppendTemplateTypeParamName (mOutputFormatHelper , tt, not full);
1229+
1230+ if (not full and tt->isParameterPack ()) {
1231+ mOutputFormatHelper .Append (kwElipsis);
1232+ }
11981233
11991234 } else {
12001235 if (auto typeConstraint = GetTypeConstraintAsString (tt->getTypeConstraint ());
@@ -1232,9 +1267,12 @@ void CodeGenerator::InsertTemplateParameters(const TemplateParameterList& list)
12321267 }
12331268 }
12341269
1235- mOutputFormatHelper .AppendNewLine (" >" sv);
1270+ mOutputFormatHelper .Append (" >" sv);
12361271
1237- InsertConceptConstraint (list);
1272+ if (full) {
1273+ mOutputFormatHelper .AppendNewLine ();
1274+ InsertConceptConstraint (list);
1275+ }
12381276}
12391277// -----------------------------------------------------------------------------
12401278
@@ -3742,6 +3780,10 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
37423780 const bool isClassTemplateSpec{isCXXMethodDecl && isa<ClassTemplateSpecializationDecl>(methodDecl->getParent ())};
37433781 const bool requiresComment{isCXXMethodDecl && not methodDecl->isUserProvided () &&
37443782 not methodDecl->isExplicitlyDefaulted ()};
3783+ // [expr.prim.lambda.closure] p7 consteval/constexpr are obtained from the call operator
3784+ const bool isLambdaStaticInvoker{isCXXMethodDecl and methodDecl->isLambdaStaticInvoker ()};
3785+ const FunctionDecl& constExprDecl{not isLambdaStaticInvoker ? decl
3786+ : *methodDecl->getParent ()->getLambdaCallOperator ()};
37453787
37463788 if (methodDecl) {
37473789 if (requiresComment) {
@@ -3803,9 +3845,22 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
38033845 }
38043846 }
38053847
3806- if (decl.isConstexpr ()) {
3807- if (decl.isConstexprSpecified ()) {
3808- const bool skipConstexpr{isLambda};
3848+ if (constExprDecl.isConstexpr ()) {
3849+ const bool skipConstexpr{isLambda and not isa<CXXConversionDecl>(constExprDecl)};
3850+ // Special treatment for a conversion operator in a captureless lambda. It appears that if the call operator is
3851+ // consteval the conversion operator must be as well, otherwise it cannot take the address of the invoke
3852+ // function.
3853+ const bool isConversionOpWithConstevalCallOp{[&]() {
3854+ if (methodDecl) {
3855+ if (const auto callOp = methodDecl->getParent ()->getLambdaCallOperator ()) {
3856+ return callOp->isConsteval ();
3857+ }
3858+ }
3859+
3860+ return false ;
3861+ }()};
3862+
3863+ if (not isConversionOpWithConstevalCallOp and constExprDecl.isConstexprSpecified ()) {
38093864 if (skipConstexpr) {
38103865 mOutputFormatHelper .Append (kwCommentStart);
38113866 }
@@ -3816,7 +3871,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
38163871 mOutputFormatHelper .Append (kwCCommentEndSpace);
38173872 }
38183873
3819- } else if (decl .isConsteval ()) {
3874+ } else if (isConversionOpWithConstevalCallOp or constExprDecl .isConsteval ()) {
38203875 mOutputFormatHelper .Append (kwConstEvalSpace);
38213876 }
38223877 }
@@ -3847,7 +3902,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
38473902 outputFormatHelper.Append (GetName (decl));
38483903 }
38493904
3850- if (!isLambda && isFirstCxxMethodDecl && decl.isFunctionTemplateSpecialization ()) {
3905+ if (isFirstCxxMethodDecl and decl.isFunctionTemplateSpecialization ()) {
38513906 CodeGenerator codeGenerator{outputFormatHelper};
38523907 codeGenerator.InsertTemplateArgs (decl);
38533908 }
@@ -3861,7 +3916,14 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
38613916 OutputFormatHelper::NameOnly::No,
38623917 OutputFormatHelper::GenMissingParamName::Yes);
38633918 } else {
3864- outputFormatHelper.AppendParameterList (decl.parameters ());
3919+ // The static invoker needs parameter names to foward parameters to the call operator even when the call
3920+ // operator doesn't care about them.
3921+ const OutputFormatHelper::GenMissingParamName genMissingParamName{
3922+ isLambdaStaticInvoker ? OutputFormatHelper::GenMissingParamName::Yes
3923+ : OutputFormatHelper::GenMissingParamName::No};
3924+
3925+ outputFormatHelper.AppendParameterList (
3926+ decl.parameters (), OutputFormatHelper::NameOnly::No, genMissingParamName);
38653927 }
38663928
38673929 if (decl.isVariadic ()) {
0 commit comments