Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[c++20] P1907R1: Support for generalized non-type template arguments of scalar type. #78041

Merged
merged 1 commit into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/DumpAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
TEMPLATE_ARGUMENT_KIND(Declaration);
TEMPLATE_ARGUMENT_KIND(Template);
TEMPLATE_ARGUMENT_KIND(TemplateExpansion);
TEMPLATE_ARGUMENT_KIND(StructuralValue);
#undef TEMPLATE_ARGUMENT_KIND
}
llvm_unreachable("Unhandled ArgKind enum");
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/FindTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ class ExplicitReferenceCollector
case TemplateArgument::Pack:
case TemplateArgument::Type:
case TemplateArgument::Expression:
case TemplateArgument::StructuralValue:
break; // Handled by VisitType and VisitExpression.
};
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A);
Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ C++ Language Changes

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kinds with e.g. floating point values and pointers and references to subobjects.
kinds with e.g. floating point values and pointers and references to subobjects.
This feature is still experimental. Accordingly, `__cpp_nontype_template_args` was not updated.

This feature is still experimental. Accordingly, `__cpp_nontype_template_args` was not updated.

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ODRHash.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

namespace clang {

class APValue;
class Decl;
class IdentifierInfo;
class NestedNameSpecifier;
Expand Down Expand Up @@ -101,6 +102,8 @@ class ODRHash {
// Save booleans until the end to lower the size of data to process.
void AddBoolean(bool value);

void AddStructuralValue(const APValue &);

static bool isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent);

private:
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,20 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
return TemplateArgument(ctx, value, type, isDefaulted);
}]>;
}
let Class = PropertyTypeCase<TemplateArgument, "StructuralValue"> in {
def : Property<"value", APValue> {
let Read = [{ node.getAsStructuralValue() }];
}
def : Property<"type", QualType> {
let Read = [{ node.getStructuralValueType() }];
}
def : Property<"isDefaulted", Bool> {
let Read = [{ node.getIsDefaulted() }];
}
def : Creator<[{
return TemplateArgument(ctx, type, value, isDefaulted);
}]>;
}
let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
def : Property<"name", TemplateName> {
let Read = [{ node.getAsTemplateOrTemplatePattern() }];
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
case TemplateArgument::StructuralValue:
return true;

case TemplateArgument::Type:
Expand Down Expand Up @@ -882,6 +883,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
case TemplateArgument::StructuralValue:
return true;

case TemplateArgument::Type: {
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/TemplateArgumentVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Base {
DISPATCH(Declaration);
DISPATCH(NullPtr);
DISPATCH(Integral);
DISPATCH(StructuralValue);
DISPATCH(Template);
DISPATCH(TemplateExpansion);
DISPATCH(Expression);
Expand All @@ -59,6 +60,7 @@ class Base {
VISIT_METHOD(Declaration);
VISIT_METHOD(NullPtr);
VISIT_METHOD(Integral);
VISIT_METHOD(StructuralValue);
VISIT_METHOD(Template);
VISIT_METHOD(TemplateExpansion);
VISIT_METHOD(Expression);
Expand Down
86 changes: 55 additions & 31 deletions clang/include/clang/AST/TemplateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ template <> struct PointerLikeTypeTraits<clang::Expr *> {

namespace clang {

class APValue;
class ASTContext;
class Expr;
struct PrintingPolicy;
Expand Down Expand Up @@ -80,6 +81,13 @@ class TemplateArgument {
/// that was provided for an integral non-type template parameter.
Integral,

/// The template argument is a non-type template argument that can't be
/// represented by the special-case Declaration, NullPtr, or Integral
/// forms. These values are only ever produced by constant evaluation,
/// so cannot be dependent.
/// TODO: merge Declaration, NullPtr and Integral into this?
AaronBallman marked this conversation as resolved.
Show resolved Hide resolved
StructuralValue,

/// The template argument is a template name that was provided for a
/// template template parameter.
Template,
Expand Down Expand Up @@ -130,6 +138,14 @@ class TemplateArgument {
};
void *Type;
};
struct V {
LLVM_PREFERRED_TYPE(ArgKind)
unsigned Kind : 31;
LLVM_PREFERRED_TYPE(bool)
unsigned IsDefaulted : 1;
APValue *Value;
void *Type;
};
struct A {
LLVM_PREFERRED_TYPE(ArgKind)
unsigned Kind : 31;
Expand All @@ -156,37 +172,42 @@ class TemplateArgument {
union {
struct DA DeclArg;
struct I Integer;
struct V Value;
struct A Args;
struct TA TemplateArg;
struct TV TypeOrValue;
};

void initFromType(QualType T, bool IsNullPtr, bool IsDefaulted);
void initFromDeclaration(ValueDecl *D, QualType QT, bool IsDefaulted);
void initFromIntegral(const ASTContext &Ctx, const llvm::APSInt &Value,
QualType Type, bool IsDefaulted);
void initFromStructural(const ASTContext &Ctx, QualType Type,
const APValue &V, bool IsDefaulted);

public:
/// Construct an empty, invalid template argument.
constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}

/// Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false,
bool IsDefaulted = false) {
TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
TypeOrValue.IsDefaulted = IsDefaulted;
TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
initFromType(T, isNullPtr, IsDefaulted);
}

/// Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
/// Construct a template argument that refers to a (non-dependent)
/// declaration.
TemplateArgument(ValueDecl *D, QualType QT, bool IsDefaulted = false) {
assert(D && "Expected decl");
DeclArg.Kind = Declaration;
DeclArg.IsDefaulted = IsDefaulted;
DeclArg.QT = QT.getAsOpaquePtr();
DeclArg.D = D;
initFromDeclaration(D, QT, IsDefaulted);
}

/// Construct an integral constant template argument. The memory to
/// store the value is allocated with Ctx.
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type,
TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value,
QualType Type, bool IsDefaulted = false);

/// Construct a template argument from an arbitrary constant value.
TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value,
bool IsDefaulted = false);

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

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

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

/// Get the value of a StructuralValue.
const APValue &getAsStructuralValue() const { return *Value.Value; }

/// Get the type of a StructuralValue.
QualType getStructuralValueType() const {
return QualType::getFromOpaquePtr(Value.Type);
}

/// If this is a non-type template argument, get its type. Otherwise,
/// returns a null QualType.
QualType getNonTypeTemplateArgumentType() const;
Expand Down Expand Up @@ -516,6 +545,7 @@ class TemplateArgumentLoc {
assert(Argument.getKind() == TemplateArgument::NullPtr ||
Argument.getKind() == TemplateArgument::Integral ||
Argument.getKind() == TemplateArgument::Declaration ||
Argument.getKind() == TemplateArgument::StructuralValue ||
Argument.getKind() == TemplateArgument::Expression);
}

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

const TemplateArgument &getArgument() const {
return Argument;
}
const TemplateArgument &getArgument() const { return Argument; }

TemplateArgumentLocInfo getLocInfo() const {
return LocInfo;
}
TemplateArgumentLocInfo getLocInfo() const { return LocInfo; }

TypeSourceInfo *getTypeSourceInfo() const {
if (Argument.getKind() != TemplateArgument::Type)
Expand Down Expand Up @@ -575,6 +601,11 @@ class TemplateArgumentLoc {
return LocInfo.getAsExpr();
}

Expr *getSourceStructuralValueExpression() const {
assert(Argument.getKind() == TemplateArgument::StructuralValue);
return LocInfo.getAsExpr();
}

NestedNameSpecifierLoc getTemplateQualifierLoc() const {
if (Argument.getKind() != TemplateArgument::Template &&
Argument.getKind() != TemplateArgument::TemplateExpansion)
Expand Down Expand Up @@ -606,8 +637,7 @@ class TemplateArgumentListInfo {
public:
TemplateArgumentListInfo() = default;

TemplateArgumentListInfo(SourceLocation LAngleLoc,
SourceLocation RAngleLoc)
TemplateArgumentListInfo(SourceLocation LAngleLoc, SourceLocation RAngleLoc)
: LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}

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

llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
return Arguments;
}
llvm::ArrayRef<TemplateArgumentLoc> arguments() const { return Arguments; }

const TemplateArgumentLoc &operator[](unsigned I) const {
return Arguments[I];
}

TemplateArgumentLoc &operator[](unsigned I) {
return Arguments[I];
}
TemplateArgumentLoc &operator[](unsigned I) { return Arguments[I]; }

void addArgument(const TemplateArgumentLoc &Loc) {
Arguments.push_back(Loc);
}
void addArgument(const TemplateArgumentLoc &Loc) { Arguments.push_back(Loc); }
};

/// Represents an explicit template argument list in C++, e.g.,
Expand Down
5 changes: 0 additions & 5 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5147,8 +5147,6 @@ def err_non_type_template_arg_subobject : Error<
"non-type template argument refers to subobject '%0'">;
def err_non_type_template_arg_addr_label_diff : Error<
"template argument / label address difference / what did you expect?">;
def err_non_type_template_arg_unsupported : Error<
"non-type template argument of type %0 is not yet supported">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
Expand Down Expand Up @@ -5200,9 +5198,6 @@ def err_template_arg_not_object_or_func : Error<
"non-type template argument does not refer to an object or function">;
def err_template_arg_not_pointer_to_member_form : Error<
"non-type template argument is not a pointer to member constant">;
def err_template_arg_member_ptr_base_derived_not_supported : Error<
"non-type template argument of pointer-to-member type %1 that refers "
"to member %q0 of a different class is not supported yet">;
def err_template_arg_invalid : Error<
"non-type template argument '%0' is invalid">;
def ext_template_arg_extra_parens : ExtWarn<
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8595,8 +8595,8 @@ class Sema final {
QualType ParamType,
SourceLocation Loc);
ExprResult
BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc);
BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc);

/// Enumeration describing how template parameter lists are compared
/// for equality.
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6754,6 +6754,11 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::Integral:
return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType()));

