@@ -1215,6 +1215,56 @@ void CodeGenerator::InsertArg(const LinkageSpecDecl* stmt)
12151215}
12161216// -----------------------------------------------------------------------------
12171217
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+
12181268void CodeGenerator::InsertArg (const VarDecl* stmt)
12191269{
12201270 if (auto * init = stmt->getInit ();
@@ -1258,7 +1308,7 @@ void CodeGenerator::InsertArg(const VarDecl* stmt)
12581308 }
12591309
12601310 if (isa<VarTemplateSpecializationDecl>(stmt)) {
1261- InsertTemplateSpecializationHeader ();
1311+ InsertTemplateSpecializationHeader (*stmt );
12621312 } else if (needsGuard) {
12631313 mOutputFormatHelper .InsertIfDefTemplateGuard ();
12641314 }
@@ -1693,12 +1743,42 @@ static std::string_view EllipsisSpace(bool b)
16931743}
16941744// -----------------------------------------------------------------------------
16951745
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+
16961764void CodeGenerator::InsertTemplateParameters (const TemplateParameterList& list,
16971765 const TemplateParamsOnly templateParamsOnly)
16981766{
16991767 const bool full{TemplateParamsOnly::No == templateParamsOnly};
17001768
17011769 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+
17021782 mOutputFormatHelper .Append (kwTemplate);
17031783 }
17041784
@@ -2283,8 +2363,11 @@ void CodeGenerator::InsertArg(const ImplicitCastExpr* stmt)
22832363
22842364void CodeGenerator::InsertArg (const DeclRefExpr* stmt)
22852365{
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)) {
22882371 const auto * init = vd->getInit ();
22892372
22902373 if (const auto * dref = dyn_cast_or_null<DeclRefExpr>(init)) {
@@ -3564,7 +3647,7 @@ void CodeGenerator::InsertArg(const CXXDeductionGuideDecl* stmt)
35643647 const auto * deducedTemplate = stmt->getDeducedTemplate ();
35653648
35663649 if (isSpecialization) {
3567- InsertTemplateSpecializationHeader ();
3650+ InsertTemplateSpecializationHeader (*stmt );
35683651 } else if (const auto * e = stmt->getDescribedFunctionTemplate ()) {
35693652 InsertTemplateParameters (*e->getTemplateParameters ());
35703653 }
@@ -3749,7 +3832,7 @@ void CodeGenerator::InsertArg(const CXXRecordDecl* stmt)
37493832 if (classTemplatePartialSpecializationDecl) {
37503833 InsertTemplateParameters (*classTemplatePartialSpecializationDecl->getTemplateParameters ());
37513834 } else {
3752- InsertTemplateSpecializationHeader ();
3835+ InsertTemplateSpecializationHeader (*stmt );
37533836 }
37543837 // Render a out-of-line struct declared inside a class template
37553838 } else if (stmt->getLexicalDeclContext () != stmt->getDeclContext ()) {
@@ -4460,7 +4543,11 @@ void CodeGenerator::InsertTemplateArg(const TemplateArgument& arg)
44604543 case TemplateArgument::Type: mOutputFormatHelper .Append (GetName (arg.getAsType ())); break ;
44614544 case TemplateArgument::Declaration:
44624545 // 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+ }
44644551 break ;
44654552 case TemplateArgument::NullPtr: mOutputFormatHelper .Append (kwNullptr); break ;
44664553 case TemplateArgument::Integral:
@@ -4473,7 +4560,17 @@ void CodeGenerator::InsertTemplateArg(const TemplateArgument& arg)
44734560 }
44744561
44754562 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 ;
44774574 case TemplateArgument::Pack: HandleTemplateParameterPack (arg.pack_elements ()); break ;
44784575 case TemplateArgument::Template:
44794576 mOutputFormatHelper .Append (GetName (*arg.getAsTemplate ().getAsTemplateDecl ()));
@@ -4482,7 +4579,7 @@ void CodeGenerator::InsertTemplateArg(const TemplateArgument& arg)
44824579 mOutputFormatHelper .Append (GetName (*arg.getAsTemplateOrTemplatePattern ().getAsTemplateDecl ()));
44834580 break ;
44844581 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 ;
44864583 }
44874584}
44884585// -----------------------------------------------------------------------------
@@ -4733,7 +4830,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d
47334830
47344831 } else if (decl.isFunctionTemplateSpecialization () or (isClassTemplateSpec and decl.isOutOfLine () and
47354832 (decl.getLexicalDeclContext () != methodDecl->getParent ()))) {
4736- InsertTemplateSpecializationHeader ();
4833+ InsertTemplateSpecializationHeader (decl );
47374834 }
47384835
47394836 InsertAttributes (decl.attrs ());
0 commit comments