@@ -1215,6 +1215,56 @@ void CodeGenerator::InsertArg(const LinkageSpecDecl* stmt)
1215
1215
}
1216
1216
// -----------------------------------------------------------------------------
1217
1217
1218
+ void CodeGenerator::InsertTemplateArgsObjectParam (const TemplateParamObjectDecl& param)
1219
+ {
1220
+ PrintingPolicy pp{GetGlobalAST ().getLangOpts ()};
1221
+ pp.adjustForCPlusPlus ();
1222
+
1223
+ if (auto varName = GetName (param); not mSeenDecls .contains (varName)) {
1224
+ std::string init{};
1225
+ ::llvm::raw_string_ostream stream{init};
1226
+ param.printAsInit (stream, pp);
1227
+
1228
+ // https://eel.is/c++draft/temp.param#8 says the variable is `static const`. However, to make the
1229
+ // compiler accept the generated code the storage object must be constexpr.
1230
+ // The initialization itself is on the lowest level, int's, floating point or nested structs with them. For
1231
+ // classes this could fail a all fields even the hidden ones are observed. However, for NTTPs the rule is that
1232
+ // only structs/classes with _only_ public data members are accepted.
1233
+ mOutputFormatHelper .AppendSemiNewLine (
1234
+ " static constexpr " , GetName (param.getType ().getUnqualifiedType ()), " " , varName, init);
1235
+ mSeenDecls [varName] = true ;
1236
+ }
1237
+ }
1238
+ // -----------------------------------------------------------------------------
1239
+
1240
+ void CodeGenerator::InsertTemplateArgsObjectParam (const ArrayRef<TemplateArgument>& array)
1241
+ {
1242
+ for (const auto & arg : array) {
1243
+ if (TemplateArgument::Declaration != arg.getKind ()) {
1244
+ continue ;
1245
+ } else if (const auto decl = dyn_cast_or_null<TemplateParamObjectDecl>(arg.getAsDecl ())) {
1246
+ InsertTemplateArgsObjectParam (*decl);
1247
+ }
1248
+ }
1249
+ }
1250
+ // -----------------------------------------------------------------------------
1251
+
1252
+ void CodeGenerator::InsertTemplateSpecializationHeader (const Decl& decl)
1253
+ {
1254
+ if (const auto * fd = dyn_cast_or_null<FunctionDecl>(&decl)) {
1255
+ if (const auto * specArgs = fd->getTemplateSpecializationArgs ()) {
1256
+ InsertTemplateArgsObjectParam (specArgs->asArray ());
1257
+ }
1258
+ } else if (const auto * vd = dyn_cast_or_null<VarTemplateSpecializationDecl>(&decl)) {
1259
+ InsertTemplateArgsObjectParam (vd->getTemplateArgs ().asArray ());
1260
+ } else if (const auto * clsTemplateSpe = dyn_cast_or_null<ClassTemplateSpecializationDecl>(&decl)) {
1261
+ InsertTemplateArgsObjectParam (clsTemplateSpe->getTemplateArgs ().asArray ());
1262
+ }
1263
+
1264
+ mOutputFormatHelper .AppendNewLine (kwTemplate, " <>" sv);
1265
+ }
1266
+ // -----------------------------------------------------------------------------
1267
+
1218
1268
void CodeGenerator::InsertArg (const VarDecl* stmt)
1219
1269
{
1220
1270
if (auto * init = stmt->getInit ();
@@ -1258,7 +1308,7 @@ void CodeGenerator::InsertArg(const VarDecl* stmt)
1258
1308
}
1259
1309
1260
1310
if (isa<VarTemplateSpecializationDecl>(stmt)) {
1261
- InsertTemplateSpecializationHeader ();
1311
+ InsertTemplateSpecializationHeader (*stmt );
1262
1312
} else if (needsGuard) {
1263
1313
mOutputFormatHelper .InsertIfDefTemplateGuard ();
1264
1314
}
@@ -1693,12 +1743,42 @@ static std::string_view EllipsisSpace(bool b)
1693
1743
}
1694
1744
// -----------------------------------------------------------------------------
1695
1745
1746
+ // / \brief Evaluates a potential NTTP as a constant expression.
1747
+ // /
1748
+ // / Used for C++20's struct/class as NTTP.
1749
+ static std::optional<std::pair<QualType, APValue>> EvaluateNTTPAsConstantExpr (const Expr* expr)
1750
+ {
1751
+ expr = expr->IgnoreParenImpCasts ();
1752
+
1753
+ // The marker when it is a C++20 class as NTTP seems to be CXXFunctionalCastExpr
1754
+ if (Expr::EvalResult evalResult{};
1755
+ isa<CXXFunctionalCastExpr>(expr) and
1756
+ expr->EvaluateAsConstantExpr (evalResult, GetGlobalAST (), ConstantExprKind::Normal)) {
1757
+ return std::pair<QualType, APValue>{expr->getType (), evalResult.Val };
1758
+ }
1759
+
1760
+ return {};
1761
+ }
1762
+ // -----------------------------------------------------------------------------
1763
+
1696
1764
void CodeGenerator::InsertTemplateParameters (const TemplateParameterList& list,
1697
1765
const TemplateParamsOnly templateParamsOnly)
1698
1766
{
1699
1767
const bool full{TemplateParamsOnly::No == templateParamsOnly};
1700
1768
1701
1769
if (full) {
1770
+ for (const auto * param : list) {
1771
+ if (const auto * nonTmplParam = dyn_cast_or_null<NonTypeTemplateParmDecl>(param);
1772
+ nonTmplParam and nonTmplParam->hasDefaultArgument ()) {
1773
+ if (auto val =
1774
+ EvaluateNTTPAsConstantExpr (nonTmplParam->getDefaultArgument ().getArgument ().getAsExpr ())) {
1775
+ auto * init = GetGlobalAST ().getTemplateParamObjectDecl (val->first , val->second );
1776
+
1777
+ InsertTemplateArgsObjectParam (*init);
1778
+ }
1779
+ }
1780
+ }
1781
+
1702
1782
mOutputFormatHelper .Append (kwTemplate);
1703
1783
}
1704
1784
@@ -2283,8 +2363,11 @@ void CodeGenerator::InsertArg(const ImplicitCastExpr* stmt)
2283
2363
2284
2364
void CodeGenerator::InsertArg (const DeclRefExpr* stmt)
2285
2365
{
2286
- if (const auto * vd = dyn_cast_or_null<VarDecl>(stmt->getDecl ());
2287
- GetInsightsOptions ().UseShow2C and IsReferenceType (vd)) {
2366
+ if (const auto * tmplObjParam = dyn_cast_or_null<TemplateParamObjectDecl>(stmt->getDecl ())) {
2367
+ mOutputFormatHelper .Append (GetName (*tmplObjParam));
2368
+
2369
+ } else if (const auto * vd = dyn_cast_or_null<VarDecl>(stmt->getDecl ());
2370
+ GetInsightsOptions ().UseShow2C and IsReferenceType (vd)) {
2288
2371
const auto * init = vd->getInit ();
2289
2372
2290
2373
if (const auto * dref = dyn_cast_or_null<DeclRefExpr>(init)) {
@@ -3564,7 +3647,7 @@ void CodeGenerator::InsertArg(const CXXDeductionGuideDecl* stmt)
3564
3647
const auto * deducedTemplate = stmt->getDeducedTemplate ();
3565
3648
3566
3649
if (isSpecialization) {
3567
- InsertTemplateSpecializationHeader ();
3650
+ InsertTemplateSpecializationHeader (*stmt );
3568
3651
} else if (const auto * e = stmt->getDescribedFunctionTemplate ()) {
3569
3652
InsertTemplateParameters (*e->getTemplateParameters ());
3570
3653
}
@@ -3749,7 +3832,7 @@ void CodeGenerator::InsertArg(const CXXRecordDecl* stmt)
3749
3832
if (classTemplatePartialSpecializationDecl) {
3750
3833
InsertTemplateParameters (*classTemplatePartialSpecializationDecl->getTemplateParameters ());
3751
3834
} else {
3752
- InsertTemplateSpecializationHeader ();
3835
+ InsertTemplateSpecializationHeader (*stmt );
3753
3836
}
3754
3837
// Render a out-of-line struct declared inside a class template
3755
3838
} else if (stmt->getLexicalDeclContext () != stmt->getDeclContext ()) {
@@ -4460,7 +4543,11 @@ void CodeGenerator::InsertTemplateArg(const TemplateArgument& arg)
4460
4543
case TemplateArgument::Type: mOutputFormatHelper .Append (GetName (arg.getAsType ())); break ;
4461
4544
case TemplateArgument::Declaration:
4462
4545
// TODO: handle pointers
4463
- mOutputFormatHelper .Append (" &" sv, GetName (*arg.getAsDecl (), QualifiedName::Yes));
4546
+ if (const auto decl = dyn_cast_or_null<TemplateParamObjectDecl>(arg.getAsDecl ())) {
4547
+ mOutputFormatHelper .Append (GetName (*decl));
4548
+ } else {
4549
+ mOutputFormatHelper .Append (" &" sv, GetName (*arg.getAsDecl (), QualifiedName::Yes));
4550
+ }
4464
4551
break ;
4465
4552
case TemplateArgument::NullPtr: mOutputFormatHelper .Append (kwNullptr); break ;
4466
4553
case TemplateArgument::Integral:
@@ -4473,7 +4560,17 @@ void CodeGenerator::InsertTemplateArg(const TemplateArgument& arg)
4473
4560
}
4474
4561
4475
4562
break ;
4476
- case TemplateArgument::Expression: InsertArg (arg.getAsExpr ()); break ;
4563
+ case TemplateArgument::Expression: {
4564
+ if (auto val = EvaluateNTTPAsConstantExpr (arg.getAsExpr ()->IgnoreParenImpCasts ())) {
4565
+ mOutputFormatHelper .Append (
4566
+ GetName (val->first ),
4567
+ BuildTemplateParamObjectName (val->second .getAsString (GetGlobalAST (), val->first )));
4568
+ } else {
4569
+ InsertArg (arg.getAsExpr ());
4570
+ }
4571
+ }
4572
+
4573
+ break ;
4477
4574
case TemplateArgument::Pack: HandleTemplateParameterPack (arg.pack_elements ()); break ;
4478
4575
case TemplateArgument::Template:
4479
4576
mOutputFormatHelper .Append (GetName (*arg.getAsTemplate ().getAsTemplateDecl ()));
@@ -4482,7 +4579,7 @@ void CodeGenerator::InsertTemplateArg(const TemplateArgument& arg)
4482
4579
mOutputFormatHelper .Append (GetName (*arg.getAsTemplateOrTemplatePattern ().getAsTemplateDecl ()));
4483
4580
break ;
4484
4581
case TemplateArgument::Null: mOutputFormatHelper .Append (" null" sv); break ;
4485
- case TemplateArgument::StructuralValue: ToDo (arg, mOutputFormatHelper ); break ;
4582
+ case TemplateArgument::StructuralValue: mOutputFormatHelper . Append (arg. getAsStructuralValue () ); break ;
4486
4583
}
4487
4584
}
4488
4585
// -----------------------------------------------------------------------------
@@ -4733,7 +4830,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
4733
4830
4734
4831
} else if (decl.isFunctionTemplateSpecialization () or (isClassTemplateSpec and decl.isOutOfLine () and
4735
4832
(decl.getLexicalDeclContext () != methodDecl->getParent ()))) {
4736
- InsertTemplateSpecializationHeader ();
4833
+ InsertTemplateSpecializationHeader (decl );
4737
4834
}
4738
4835
4739
4836
InsertAttributes (decl.attrs ());
0 commit comments