@@ -978,34 +978,56 @@ void CodeGenerator::InsertArg(const VarDecl* stmt)
978
978
979
979
bool CodeGenerator::InsertLambdaStaticInvoker (const CXXMethodDecl* cxxMethodDecl)
980
980
{
981
- if (cxxMethodDecl && cxxMethodDecl->isLambdaStaticInvoker ()) {
982
- mOutputFormatHelper .AppendNewLine ();
981
+ if (not (cxxMethodDecl and cxxMethodDecl->isLambdaStaticInvoker ())) {
982
+ return false ;
983
+ }
983
984
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.
994
990
995
- InsertArg (callOp-> getBody () );
996
- mOutputFormatHelper .AppendNewLine ();
991
+ mOutputFormatHelper . AppendNewLine ( );
992
+ mOutputFormatHelper .OpenScope ();
997
993
998
- return true ;
994
+ if (not cxxMethodDecl->getReturnType ()->isVoidType ()) {
995
+ mOutputFormatHelper .Append (kwReturn, " " sv);
999
996
}
1000
997
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 ;
1002
1025
}
1003
1026
// -----------------------------------------------------------------------------
1004
1027
1005
1028
// / \brief Inserts the instantiation point of a template.
1006
1029
//
1007
1030
// This reveals at which place the template is first used.
1008
-
1009
1031
void CodeGenerator::InsertInstantiationPoint (const SourceManager& sm,
1010
1032
const SourceLocation& instLoc,
1011
1033
std::string_view text)
@@ -1172,9 +1194,16 @@ static std::string GetTypeConstraintAsString(const TypeConstraint* typeConstrain
1172
1194
}
1173
1195
// -----------------------------------------------------------------------------
1174
1196
1175
- void CodeGenerator::InsertTemplateParameters (const TemplateParameterList& list)
1197
+ void CodeGenerator::InsertTemplateParameters (const TemplateParameterList& list,
1198
+ const TemplateParamsOnly templateParamsOnly)
1176
1199
{
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);
1178
1207
1179
1208
OnceFalse needsComma{};
1180
1209
for (const auto * param : list) {
@@ -1183,18 +1212,24 @@ void CodeGenerator::InsertTemplateParameters(const TemplateParameterList& list)
1183
1212
const auto & typeName = GetName (*param);
1184
1213
1185
1214
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
+ }
1191
1221
1192
- if (tt->isParameterPack ()) {
1193
- mOutputFormatHelper .Append (kwElipsisSpace);
1222
+ if (tt->isParameterPack ()) {
1223
+ mOutputFormatHelper .Append (kwElipsisSpace);
1224
+ }
1194
1225
}
1195
1226
1196
1227
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
+ }
1198
1233
1199
1234
} else {
1200
1235
if (auto typeConstraint = GetTypeConstraintAsString (tt->getTypeConstraint ());
@@ -1232,9 +1267,12 @@ void CodeGenerator::InsertTemplateParameters(const TemplateParameterList& list)
1232
1267
}
1233
1268
}
1234
1269
1235
- mOutputFormatHelper .AppendNewLine (" >" sv);
1270
+ mOutputFormatHelper .Append (" >" sv);
1236
1271
1237
- InsertConceptConstraint (list);
1272
+ if (full) {
1273
+ mOutputFormatHelper .AppendNewLine ();
1274
+ InsertConceptConstraint (list);
1275
+ }
1238
1276
}
1239
1277
// -----------------------------------------------------------------------------
1240
1278
@@ -3742,6 +3780,10 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
3742
3780
const bool isClassTemplateSpec{isCXXMethodDecl && isa<ClassTemplateSpecializationDecl>(methodDecl->getParent ())};
3743
3781
const bool requiresComment{isCXXMethodDecl && not methodDecl->isUserProvided () &&
3744
3782
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 ()};
3745
3787
3746
3788
if (methodDecl) {
3747
3789
if (requiresComment) {
@@ -3803,9 +3845,22 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
3803
3845
}
3804
3846
}
3805
3847
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 ()) {
3809
3864
if (skipConstexpr) {
3810
3865
mOutputFormatHelper .Append (kwCommentStart);
3811
3866
}
@@ -3816,7 +3871,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
3816
3871
mOutputFormatHelper .Append (kwCCommentEndSpace);
3817
3872
}
3818
3873
3819
- } else if (decl .isConsteval ()) {
3874
+ } else if (isConversionOpWithConstevalCallOp or constExprDecl .isConsteval ()) {
3820
3875
mOutputFormatHelper .Append (kwConstEvalSpace);
3821
3876
}
3822
3877
}
@@ -3847,7 +3902,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
3847
3902
outputFormatHelper.Append (GetName (decl));
3848
3903
}
3849
3904
3850
- if (!isLambda && isFirstCxxMethodDecl && decl.isFunctionTemplateSpecialization ()) {
3905
+ if (isFirstCxxMethodDecl and decl.isFunctionTemplateSpecialization ()) {
3851
3906
CodeGenerator codeGenerator{outputFormatHelper};
3852
3907
codeGenerator.InsertTemplateArgs (decl);
3853
3908
}
@@ -3861,7 +3916,14 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
3861
3916
OutputFormatHelper::NameOnly::No,
3862
3917
OutputFormatHelper::GenMissingParamName::Yes);
3863
3918
} 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);
3865
3927
}
3866
3928
3867
3929
if (decl.isVariadic ()) {
0 commit comments