Skip to content

Commit 9bef9d5

Browse files
Andrey Ali Khan Bolshakovbolshakov-a
Andrey Ali Khan Bolshakov
authored andcommitted
[c++20] P1907R1: Support for generalized non-type template arguments of scalar type.
Previously committed as 9e08e51, and reverted because a dependency commit was reverted, then committed again as 4b57400 and reverted again because "dependency commit" 5a391d3 was reverted. But it doesn't seem that 5a391d3 was a real dependency for this. This commit incorporates 4b57400 and 18e093f by Richard Smith, with some minor fixes, most notably: - `UncommonValue` renamed to `StructuralValue` - `VK_PRValue` instead of `VK_RValue` as default kind in lvalue and member pointer handling branch in `BuildExpressionFromNonTypeTemplateArgumentValue`; - handling of `StructuralValue` in `IsTypeDeclaredInsideVisitor`; - filling in `SugaredConverted` along with `CanonicalConverted` parameter in `Sema::CheckTemplateArgument`; - minor cleanup in `TemplateInstantiator::transformNonTypeTemplateParmRef`; - `TemplateArgument` constructors refactored; - `ODRHash` calculation for `UncommonValue`; - USR generation for `UncommonValue`; - more correct MS compatibility mangling algorithm (tested on MSVC ver. 19.35; toolset ver. 143); - IR emitting fixed on using a subobject as a template argument when the corresponding template parameter is used in an lvalue context; - `noundef` attribute and opaque pointers in `template-arguments` test; - analysis for C++17 mode is turned off for templates in `warn-bool-conversion` test; in C++17 and C++20 mode, array reference used as a template argument of pointer type produces template argument of UncommonValue type, and `BuildExpressionFromNonTypeTemplateArgumentValue` makes `OpaqueValueExpr` for it, and `DiagnoseAlwaysNonNullPointer` cannot see through it; despite of "These cases should not warn" comment, I'm not sure about correct behavior; I'd expect a suggestion to replace `if` by `if constexpr`; - `temp.arg.nontype/p1.cpp` and `dr18xx.cpp` tests fixed.
1 parent 8e8bbbd commit 9bef9d5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1108
-230
lines changed

clang-tools-extra/clangd/DumpAST.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
143143
TEMPLATE_ARGUMENT_KIND(Declaration);
144144
TEMPLATE_ARGUMENT_KIND(Template);
145145
TEMPLATE_ARGUMENT_KIND(TemplateExpansion);
146+
TEMPLATE_ARGUMENT_KIND(StructuralValue);
146147
#undef TEMPLATE_ARGUMENT_KIND
147148
}
148149
llvm_unreachable("Unhandled ArgKind enum");

clang-tools-extra/clangd/FindTarget.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,7 @@ class ExplicitReferenceCollector
10321032
case TemplateArgument::Pack:
10331033
case TemplateArgument::Type:
10341034
case TemplateArgument::Expression:
1035+
case TemplateArgument::StructuralValue:
10351036
break; // Handled by VisitType and VisitExpression.
10361037
};
10371038
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A);

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ C++ Language Changes
180180

181181
C++20 Feature Support
182182
^^^^^^^^^^^^^^^^^^^^^
183+
- Implemented `P1907R1 <https://wg21.link/P1907R1>` which extends allowed non-type template argument
184+
kinds with e.g. floating point values and pointers and references to subobjects.
183185