case TemplateArgument::StructuralValue:
return TemplateArgument(*this,
getCanonicalType(Arg.getStructuralValueType()),
Arg.getAsStructuralValue());

case TemplateArgument::Type:
return TemplateArgument(getCanonicalType(Arg.getAsType()),
/*isNullPtr*/ false, Arg.getIsDefaulted());
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,17 @@ ASTNodeImporter::import(const TemplateArgument &From) {
From.getIsDefaulted());
}

case TemplateArgument::StructuralValue: {
ExpectedType ToTypeOrErr = import(From.getStructuralValueType());
if (!ToTypeOrErr)
return ToTypeOrErr.takeError();
Expected<APValue> ToValueOrErr = import(From.getAsStructuralValue());
if (!ToValueOrErr)
return ToValueOrErr.takeError();
return TemplateArgument(Importer.getToContext(), *ToTypeOrErr,
*ToValueOrErr);
}

case TemplateArgument::Template: {
Expected<TemplateName> ToTemplateOrErr = import(From.getAsTemplate());
if (!ToTemplateOrErr)
Expand Down Expand Up @@ -3572,6 +3583,8 @@ class IsTypeDeclaredInsideVisitor
case TemplateArgument::NullPtr:
// FIXME: The type is not allowed to be in the function?
return CheckType(Arg.getNullPtrType());
case TemplateArgument::StructuralValue:
return CheckType(Arg.getStructuralValueType());
case TemplateArgument::Pack:
for (const auto &PackArg : Arg.getPackAsArray())
if (checkTemplateArgument(PackArg))
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
Arg2.getAsExpr());

case TemplateArgument::StructuralValue:
return Arg1.structurallyEquals(Arg2);

case TemplateArgument::Pack:
return IsStructurallyEquivalent(Context, Arg1.pack_elements(),
Arg2.pack_elements());
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,10 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType()));
continue;

case TemplateArgument::StructuralValue:
LV.merge(getLVForValue(Arg.getAsStructuralValue(), computation));
continue;

case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template =
Expand Down