Skip to content

Commit 9e08e51

Browse files
committed
[c++20] P1907R1: Support for generalized non-type template arguments of scalar type.
1 parent 333d41e commit 9e08e51

36 files changed

+621
-188
lines changed

clang/include/clang/AST/PropertiesBase.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class CountPropertyType<string typeName = ""> : PropertyType<typeName> {
7272

7373
def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
7474
def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
75+
def APValue : PropertyType { let PassByReference = 1; }
7576
def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
7677
def AttrKind : EnumPropertyType<"attr::Kind">;
7778
def AutoTypeKeyword : EnumPropertyType;
@@ -450,6 +451,17 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
450451
return TemplateArgument(ctx, value, type);
451452
}]>;
452453
}
454+
let Class = PropertyTypeCase<TemplateArgument, "UncommonValue"> in {
455+
def : Property<"value", APValue> {
456+
let Read = [{ node.getAsUncommonValue() }];
457+
}
458+
def : Property<"type", QualType> {
459+
let Read = [{ node.getUncommonValueType() }];
460+
}
461+
def : Creator<[{
462+
return TemplateArgument(ctx, type, value);
463+
}]>;
464+
}
453465
let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
454466
def : Property<"name", TemplateName> {
455467
let Read = [{ node.getAsTemplateOrTemplatePattern() }];

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
767767
case TemplateArgument::Declaration:
768768
case TemplateArgument::Integral:
769769
case TemplateArgument::NullPtr:
770+
case TemplateArgument::UncommonValue:
770771
return true;
771772

772773
case TemplateArgument::Type:
@@ -800,6 +801,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
800801
case TemplateArgument::Declaration:
801802
case TemplateArgument::Integral:
802803
case TemplateArgument::NullPtr:
804+
case TemplateArgument::UncommonValue:
803805
return true;
804806

805807
case TemplateArgument::Type: {

clang/include/clang/AST/TemplateArgumentVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class Base {
3737
DISPATCH(Declaration);
3838
DISPATCH(NullPtr);
3939
DISPATCH(Integral);
40+
DISPATCH(UncommonValue);
4041
DISPATCH(Template);
4142
DISPATCH(TemplateExpansion);
4243
DISPATCH(Expression);
@@ -59,6 +60,7 @@ class Base {
5960
VISIT_METHOD(Declaration);
6061
VISIT_METHOD(NullPtr);
6162
VISIT_METHOD(Integral);
63+
VISIT_METHOD(UncommonValue);
6264
VISIT_METHOD(Template);
6365
VISIT_METHOD(TemplateExpansion);
6466
VISIT_METHOD(Expression);

clang/include/clang/AST/TemplateBase.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ template <> struct PointerLikeTypeTraits<clang::Expr *> {
5151

5252
namespace clang {
5353

54+
class APValue;
5455
class ASTContext;
5556
class DiagnosticBuilder;
5657
class Expr;
@@ -82,6 +83,12 @@ class TemplateArgument {
8283
/// that was provided for an integral non-type template parameter.
8384
Integral,
8485

86+
/// The template argument is a non-type template argument that can't be
87+
/// represented by the special-case Declaration, NullPtr, or Integral
88+
/// forms. These values are only ever produced by constant evaluation,
89+
/// so cannot be dependent.
90+
UncommonValue,
91+
8592
/// The template argument is a template name that was provided for a
8693
/// template template parameter.
8794
Template,
@@ -125,6 +132,11 @@ class TemplateArgument {
125132
};
126133
void *Type;
127134
};
135+
struct V {
136+
unsigned Kind;
137+
const APValue *Value;
138+
void *Type;
139+
};
128140
struct A {
129141
unsigned Kind;
130142
unsigned NumArgs;
@@ -142,6 +154,7 @@ class TemplateArgument {
142154
union {
143155
struct DA DeclArg;
144156
struct I Integer;
157+
struct V Value;
145158
struct A Args;
146159
struct TA TemplateArg;
147160
struct TV TypeOrValue;
@@ -157,9 +170,8 @@ class TemplateArgument {
157170
TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
158171
}
159172

160-
/// Construct a template argument that refers to a
161-
/// declaration, which is either an external declaration or a
162-
/// template declaration.
173+
/// Construct a template argument that refers to a (non-dependent)
174+
/// declaration.
163175
TemplateArgument(ValueDecl *D, QualType QT) {
164176
assert(D && "Expected decl");
165177
DeclArg.Kind = Declaration;
@@ -169,7 +181,11 @@ class TemplateArgument {
169181

170182
/// Construct an integral constant template argument. The memory to
171183
/// store the value is allocated with Ctx.
172-
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
184+
TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value,
185+
QualType Type);
186+
187+
/// Construct a template argument from an arbitrary constant value.
188+
TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value);
173189

174190
/// Construct an integral constant template argument with the same
175191
/// value as Other but a different type.
@@ -340,6 +356,16 @@ class TemplateArgument {
340356
Integer.Type = T.getAsOpaquePtr();
341357
}
342358

359+
/// Get the value of an UncommonValue.
360+
const APValue &getAsUncommonValue() const {
361+
return *Value.Value;
362+
}
363+
364+
/// Get the type of an UncommonValue.
365+
QualType getUncommonValueType() const {
366+
return QualType::getFromOpaquePtr(Value.Type);
367+
}
368+
343369
/// If this is a non-type template argument, get its type. Otherwise,
344370
/// returns a null QualType.
345371
QualType getNonTypeTemplateArgumentType() const;
@@ -484,6 +510,7 @@ class TemplateArgumentLoc {
484510
assert(Argument.getKind() == TemplateArgument::NullPtr ||
485511
Argument.getKind() == TemplateArgument::Integral ||
486512
Argument.getKind() == TemplateArgument::Declaration ||
513+
Argument.getKind() == TemplateArgument::UncommonValue ||
487514
Argument.getKind() == TemplateArgument::Expression);
488515
}
489516

@@ -542,6 +569,11 @@ class TemplateArgumentLoc {
542569
return LocInfo.getAsExpr();
543570
}
544571

572+
Expr *getSourceUncommonValueExpression() const {
573+
assert(Argument.getKind() == TemplateArgument::UncommonValue);
574+
return LocInfo.getAsExpr();
575+
}
576+
545577
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
546578
if (Argument.getKind() != TemplateArgument::Template &&
547579
Argument.getKind() != TemplateArgument::TemplateExpansion)

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4656,8 +4656,6 @@ def err_non_type_template_arg_subobject : Error<
46564656
"non-type template argument refers to subobject '%0'">;
46574657
def err_non_type_template_arg_addr_label_diff : Error<
46584658
"template argument / label address difference / what did you expect?">;
4659-
def err_non_type_template_arg_unsupported : Error<
4660-
"sorry, non-type template argument of type %0 is not yet supported">;
46614659
def err_template_arg_not_convertible : Error<
46624660
"non-type template argument of type %0 cannot be converted to a value "
46634661
"of type %1">;
@@ -4709,9 +4707,6 @@ def err_template_arg_not_object_or_func : Error<
47094707
"non-type template argument does not refer to an object or function">;
47104708
def err_template_arg_not_pointer_to_member_form : Error<
47114709
"non-type template argument is not a pointer to member constant">;
4712-
def err_template_arg_member_ptr_base_derived_not_supported : Error<
4713-
"sorry, non-type template argument of pointer-to-member type %1 that refers "
4714-
"to member %q0 of a different class is not supported yet">;
47154710
def ext_template_arg_extra_parens : ExtWarn<
47164711
"address non-type template argument cannot be surrounded by parentheses">;
47174712
def warn_cxx98_compat_template_arg_extra_parens : Warning<

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7623,8 +7623,8 @@ class Sema final {
76237623
QualType ParamType,
76247624
SourceLocation Loc);
76257625
ExprResult
7626-
BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
7627-
SourceLocation Loc);
7626+
BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
7627+
SourceLocation Loc);
76287628

76297629
/// Enumeration describing how template parameter lists are compared
76307630
/// for equality.

clang/include/clang/Serialization/ASTRecordWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ class ASTRecordWriter
166166

167167
/// Emit an APvalue.
168168
void AddAPValue(const APValue &Value);
169+
void writeAPValue(const APValue &Value) { AddAPValue(Value); }
169170

170171
/// Emit a reference to an identifier.
171172
void AddIdentifierRef(const IdentifierInfo *II) {

clang/lib/AST/ASTContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5941,6 +5941,11 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
59415941
case TemplateArgument::Integral:
59425942
return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType()));
59435943

5944+
case TemplateArgument::UncommonValue:
5945+
return TemplateArgument(*this,
5946+
getCanonicalType(Arg.getUncommonValueType()),
5947+
Arg.getAsUncommonValue());
5948+
59445949
case TemplateArgument::Type:
59455950
return TemplateArgument(getCanonicalType(Arg.getAsType()));
59465951

clang/lib/AST/ASTImporter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,17 @@ ASTNodeImporter::import(const TemplateArgument &From) {
808808
return TemplateArgument(*ToTypeOrErr, /*isNullPtr*/true);
809809
}
810810

811+
case TemplateArgument::UncommonValue: {
812+
ExpectedType ToTypeOrErr = import(From.getUncommonValueType());
813+
if (!ToTypeOrErr)
814+
return ToTypeOrErr.takeError();
815+
Expected<APValue> ToValueOrErr = import(From.getAsUncommonValue());
816+
if (!ToValueOrErr)
817+
return ToValueOrErr.takeError();
818+
return TemplateArgument(Importer.getToContext(), *ToTypeOrErr,
819+
*ToValueOrErr);
820+
}
821+
811822
case TemplateArgument::Template: {
812823
Expected<TemplateName> ToTemplateOrErr = import(From.getAsTemplate());
813824
if (!ToTemplateOrErr)

clang/lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
565565
return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
566566
Arg2.getAsExpr());
567567

568+
case TemplateArgument::UncommonValue:
569+
// FIXME: Do we need to customize the comparison?
570+
return Arg1.structurallyEquals(Arg2);
571+
568572
case TemplateArgument::Pack:
569573
if (Arg1.pack_size() != Arg2.pack_size())
570574
return false;

clang/lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
342342
LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType()));
343343
continue;
344344

345+
case TemplateArgument::UncommonValue:
346+
LV.merge(getLVForValue(Arg.getAsUncommonValue(), computation));
347+
continue;
348+
345349
case TemplateArgument::Template:
346350
case TemplateArgument::TemplateExpansion:
347351
if (TemplateDecl *Template =

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4079,10 +4079,28 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
40794079
mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
40804080
break;
40814081

4082-
case Expr::SubstNonTypeTemplateParmExprClass:
4083-
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
4084-
Arity);
4082+
case Expr::SubstNonTypeTemplateParmExprClass: {
4083+
// Mangle a substituted parameter the same way we mangle the template
4084+
// argument.
4085+
// As proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/111.
4086+
auto *SNTTPE = cast<SubstNonTypeTemplateParmExpr>(E);
4087+
if (auto *CE = dyn_cast<ConstantExpr>(SNTTPE->getReplacement())) {
4088+
// Pull out the constant value and mangle it as a template argument.
4089+
QualType ParamType = SNTTPE->getParameterType(Context.getASTContext());
4090+
if (CE->hasAPValueResult())
4091+
mangleValueInTemplateArg(ParamType, CE->getResultAsAPValue(), false,
4092+
/*NeedExactType=*/true);
4093+
else
4094+
mangleValueInTemplateArg(ParamType, CE->getAPValueResult(), false,
4095+
/*NeedExactType=*/true);
4096+
} else {
4097+
// The remaining cases all happen to be substituted with expressions that
4098+
// mangle the same as a corresponding template argument anyway.
4099+
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
4100+
Arity);
4101+
}
40854102
break;
4103+
}
40864104

40874105
case Expr::UserDefinedLiteralClass:
40884106
// We follow g++'s approach of mangling a UDL as a call to the literal
@@ -5039,6 +5057,10 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
50395057
mangleNullPointer(A.getNullPtrType());
50405058
break;
50415059
}
5060+
case TemplateArgument::UncommonValue:
5061+
mangleValueInTemplateArg(A.getUncommonValueType(), A.getAsUncommonValue(),
5062+
/*TopLevel=*/true, NeedExactType);
5063+
break;
50425064
case TemplateArgument::Pack: {
50435065
// <template-arg> ::= J <template-arg>* E
50445066
Out << 'J';
@@ -5373,7 +5395,20 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
53735395
Out << "plcvPcad";
53745396
Kind = Offset;
53755397
} else {
5376-
if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) {
5398+
// Clang 11 and before mangled an array subject to array-to-pointer decay
5399+
// as if it were the declaration itself.
5400+
bool IsArrayToPointerDecayMangledAsDecl = false;
5401+
if (TopLevel && Ctx.getLangOpts().getClangABICompat() <=
5402+
LangOptions::ClangABI::Ver11) {
5403+
QualType BType = B.getType();
5404+
IsArrayToPointerDecayMangledAsDecl =
5405+
BType->isArrayType() && V.getLValuePath().size() == 1 &&
5406+
V.getLValuePath()[0].getAsArrayIndex() == 0 &&
5407+
Ctx.hasSimilarType(T, Ctx.getDecayedType(BType));
5408+
}
5409+
5410+
if ((!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) &&
5411+
!IsArrayToPointerDecayMangledAsDecl) {
53775412
NotPrimaryExpr();
53785413
// A final conversion to the template parameter's type is usually
53795414
// folded into the 'so' mangling, but we can't do that for 'void*'

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,17 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
15751575
cast<NonTypeTemplateParmDecl>(Parm), T);
15761576
break;
15771577
}
1578+
case TemplateArgument::UncommonValue:
1579+
Out << "$";
1580+
if (cast<NonTypeTemplateParmDecl>(Parm)
1581+
->getType()
1582+
->getContainedDeducedType()) {
1583+
Out << "M";
1584+
mangleType(TA.getNonTypeTemplateArgumentType(), SourceRange(), QMM_Drop);
1585+
}
1586+
mangleTemplateArgValue(TA.getUncommonValueType(), TA.getAsUncommonValue(),
1587+
/*WithScalarType=*/false);
1588+
break;
15781589
case TemplateArgument::Expression:
15791590
mangleExpression(TA.getAsExpr(), cast<NonTypeTemplateParmDecl>(Parm));
15801591
break;

clang/lib/AST/ODRHash.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) {
169169
break;
170170
case TemplateArgument::NullPtr:
171171
case TemplateArgument::Integral:
172+
case TemplateArgument::UncommonValue:
173+
// FIXME: Include a representation of these arguments.
172174
break;
173175
case TemplateArgument::Template:
174176
case TemplateArgument::TemplateExpansion:

clang/lib/AST/StmtProfile.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,12 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
22082208
Arg.getAsIntegral().Profile(ID);
22092209
break;
22102210

2211+
case TemplateArgument::UncommonValue:
2212+
VisitType(Arg.getUncommonValueType());
2213+
// FIXME: Do we need to recursively decompose this ourselves?
2214+
Arg.getAsUncommonValue().Profile(ID);
2215+
break;
2216+
22112217
case TemplateArgument::Expression:
22122218
Visit(Arg.getAsExpr());
22132219
break;

0 commit comments

Comments
 (0)