184186
C++23 Feature Support
185187
^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ODRHash.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
namespace clang {
2727

28+
class APValue;
2829
class Decl;
2930
class IdentifierInfo;
3031
class NestedNameSpecifier;
@@ -101,6 +102,8 @@ class ODRHash {
101102
// Save booleans until the end to lower the size of data to process.
102103
void AddBoolean(bool value);
103104

105+
void AddStructuralValue(const APValue &);
106+
104107
static bool isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent);
105108

106109
private:

clang/include/clang/AST/PropertiesBase.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,20 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
808808
return TemplateArgument(ctx, value, type, isDefaulted);
809809
}]>;
810810
}
811+
let Class = PropertyTypeCase<TemplateArgument, "StructuralValue"> in {
812+
def : Property<"value", APValue> {
813+
let Read = [{ node.getAsStructuralValue() }];
814+
}
815+
def : Property<"type", QualType> {
816+
let Read = [{ node.getStructuralValueType() }];
817+
}
818+
def : Property<"isDefaulted", Bool> {
819+
let Read = [{ node.getIsDefaulted() }];
820+
}
821+
def : Creator<[{
822+
return TemplateArgument(ctx, type, value, isDefaulted);
823+
}]>;
824+
}
811825
let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
812826
def : Property<"name", TemplateName> {
813827
let Read = [{ node.getAsTemplateOrTemplatePattern() }];

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
850850
case TemplateArgument::Declaration:
851851
case TemplateArgument::Integral:
852852
case TemplateArgument::NullPtr:
853+
case TemplateArgument::StructuralValue:
853854
return true;
854855

855856
case TemplateArgument::Type:
@@ -882,6 +883,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
882883
case TemplateArgument::Declaration:
883884
case TemplateArgument::Integral:
884885
case TemplateArgument::NullPtr:
886+
case TemplateArgument::StructuralValue:
885887
return true;
886888

887889
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(StructuralValue);
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(StructuralValue);
6264
VISIT_METHOD(Template);
6365
VISIT_METHOD(TemplateExpansion);
6466
VISIT_METHOD(Expression);

clang/include/clang/AST/TemplateBase.h

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ template <> struct PointerLikeTypeTraits<clang::Expr *> {
5050

5151
namespace clang {
5252

53+
class APValue;
5354
class ASTContext;
5455
class Expr;
5556
struct PrintingPolicy;
@@ -80,6 +81,13 @@ class TemplateArgument {
8081
/// that was provided for an integral non-type template parameter.
8182
Integral,
8283

84+
/// The template argument is a non-type template argument that can't be
85+
/// represented by the special-case Declaration, NullPtr, or Integral
86+
/// forms. These values are only ever produced by constant evaluation,
87+
/// so cannot be dependent.
88+
/// TODO: merge Declaration, NullPtr and Integral into this?
89+
StructuralValue,
90+
8391
/// The template argument is a template name that was provided for a
8492
/// template template parameter.
8593
Template,
@@ -130,6 +138,14 @@ class TemplateArgument {
130138
};
131139
void *Type;
132140
};
141+
struct V {
142+
LLVM_PREFERRED_TYPE(ArgKind)
143+
unsigned Kind : 31;
144+
LLVM_PREFERRED_TYPE(bool)
145+
unsigned IsDefaulted : 1;
146+
APValue *Value;
147+
void *Type;
148+
};
133149
struct A {
134150
LLVM_PREFERRED_TYPE(ArgKind)
135151
unsigned Kind : 31;
@@ -156,37 +172,42 @@ class TemplateArgument {
156172
union {
157173
struct DA DeclArg;
158174
struct I Integer;
175+
struct V Value;
159176
struct A Args;
160177
struct TA TemplateArg;
161178
struct TV TypeOrValue;
162179
};
163180

181+
void initFromType(QualType T, bool IsNullPtr, bool IsDefaulted);
182+
void initFromDeclaration(ValueDecl *D, QualType QT, bool IsDefaulted);
183+
void initFromIntegral(const ASTContext &Ctx, const llvm::APSInt &Value,
184+
QualType Type, bool IsDefaulted);
185+
void initFromStructural(const ASTContext &Ctx, QualType Type,
186+
const APValue &V, bool IsDefaulted);
187+
164188
public:
165189
/// Construct an empty, invalid template argument.
166190
constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
167191

168192
/// Construct a template type argument.
169193
TemplateArgument(QualType T, bool isNullPtr = false,
170194
bool IsDefaulted = false) {
171-
TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
172-
TypeOrValue.IsDefaulted = IsDefaulted;
173-
TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
195+
initFromType(T, isNullPtr, IsDefaulted);
174196
}
175197

176-
/// Construct a template argument that refers to a
177-
/// declaration, which is either an external declaration or a
178-
/// template declaration.
198+
/// Construct a template argument that refers to a (non-dependent)
199+
/// declaration.
179200
TemplateArgument(ValueDecl *D, QualType QT, bool IsDefaulted = false) {
180-
assert(D && "Expected decl");
181-
DeclArg.Kind = Declaration;
182-
DeclArg.IsDefaulted = IsDefaulted;
183-
DeclArg.QT = QT.getAsOpaquePtr();
184-
DeclArg.D = D;
201+
initFromDeclaration(D, QT, IsDefaulted);
185202
}
186203

187204
/// Construct an integral constant template argument. The memory to
188205
/// store the value is allocated with Ctx.
189-
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type,
206+
TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value,
207+
QualType Type, bool IsDefaulted = false);
208+
209+
/// Construct a template argument from an arbitrary constant value.
210+
TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value,
190211
bool IsDefaulted = false);
191212

192213
/// Construct an integral constant template argument with the same
@@ -297,7 +318,7 @@ class TemplateArgument {
297318
/// Retrieve the type for a type template argument.
298319
QualType getAsType() const {
299320
assert(getKind() == Type && "Unexpected kind");
300-
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
321+
return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V));
301322
}
302323

303324
/// Retrieve the declaration for a declaration non-type
@@ -315,7 +336,7 @@ class TemplateArgument {
315336
/// Retrieve the type for null non-type template argument.
316337
QualType getNullPtrType() const {
317338
assert(getKind() == NullPtr && "Unexpected kind");
318-
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
339+
return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V));
319340
}
320341

321342
/// Retrieve the template name for a template name argument.
@@ -371,6 +392,14 @@ class TemplateArgument {
371392
/// default template parameter.
372393
bool getIsDefaulted() const { return (bool)TypeOrValue.IsDefaulted; }
373394

395+
/// Get the value of a StructuralValue.
396+
const APValue &getAsStructuralValue() const { return *Value.Value; }
397+
398+
/// Get the type of a StructuralValue.
399+
QualType getStructuralValueType() const {
400+
return QualType::getFromOpaquePtr(Value.Type);
401+
}
402+
374403
/// If this is a non-type template argument, get its type. Otherwise,
375404
/// returns a null QualType.
376405
QualType getNonTypeTemplateArgumentType() const;
@@ -516,6 +545,7 @@ class TemplateArgumentLoc {
516545
assert(Argument.getKind() == TemplateArgument::NullPtr ||
517546
Argument.getKind() == TemplateArgument::Integral ||
518547
Argument.getKind() == TemplateArgument::Declaration ||
548+
Argument.getKind() == TemplateArgument::StructuralValue ||
519549
Argument.getKind() == TemplateArgument::Expression);
520550
}
521551

@@ -541,13 +571,9 @@ class TemplateArgumentLoc {
541571
/// - Fetches the full source range of the argument.
542572
SourceRange getSourceRange() const LLVM_READONLY;
543573

544-
const TemplateArgument &getArgument() const {
545-
return Argument;
546-
}
574+
const TemplateArgument &getArgument() const { return Argument; }
547575

548-
TemplateArgumentLocInfo getLocInfo() const {
549-
return LocInfo;
550-
}
576+
TemplateArgumentLocInfo getLocInfo() const { return LocInfo; }
551577

552578
TypeSourceInfo *getTypeSourceInfo() const {
553579
if (Argument.getKind() != TemplateArgument::Type)
@@ -575,6 +601,11 @@ class TemplateArgumentLoc {
575601
return LocInfo.getAsExpr();
576602
}
577603

604+
Expr *getSourceStructuralValueExpression() const {
605+
assert(Argument.getKind() == TemplateArgument::StructuralValue);
606+
return LocInfo.getAsExpr();
607+
}
608+
578609
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
579610
if (Argument.getKind() != TemplateArgument::Template &&
580611
Argument.getKind() != TemplateArgument::TemplateExpansion)
@@ -606,8 +637,7 @@ class TemplateArgumentListInfo {
606637
public:
607638
TemplateArgumentListInfo() = default;
608639

609-
TemplateArgumentListInfo(SourceLocation LAngleLoc,
610-
SourceLocation RAngleLoc)
640+
TemplateArgumentListInfo(SourceLocation LAngleLoc, SourceLocation RAngleLoc)
611641
: LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}
612642

613643
// This can leak if used in an AST node, use ASTTemplateArgumentListInfo
@@ -626,21 +656,15 @@ class TemplateArgumentListInfo {
626656
return Arguments.data();
627657
}
628658

629-
llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
630-
return Arguments;
631-
}
659+
llvm::ArrayRef<TemplateArgumentLoc> arguments() const { return Arguments; }
632660

633661
const TemplateArgumentLoc &operator[](unsigned I) const {
634662
return Arguments[I];
635663
}
636664

637-
TemplateArgumentLoc &operator[](unsigned I) {
638-
return Arguments[I];
639-
}
665+
TemplateArgumentLoc &operator[](unsigned I) { return Arguments[I]; }
640666

641-
void addArgument(const TemplateArgumentLoc &Loc) {
642-
Arguments.push_back(Loc);
643-
}
667+
void addArgument(const TemplateArgumentLoc &Loc) { Arguments.push_back(Loc); }
644668
};
645669

646670
/// Represents an explicit template argument list in C++, e.g.,

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5138,8 +5138,6 @@ def err_non_type_template_arg_subobject : Error<
51385138
"non-type template argument refers to subobject '%0'">;
51395139
def err_non_type_template_arg_addr_label_diff : Error<
51405140
"template argument / label address difference / what did you expect?">;
5141-
def err_non_type_template_arg_unsupported : Error<
5142-
"sorry, non-type template argument of type %0 is not yet supported">;
51435141
def err_template_arg_not_convertible : Error<
51445142
"non-type template argument of type %0 cannot be converted to a value "
51455143
"of type %1">;
@@ -5191,9 +5189,6 @@ def err_template_arg_not_object_or_func : Error<
51915189
"non-type template argument does not refer to an object or function">;
51925190
def err_template_arg_not_pointer_to_member_form : Error<
51935191
"non-type template argument is not a pointer to member constant">;
5194-
def err_template_arg_member_ptr_base_derived_not_supported : Error<
5195-
"sorry, non-type template argument of pointer-to-member type %1 that refers "
5196-
"to member %q0 of a different class is not supported yet">;
51975192
def err_template_arg_invalid : Error<
51985193
"non-type template argument '%0' is invalid">;
51995194
def ext_template_arg_extra_parens : ExtWarn<

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8569,8 +8569,8 @@ class Sema final {
85698569
QualType ParamType,
85708570
SourceLocation Loc);
85718571
ExprResult
8572-
BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
8573-
SourceLocation Loc);
8572+
BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
8573+
SourceLocation Loc);
85748574

85758575
/// Enumeration describing how template parameter lists are compared
85768576
/// for equality.

clang/lib/AST/ASTContext.cpp

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

6756+
case TemplateArgument::StructuralValue:
6757+
return TemplateArgument(*this,
6758+
getCanonicalType(Arg.getStructuralValueType()),
6759+
Arg.getAsStructuralValue());
6760+
67566761
case TemplateArgument::Type:
67576762
return TemplateArgument(getCanonicalType(Arg.getAsType()),
67586763
/*isNullPtr*/ false, Arg.getIsDefaulted());

clang/lib/AST/ASTImporter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,17 @@ ASTNodeImporter::import(const TemplateArgument &From) {
823823
From.getIsDefaulted());
824824
}
825825

826+
case TemplateArgument::StructuralValue: {
827+
ExpectedType ToTypeOrErr = import(From.getStructuralValueType());
828+
if (!ToTypeOrErr)
829+
return ToTypeOrErr.takeError();
830+
Expected<APValue> ToValueOrErr = import(From.getAsStructuralValue());
831+
if (!ToValueOrErr)
832+
return ToValueOrErr.takeError();
833+
return TemplateArgument(Importer.getToContext(), *ToTypeOrErr,
834+
*ToValueOrErr);
835+
}
836+
826837
case TemplateArgument::Template: {
827838
Expected<TemplateName> ToTemplateOrErr = import(From.getAsTemplate());
828839
if (!ToTemplateOrErr)
@@ -3572,6 +3583,8 @@ class IsTypeDeclaredInsideVisitor
35723583
case TemplateArgument::NullPtr:
35733584
// FIXME: The type is not allowed to be in the function?
35743585
return CheckType(Arg.getNullPtrType());
3586+
case TemplateArgument::StructuralValue:
3587+
return CheckType(Arg.getStructuralValueType());
35753588
case TemplateArgument::Pack:
35763589
for (const auto &PackArg : Arg.getPackAsArray())
35773590
if (checkTemplateArgument(PackArg))

clang/lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
628628
return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
629629
Arg2.getAsExpr());
630630

631+
case TemplateArgument::StructuralValue:
632+
return Arg1.structurallyEquals(Arg2);
633+
631634
case TemplateArgument::Pack:
632635
return IsStructurallyEquivalent(Context, Arg1.pack_elements(),
633636
Arg2.pack_elements());

clang/lib/AST/Decl.cpp

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

346+
case TemplateArgument::StructuralValue:
347+
LV.merge(getLVForValue(Arg.getAsStructuralValue(), computation));
348+
continue;
349+
346350
case TemplateArgument::Template:
347351
case TemplateArgument::TemplateExpansion:
348352
if (TemplateDecl *Template =

0 commit comments

Comments
 (0)