Merge branch 'p2996' into wip
This commit is contained in:
@@ -1026,6 +1026,7 @@ public:
|
||||
|
||||
let HasCustomParsing = 1;
|
||||
let TemplateDependent = 1;
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
let Documentation = [InternalOnly];
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ def metafn_parent_of_extern_c : Note<
|
||||
// Substitution and invocation.
|
||||
def metafn_cannot_be_arg : Note<
|
||||
"a reflection of %0 cannot represent a %select{function|template}1 argument">;
|
||||
def metafn_undeduced_placeholder : Note<
|
||||
"cannot form a reflection of function %0 whose type %1 contains an undeduced "
|
||||
"placeholder">;
|
||||
def metafn_cannot_invoke : Note<"cannot invoke %0">;
|
||||
def metafn_no_specialization_found : Note<
|
||||
"no specialization of the function template %0 matched the provided "
|
||||
|
||||
@@ -2023,7 +2023,8 @@ CXXSpliceExpr::CXXSpliceExpr(QualType ResultTy, ExprValueKind ValueKind,
|
||||
SourceLocation TemplateKWLoc,
|
||||
SpliceSpecifier *Splice, Expr *Model,
|
||||
bool AllowMemberReference)
|
||||
: Expr(CXXSpliceExprClass, ResultTy, ValueKind, OK_Ordinary),
|
||||
: Expr(CXXSpliceExprClass, ResultTy, ValueKind,
|
||||
Model ? Model->getObjectKind() : OK_Ordinary),
|
||||
TemplateKWLoc(TemplateKWLoc), Splice(Splice), Model(Model),
|
||||
AllowMemberReference(AllowMemberReference) {
|
||||
setDependence(computeDependence(this));
|
||||
@@ -2078,7 +2079,7 @@ ExplDependentCallExpr::ExplDependentCallExpr(CallExpr *SubExpr,
|
||||
unsigned TemplateDepth)
|
||||
: Expr(ExplDependentCallExprClass, SubExpr->getType(),
|
||||
SubExpr->getValueKind(), OK_Ordinary),
|
||||
SubExpr(SubExpr), TemplateDepth(TemplateDepth) {
|
||||
TemplateDepth(TemplateDepth), SubExpr(SubExpr) {
|
||||
setDependence(computeDependence(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -126,10 +126,17 @@ static bool parent_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
ArrayRef<Expr *> Args, Decl *ContainingDecl);
|
||||
|
||||
static bool dealias(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
ArrayRef<Expr *> Args, Decl *ContainingDecl);
|
||||
static bool underlying_entity_of(APValue &Result, ASTContext &C,
|
||||
MetaActions &Meta, EvalFn Evaluator,
|
||||
DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
ArrayRef<Expr *> Args, Decl *ContainingDecl);
|
||||
|
||||
static bool proxied_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser,
|
||||
bool AllowInjection, QualType ResultTy,
|
||||
SourceRange Range, ArrayRef<Expr *> Args,
|
||||
Decl *ContainingDecl);
|
||||
|
||||
static bool value_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
@@ -146,12 +153,6 @@ static bool template_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
ArrayRef<Expr *> Args, Decl *ContainingDecl);
|
||||
|
||||
static bool can_substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser,
|
||||
bool AllowInjection, QualType ResultTy,
|
||||
SourceRange Range, ArrayRef<Expr *> Args,
|
||||
Decl *ContainingDecl);
|
||||
|
||||
static bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
@@ -740,12 +741,12 @@ static constexpr Metafunction Metafunctions[] = {
|
||||
{ Metafunction::MFRK_sourceLoc, 1, 1, source_location_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, type_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, parent_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, dealias },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, underlying_entity_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, proxied_entity_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, object_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, value_of },
|
||||
{ Metafunction::MFRK_metaInfo, 1, 1, template_of },
|
||||
{ Metafunction::MFRK_bool, 3, 3, can_substitute },
|
||||
{ Metafunction::MFRK_metaInfo, 3, 3, substitute },
|
||||
{ Metafunction::MFRK_metaInfo, 4, 4, substitute },
|
||||
{ Metafunction::MFRK_spliceFromArg, 2, 2, extract },
|
||||
{ Metafunction::MFRK_bool, 1, 1, is_public },
|
||||
{ Metafunction::MFRK_bool, 1, 1, is_protected },
|
||||
@@ -880,6 +881,10 @@ static APValue makeBool(ASTContext &C, bool B) {
|
||||
return APValue(C.MakeIntValue(B, C.BoolTy));
|
||||
}
|
||||
|
||||
static APValue makeReflection(std::nullptr_t) {
|
||||
return APValue(ReflectionKind::Null, nullptr);
|
||||
}
|
||||
|
||||
static APValue makeReflection(QualType QT) {
|
||||
return APValue(ReflectionKind::Type, QT.getAsOpaquePtr());
|
||||
}
|
||||
@@ -1767,7 +1772,11 @@ bool get_ith_base_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
|
||||
switch (RV.getReflectionKind()) {
|
||||
case ReflectionKind::Type: {
|
||||
Decl *typeDecl = findTypeDecl(RV.getReflectedType());
|
||||
QualType QT = RV.getReflectedType();
|
||||
QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/false,
|
||||
/*DropRefs=*/false);
|
||||
|
||||
Decl *typeDecl = findTypeDecl(QT);
|
||||
|
||||
if (auto cxxRecordDecl = dyn_cast_or_null<CXXRecordDecl>(typeDecl)) {
|
||||
Meta.EnsureInstantiated(typeDecl, Range);
|
||||
@@ -2456,10 +2465,11 @@ bool parent_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
llvm_unreachable("unknown reflection kind");
|
||||
}
|
||||
|
||||
bool dealias(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range, ArrayRef<Expr *> Args,
|
||||
Decl *ContainingDecl) {
|
||||
bool underlying_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser,
|
||||
bool AllowInjection, QualType ResultTy,
|
||||
SourceRange Range, ArrayRef<Expr *> Args,
|
||||
Decl *ContainingDecl) {
|
||||
assert(Args[0]->getType()->isReflectionType());
|
||||
assert(ResultTy == C.MetaInfoTy);
|
||||
|
||||
@@ -2495,6 +2505,35 @@ bool dealias(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
llvm_unreachable("unknown reflection kind");
|
||||
}
|
||||
|
||||
bool proxied_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser,bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
ArrayRef<Expr *> Args, Decl *ContainingDecl) {
|
||||
assert(Args[0]->getType()->isReflectionType());
|
||||
assert(ResultTy == C.MetaInfoTy);
|
||||
|
||||
APValue RV;
|
||||
if (!Evaluator(RV, Args[0], true))
|
||||
return true;
|
||||
|
||||
switch (RV.getReflectionKind()) {
|
||||
case ReflectionKind::Null:
|
||||
case ReflectionKind::Type:
|
||||
case ReflectionKind::Object:
|
||||
case ReflectionKind::Value:
|
||||
case ReflectionKind::Declaration:
|
||||
case ReflectionKind::Namespace:
|
||||
case ReflectionKind::Template:
|
||||
case ReflectionKind::BaseSpecifier:
|
||||
case ReflectionKind::DataMemberSpec:
|
||||
case ReflectionKind::Annotation:
|
||||
return DiagnoseReflectionKind(Diagnoser, Range, "an entity proxy");
|
||||
case ReflectionKind::EntityProxy:
|
||||
return SetAndSucceed(Result, MaybeUnproxy(C, RV, false));
|
||||
}
|
||||
llvm_unreachable("unknown reflection kind");
|
||||
}
|
||||
|
||||
bool object_of(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range, ArrayRef<Expr *> Args,
|
||||
@@ -2761,71 +2800,6 @@ static TemplateArgument TArgFromReflection(ASTContext &C, EvalFn Evaluator,
|
||||
return TemplateArgument();
|
||||
}
|
||||
|
||||
// TODO(P2996): Abstract this out, and use as an implementation detail of
|
||||
// 'substitute'.
|
||||
bool can_substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range,
|
||||
ArrayRef<Expr *> Args, Decl *ContainingDecl) {
|
||||
assert(Args[0]->getType()->isReflectionType());
|
||||
assert(
|
||||
Args[1]->getType()->getPointeeOrArrayElementType()->isReflectionType());
|
||||
assert(Args[2]->getType()->isIntegerType());
|
||||
|
||||
APValue Template;
|
||||
if (!Evaluator(Template, Args[0], true))
|
||||
return true;
|
||||
|
||||
if (!Template.isReflectedTemplate())
|
||||
return DiagnoseReflectionKind(Diagnoser, Range, "a template",
|
||||
DescriptionOf(Template));
|
||||
TemplateDecl *TDecl = Template.getReflectedTemplate().getAsTemplateDecl();
|
||||
if (TDecl->isInvalidDecl())
|
||||
return true;
|
||||
|
||||
SmallVector<TemplateArgument, 4> TArgs;
|
||||
{
|
||||
// Evaluate how many template arguments were provided.
|
||||
APValue NumArgs;
|
||||
if (!Evaluator(NumArgs, Args[2], true))
|
||||
return true;
|
||||
size_t nArgs = NumArgs.getInt().getExtValue();
|
||||
TArgs.reserve(nArgs);
|
||||
|
||||
for (uint64_t k = 0; k < nArgs; ++k) {
|
||||
llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false);
|
||||
Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(),
|
||||
Args[1]->getExprLoc());
|
||||
|
||||
Synthesized = new (C) ArraySubscriptExpr(Args[1], Synthesized,
|
||||
C.MetaInfoTy, VK_LValue,
|
||||
OK_Ordinary, Range.getBegin());
|
||||
if (Synthesized->isValueDependent() || Synthesized->isTypeDependent())
|
||||
return true;
|
||||
|
||||
APValue Unwrapped;
|
||||
if (!Evaluator(Unwrapped, Synthesized, true) ||
|
||||
!Unwrapped.isReflection())
|
||||
return true;
|
||||
Unwrapped = MaybeUnproxy(C, Unwrapped);
|
||||
if (!CanActAsTemplateArg(Unwrapped))
|
||||
return SetAndSucceed(Result, makeBool(C, false));
|
||||
|
||||
TemplateArgument TArg = TArgFromReflection(C, Evaluator, Unwrapped,
|
||||
Range.getBegin());
|
||||
if (TArg.isNull())
|
||||
return true;
|
||||
TArgs.push_back(TArg);
|
||||
}
|
||||
}
|
||||
SmallVector<TemplateArgument, 4> ExpandedTArgs;
|
||||
expandTemplateArgPacks(TArgs, ExpandedTArgs);
|
||||
|
||||
bool CanSub = Meta.CheckTemplateArgumentList(TDecl, ExpandedTArgs, true,
|
||||
Args[0]->getExprLoc());
|
||||
return SetAndSucceed(Result, makeBool(C, CanSub));
|
||||
}
|
||||
|
||||
bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
|
||||
QualType ResultTy, SourceRange Range, ArrayRef<Expr *> Args,
|
||||
@@ -2847,6 +2821,14 @@ bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
if (TDecl->isInvalidDecl())
|
||||
return true;
|
||||
|
||||
APValue DiagnoseAPV;
|
||||
if (!Evaluator(DiagnoseAPV, Args[3], true))
|
||||
return true;
|
||||
bool NoDiagnose = !DiagnoseAPV.getInt().getBoolValue();
|
||||
auto ElideDiagnosis = [&] {
|
||||
return SetAndSucceed(Result, makeReflection(nullptr));
|
||||
};
|
||||
|
||||
SmallVector<TemplateArgument, 4> TArgs;
|
||||
{
|
||||
// Evaluate how many template arguments were provided.
|
||||
@@ -2873,8 +2855,9 @@ bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
return true;
|
||||
Unwrapped = MaybeUnproxy(C, Unwrapped);
|
||||
if (!CanActAsTemplateArg(Unwrapped))
|
||||
return Diagnoser(Range.getBegin(), diag::metafn_cannot_be_arg)
|
||||
<< DescriptionOf(Unwrapped) << 1 << Range;
|
||||
return NoDiagnose ? ElideDiagnosis() :
|
||||
Diagnoser(Range.getBegin(), diag::metafn_cannot_be_arg)
|
||||
<< DescriptionOf(Unwrapped) << 1 << Range;
|
||||
|
||||
TemplateArgument TArg = TArgFromReflection(C, Evaluator, Unwrapped,
|
||||
Range.getBegin());
|
||||
@@ -2898,9 +2881,9 @@ bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
if (C.checkCachedSubstitution(SubstitutionHash, &Result))
|
||||
return false;
|
||||
|
||||
if (!Meta.CheckTemplateArgumentList(TDecl, ExpandedTArgs, false,
|
||||
if (!Meta.CheckTemplateArgumentList(TDecl, ExpandedTArgs, NoDiagnose,
|
||||
Args[0]->getExprLoc()))
|
||||
return true;
|
||||
return NoDiagnose ? ElideDiagnosis() : true;
|
||||
for (const auto &TArg : ExpandedTArgs)
|
||||
if (TArg.getKind() == TemplateArgument::Expression &&
|
||||
TArg.getAsExpr()->containsErrors())
|
||||
@@ -2938,6 +2921,11 @@ bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
FunctionDecl *Spec = Meta.Substitute(FTD, ExpandedTArgs, Range.getBegin());
|
||||
assert(Spec && "substitution failed after validating arguments?");
|
||||
|
||||
if (Spec->getReturnType()->isUndeducedType())
|
||||
return NoDiagnose ? ElideDiagnosis() :
|
||||
Diagnoser(Range.getBegin(), diag::metafn_undeduced_placeholder)
|
||||
<< Spec << Spec->getType() << Range;
|
||||
|
||||
APValue RV = makeReflection(Spec);
|
||||
//C.recordCachedSubstitution(SubstitutionHash, RV);
|
||||
return SetAndSucceed(Result, RV);
|
||||
@@ -4797,23 +4785,41 @@ bool reflect_result(APValue &Result, ASTContext &C, MetaActions &Meta,
|
||||
if (!Evaluator(Arg, Args[1], !IsLValue))
|
||||
return true;
|
||||
|
||||
// Construct an expression whose result is 'Arg', and evaluate it to check if
|
||||
// it's an allowed result of a constant template argument.
|
||||
//
|
||||
// This is just a hack to get 'CheckConstantExpression' in ExprConstant.cpp
|
||||
// called on 'Arg', to diagnose cases like string literals and temporaries
|
||||
// that aren't allowed in template arguments.
|
||||
//
|
||||
// The expression is constructed in three layers:
|
||||
// - A ConstantExpr to hold 'Arg'
|
||||
// - An OpaqueValueExpr to act as the ConstantExpr's subexpression (we can
|
||||
// otherwise ICE when e.g., checking source location of the ConstantExpr)
|
||||
// - An OpaqueValueExpr wrapper around the ConstantExpr to prevent
|
||||
// EvaluateAsConstantExpr from grabbing 'Arg' and short-circuiting the
|
||||
// evaluation (and, more imporantly, the result validation).
|
||||
Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), Args[1]->getType(),
|
||||
IsLValue ? VK_LValue : VK_PRValue);
|
||||
Expr *CE = ConstantExpr::Create(C, OVE, Arg);
|
||||
{
|
||||
Expr *CE = ConstantExpr::Create(C, OVE, Arg);
|
||||
OVE = new (C) OpaqueValueExpr(Range.getBegin(), Args[1]->getType(),
|
||||
CE->getValueKind(), OK_Ordinary, CE);
|
||||
}
|
||||
{
|
||||
Expr::EvalResult Discarded;
|
||||
|
||||
ConstantExprKind CEKind = (CE->getType()->isClassType() && !IsLValue) ?
|
||||
ConstantExprKind CEKind = (OVE->getType()->isClassType() && !IsLValue) ?
|
||||
ConstantExprKind::ClassTemplateArgument :
|
||||
ConstantExprKind::NonClassTemplateArgument;
|
||||
if (!CE->EvaluateAsConstantExpr(Discarded, C, CEKind))
|
||||
if (!OVE->EvaluateAsConstantExpr(Discarded, C, CEKind))
|
||||
return Diagnoser(Range.getBegin(), diag::metafn_result_not_representable)
|
||||
<< (IsLValue ? 1 : 0) << Range;
|
||||
}
|
||||
|
||||
// If this is an lvalue to a function, promote the result to reflect
|
||||
// the declaration.
|
||||
if (CE->getType()->isFunctionType() && Arg.isLValue() &&
|
||||
if (OVE->getType()->isFunctionType() && Arg.isLValue() &&
|
||||
Arg.getLValueOffset().isZero())
|
||||
if (!Arg.hasLValuePath() || Arg.getLValuePath().size() == 0)
|
||||
if (APValue::LValueBase LVBase = Arg.getLValueBase();
|
||||
|
||||
@@ -8741,6 +8741,10 @@ class BuiltinCandidateTypeSet {
|
||||
/// candidate set.
|
||||
bool HasNullPtrType;
|
||||
|
||||
/// A flag indicating whether the reflection type was present in the
|
||||
/// candidate set.
|
||||
bool HasReflectionType;
|
||||
|
||||
/// Sema - The semantic analysis instance where we are building the
|
||||
/// candidate type set.
|
||||
Sema &SemaRef;
|
||||
@@ -8760,6 +8764,7 @@ public:
|
||||
: HasNonRecordTypes(false),
|
||||
HasArithmeticOrEnumeralTypes(false),
|
||||
HasNullPtrType(false),
|
||||
HasReflectionType(false),
|
||||
SemaRef(SemaRef),
|
||||
Context(SemaRef.Context) { }
|
||||
|
||||
@@ -8784,6 +8789,7 @@ public:
|
||||
bool hasNonRecordTypes() { return HasNonRecordTypes; }
|
||||
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
|
||||
bool hasNullPtrType() const { return HasNullPtrType; }
|
||||
bool hasReflectionType() const { return HasReflectionType; }
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@@ -8965,6 +8971,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
|
||||
MatrixTypes.insert(Ty);
|
||||
} else if (Ty->isNullPtrType()) {
|
||||
HasNullPtrType = true;
|
||||
} else if (Ty->isReflectionType()) {
|
||||
HasReflectionType = true;
|
||||
} else if (AllowUserConversions && TyRec) {
|
||||
// No conversion functions in incomplete types.
|
||||
if (!SemaRef.isCompleteType(Loc, Ty))
|
||||
@@ -9445,6 +9453,14 @@ public:
|
||||
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
|
||||
}
|
||||
}
|
||||
|
||||
if (CandidateTypes[ArgIdx].hasReflectionType()) {
|
||||
CanQualType InfoTy = S.Context.getCanonicalType(S.Context.MetaInfoTy);
|
||||
if (AddedTypes.insert(InfoTy).second) {
|
||||
QualType ParamTypes[2] = { InfoTy, InfoTy };
|
||||
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "clang/Sema/TemplateDeduction.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
@@ -737,10 +737,16 @@ void Sema::InstantiateAttrsForDecl(
|
||||
// FIXME: This function is called multiple times for the same template
|
||||
// specialization. We should only instantiate attributes that were added
|
||||
// since the previous instantiation.
|
||||
bool AddAnnotations = New->attrs().empty();
|
||||
for (const auto *TmplAttr : Tmpl->attrs()) {
|
||||
if (!isRelevantAttr(*this, New, TmplAttr))
|
||||
continue;
|
||||
|
||||
if (isa<CXX26AnnotationAttr>(TmplAttr) && !AddAnnotations)
|
||||
// See https://github.com/llvm/llvm-project/issues/138596
|
||||
// Just skip here to avoid duplication of the attribute.
|
||||
continue;
|
||||
|
||||
// FIXME: If any of the special case versions from InstantiateAttrs become
|
||||
// applicable to template declaration, we'll need to add them here.
|
||||
CXXThisScopeRAII ThisScope(
|
||||
@@ -778,6 +784,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
const Decl *Tmpl, Decl *New,
|
||||
LateInstantiatedAttrVec *LateAttrs,
|
||||
LocalInstantiationScope *OuterMostScope) {
|
||||
bool AddAnnotations = New->attrs().empty();
|
||||
for (const auto *TmplAttr : Tmpl->attrs()) {
|
||||
if (!isRelevantAttr(*this, New, TmplAttr))
|
||||
continue;
|
||||
@@ -879,6 +886,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isa<CXX26AnnotationAttr>(TmplAttr) && !AddAnnotations)
|
||||
// See https://github.com/llvm/llvm-project/issues/138596
|
||||
// Just skip here to avoid duplication of the attribute.
|
||||
continue;
|
||||
|
||||
// Existing DLL attribute on the instantiation takes precedence.
|
||||
if (TmplAttr->getKind() == attr::DLLExport ||
|
||||
TmplAttr->getKind() == attr::DLLImport) {
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
// CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance)
|
||||
// CHECK-NEXT: IFunc (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: InitPriority (SubjectMatchRule_variable)
|
||||
// CHECK-NEXT: InstantiationDependent (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
|
||||
// CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
|
||||
// CHECK-NEXT: Leaf (SubjectMatchRule_function)
|
||||
|
||||
@@ -156,7 +156,10 @@ consteval info local_var_reflection() {
|
||||
}
|
||||
static_assert(local_var_reflection() == local_var_reflection());
|
||||
|
||||
// Compare reflections of the same local variable in different stack frames.
|
||||
// ======================================
|
||||
// local_variables_different_stack_frames
|
||||
// ======================================
|
||||
|
||||
namespace local_variables_different_stack_frames {
|
||||
consteval bool local_var_in_diff_frames_equal(info inf, int call_depth = 0) {
|
||||
int lcl = call_depth;
|
||||
@@ -172,3 +175,16 @@ consteval bool local_var_in_diff_frames_equal(info inf, int call_depth = 0) {
|
||||
}
|
||||
|
||||
} // namespace local_variables_different_stack_frames
|
||||
|
||||
// ==============================
|
||||
// defaulted_comparison_operators
|
||||
// ==============================
|
||||
|
||||
namespace defaulted_comparison_operators {
|
||||
struct S {
|
||||
info mem;
|
||||
consteval bool operator==(const S &) const = default;
|
||||
};
|
||||
|
||||
static_assert(S{} == S{});
|
||||
} // namespace defaulted_comparison_operators
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// RUN: %clang_cc1 %s -std=c++26 -freflection -fentity-proxy-reflection
|
||||
// RUN: %clang_cc1 %s -std=c++26 -freflection -fentity-proxy-reflection -verify
|
||||
|
||||
using info = decltype(^^int);
|
||||
|
||||
@@ -283,6 +283,21 @@ static_assert(int([:rB:]) == int([:rClsB:]));
|
||||
static_assert(static_cast<Enum>([:rClsB:]) == B);
|
||||
} // namespace with_enums
|
||||
|
||||
// ====================
|
||||
// address_of_bit_field
|
||||
// ====================
|
||||
|
||||
namespace address_of_bit_field {
|
||||
struct S {
|
||||
int x : 4, y : 4;
|
||||
};
|
||||
|
||||
constexpr auto f() {
|
||||
constexpr auto r = ^^S::y;
|
||||
return &[:r:]; // expected-error {{address of bit-field requested}}
|
||||
}
|
||||
} // namespace address_of_bit_field
|
||||
|
||||
// =============
|
||||
// colon_parsing
|
||||
// =============
|
||||
|
||||
@@ -442,11 +442,11 @@ enum : unsigned {
|
||||
__metafn_source_location_of,
|
||||
__metafn_type_of,
|
||||
__metafn_parent_of,
|
||||
__metafn_dealias,
|
||||
__metafn_underlying_entity_of,
|
||||
__metafn_proxied_entity_of,
|
||||
__metafn_object_of,
|
||||
__metafn_value_of,
|
||||
__metafn_template_of,
|
||||
__metafn_can_substitute,
|
||||
__metafn_substitute,
|
||||
__metafn_extract,
|
||||
__metafn_is_public,
|
||||
@@ -551,6 +551,10 @@ enum : unsigned {
|
||||
|
||||
consteval auto __workaround_expand_compiler_builtins(info type) -> info;
|
||||
|
||||
consteval auto __underlying_entity_of(info r) -> info {
|
||||
return __metafunction(detail::__metafn_underlying_entity_of, r);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace __range_of_infos {
|
||||
@@ -764,10 +768,23 @@ struct front_annotation_of {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Returns a reflection of the canonical type for the reflected type.
|
||||
#if __has_feature(entity_proxy_reflection)
|
||||
[[deprecated("renamed to 'underlying_entity_of' in PXYZ")]]
|
||||
#endif
|
||||
consteval auto dealias(info r) -> info {
|
||||
return __metafunction(detail::__metafn_dealias, r);
|
||||
return __metafunction(detail::__metafn_underlying_entity_of, r);
|
||||
}
|
||||
|
||||
#if __has_feature(entity_proxy_reflection)
|
||||
consteval auto underlying_entity_of(info r) -> info {
|
||||
return __metafunction(detail::__metafn_underlying_entity_of, r);
|
||||
}
|
||||
|
||||
consteval auto proxied_entity_of(info r) -> info {
|
||||
return __metafunction(detail::__metafn_proxied_entity_of, r);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns the identifier for the represented entity. If the entity is a
|
||||
// literal operator or literal operator template, then this is the identifier
|
||||
// suffix for the literal operator.
|
||||
@@ -907,14 +924,16 @@ consteval auto is_data_member_spec(info r) -> bool {
|
||||
// Returns whether 'templ' substituted with 'args' forms a valid template-id.
|
||||
template <reflection_range R = initializer_list<info>>
|
||||
consteval auto can_substitute(info templ, R &&args) -> bool {
|
||||
info sub;
|
||||
if constexpr (ranges::contiguous_range<R>) {
|
||||
return __metafunction(detail::__metafn_can_substitute, templ,
|
||||
ranges::data(args), ranges::size(args));
|
||||
sub = __metafunction(detail::__metafn_substitute, templ,
|
||||
ranges::data(args), ranges::size(args), false);
|
||||
} else {
|
||||
vector vargs = args | ranges::to<vector>();
|
||||
return __metafunction(detail::__metafn_can_substitute, templ,
|
||||
vargs.data(), vargs.size());
|
||||
sub = __metafunction(detail::__metafn_substitute, templ,
|
||||
vargs.data(), vargs.size(), false);
|
||||
}
|
||||
return sub != info{};
|
||||
}
|
||||
|
||||
// Returns a reflection representing the template instantiation of the entity
|
||||
@@ -923,11 +942,11 @@ template <reflection_range R = initializer_list<info>>
|
||||
consteval auto substitute(info templ, R &&args) -> info {
|
||||
if constexpr (ranges::contiguous_range<R>) {
|
||||
return __metafunction(detail::__metafn_substitute, templ,
|
||||
ranges::data(args), ranges::size(args));
|
||||
ranges::data(args), ranges::size(args), true);
|
||||
} else {
|
||||
vector vargs = args | ranges::to<vector>();
|
||||
return __metafunction(detail::__metafn_substitute, templ, vargs.data(),
|
||||
vargs.size());
|
||||
vargs.size(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1906,100 +1925,103 @@ consteval auto is_nothrow_invocable_r_type(info result, info type,
|
||||
|
||||
consteval auto remove_const(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_const_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_const_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto remove_volatile(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_volatile_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_volatile_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto remove_cv(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_cv_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_cv_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto add_const(info type) -> info {
|
||||
return dealias(substitute(^^add_const_t, {type}));
|
||||
return detail::__underlying_entity_of(substitute(^^add_const_t, {type}));
|
||||
}
|
||||
|
||||
consteval auto add_volatile(info type) -> info {
|
||||
return dealias(substitute(^^add_volatile_t, {type}));
|
||||
return detail::__underlying_entity_of(substitute(^^add_volatile_t, {type}));
|
||||
}
|
||||
|
||||
consteval auto add_cv(info type) -> info {
|
||||
return dealias(substitute(^^add_cv_t, {type}));
|
||||
return detail::__underlying_entity_of(substitute(^^add_cv_t, {type}));
|
||||
}
|
||||
|
||||
consteval auto remove_reference(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_reference_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_reference_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto add_lvalue_reference(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^add_lvalue_reference_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^add_lvalue_reference_t,
|
||||
{type})));
|
||||
}
|
||||
|
||||
consteval auto add_rvalue_reference(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^add_rvalue_reference_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^add_rvalue_reference_t,
|
||||
{type})));
|
||||
}
|
||||
|
||||
consteval auto make_signed(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^make_signed_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^make_signed_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto make_unsigned(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^make_unsigned_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^make_unsigned_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto remove_extent(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_extent_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_extent_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto remove_all_extents(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_all_extents_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_all_extents_t,
|
||||
{type})));
|
||||
}
|
||||
|
||||
consteval auto remove_pointer(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_pointer_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_pointer_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto add_pointer(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^add_pointer_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^add_pointer_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto remove_cvref(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^remove_cvref_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^remove_cvref_t, {type})));
|
||||
}
|
||||
|
||||
consteval auto decay(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^decay_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^decay_t, {type})));
|
||||
}
|
||||
|
||||
template <reflection_range R = initializer_list<info>>
|
||||
consteval auto common_type(R &&args) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^common_type_t, args)));
|
||||
detail::__underlying_entity_of(substitute(^^common_type_t, args)));
|
||||
}
|
||||
|
||||
template <reflection_range R = initializer_list<info>>
|
||||
consteval auto common_reference(R &&args) -> info {
|
||||
return dealias(substitute(^^common_reference_t, args));
|
||||
return detail::__underlying_entity_of(substitute(^^common_reference_t, args));
|
||||
}
|
||||
|
||||
consteval auto underlying_type(info type) -> info {
|
||||
return detail::__workaround_expand_compiler_builtins(
|
||||
dealias(substitute(^^underlying_type_t, {type})));
|
||||
detail::__underlying_entity_of(substitute(^^underlying_type_t, {type})));
|
||||
}
|
||||
|
||||
template <reflection_range R = initializer_list<info>>
|
||||
@@ -2007,15 +2029,17 @@ consteval auto invoke_result(info type, R &&args) -> info {
|
||||
vector<info> targs(from_range, args);
|
||||
targs.insert(targs.begin(), type);
|
||||
|
||||
return dealias(substitute(^^invoke_result_t, targs));
|
||||
return detail::__underlying_entity_of(substitute(^^invoke_result_t, targs));
|
||||
}
|
||||
|
||||
consteval auto unwrap_reference(info type) -> info {
|
||||
return dealias(substitute(^^unwrap_reference_t, {type}));
|
||||
return detail::__underlying_entity_of(substitute(^^unwrap_reference_t,
|
||||
{type}));
|
||||
}
|
||||
|
||||
consteval auto unwrap_ref_decay(info type) -> info {
|
||||
return dealias(substitute(^^unwrap_ref_decay_t, {type}));
|
||||
return detail::__underlying_entity_of(substitute(^^unwrap_ref_decay_t,
|
||||
{type}));
|
||||
}
|
||||
|
||||
consteval auto tuple_size(info type) -> size_t {
|
||||
@@ -2023,7 +2047,7 @@ consteval auto tuple_size(info type) -> size_t {
|
||||
}
|
||||
|
||||
consteval auto tuple_element(size_t index, info type) -> info {
|
||||
return dealias(substitute(^^tuple_element_t,
|
||||
return detail::__underlying_entity_of(substitute(^^tuple_element_t,
|
||||
{reflect_value(index), type}));
|
||||
}
|
||||
|
||||
@@ -2032,7 +2056,7 @@ consteval auto variant_size(info type) -> size_t {
|
||||
}
|
||||
|
||||
consteval auto variant_alternative(size_t index, info type) -> info {
|
||||
return dealias(substitute(^^variant_alternative_t,
|
||||
return detail::__underlying_entity_of(substitute(^^variant_alternative_t,
|
||||
{reflect_value(index), type}));
|
||||
}
|
||||
|
||||
@@ -2041,7 +2065,8 @@ namespace detail {
|
||||
template <class T> struct __wrap_workaround { using type = T; };
|
||||
consteval auto __workaround_expand_compiler_builtins(info type) -> info {
|
||||
auto r = substitute(^^__wrap_workaround, {type});
|
||||
return dealias(members_of(r, access_context::unchecked())[0]);
|
||||
r = members_of(r, access_context::unchecked())[0];
|
||||
return detail::__underlying_entity_of(r);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@@ -2216,11 +2241,12 @@ template <typename Ty>
|
||||
[[deprecated("separated into 'reflect_value', 'reflect_result', and "
|
||||
"'reflect_function' in P2996R4")]]
|
||||
consteval auto reflect_result(Ty r) -> info {
|
||||
constexpr auto DTy = dealias(^^Ty);
|
||||
constexpr auto DTy = detail::__underlying_entity_of(^^Ty);
|
||||
constexpr auto RTy = is_class_v<[:DTy:]> || is_reference_v<[:DTy:]> ?
|
||||
DTy : ^^remove_cv_t<[:DTy:]>;
|
||||
|
||||
return __metafunction(detail::__metafn_reflect_result, dealias(RTy),
|
||||
return __metafunction(detail::__metafn_reflect_result,
|
||||
detail::__underlying_entity_of(RTy),
|
||||
static_cast<typename [:DTy:]>(r));
|
||||
}
|
||||
|
||||
@@ -2357,8 +2383,8 @@ namespace detail {
|
||||
|
||||
template <typename CharT>
|
||||
struct pretty_printer {
|
||||
static_assert(dealias(^^CharT) == ^^char ||
|
||||
dealias(^^CharT) == ^^char8_t);
|
||||
static_assert(detail::__underlying_entity_of(^^CharT) == ^^char ||
|
||||
detail::__underlying_entity_of(^^CharT) == ^^char8_t);
|
||||
static constexpr bool IsUtf8 = is_same_type(^^CharT, ^^char8_t);
|
||||
|
||||
using string_t = basic_string<CharT>;
|
||||
@@ -2588,7 +2614,7 @@ template <info R> // Values of fundamental type.
|
||||
requires(is_value(R) && is_fundamental_type(type_of(R)))
|
||||
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
||||
string_t result;
|
||||
constexpr info Ty = dealias(type_of(R));
|
||||
constexpr info Ty = detail::__underlying_entity_of(type_of(R));
|
||||
|
||||
if constexpr (Ty == ^^nullptr_t)
|
||||
result = string_constant("nullptr");
|
||||
@@ -2606,7 +2632,8 @@ consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
||||
result += string_constant("'");
|
||||
}
|
||||
|
||||
else if constexpr (is_integral_type(Ty) && dealias(^^CharT) == ^^char) {
|
||||
else if constexpr (is_integral_type(Ty) &&
|
||||
detail::__underlying_entity_of(^^CharT) == ^^char) {
|
||||
CharT buffer[32] = {};
|
||||
if (!to_chars(begin(buffer), end(buffer), [:R:]))
|
||||
throw "'to_chars' failed to format integeral value";
|
||||
@@ -2760,7 +2787,7 @@ consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
||||
|
||||
if (R == ^^decltype(nullptr) || R == ^^nullptr_t)
|
||||
return string_constant("std::nullptr_t");
|
||||
if (R == ^^info || R == dealias(^^info))
|
||||
if (R == ^^info || R == detail::__underlying_entity_of(^^info))
|
||||
return string_constant("std::meta::info");
|
||||
|
||||
if (R == ^^bool) return string_constant("bool");
|
||||
|
||||
@@ -50,22 +50,23 @@ static_assert(is_accessible(^^B::Inner, ctx));
|
||||
static_assert(is_entity_proxy(^^B::Inner));
|
||||
static_assert(!is_entity_proxy(^^A::Inner));
|
||||
|
||||
static_assert(nonstatic_data_members_of(dealias(^^B::Inner), ctx).size() == 1);
|
||||
static_assert(bases_of(dealias(^^B::Inner), ctx).size() == 1);
|
||||
static_assert(nonstatic_data_members_of(underlying_entity_of(^^B::Inner),
|
||||
ctx).size() == 1);
|
||||
static_assert(bases_of(underlying_entity_of(^^B::Inner), ctx).size() == 1);
|
||||
|
||||
static_assert(template_arguments_of(dealias(^^B::Alias)) ==
|
||||
static_assert(template_arguments_of(underlying_entity_of(^^B::Alias)) ==
|
||||
std::vector {^^int, ^^std::allocator<int>});
|
||||
static_assert(identifier_of(^^B::Alias) == "Alias");
|
||||
static_assert(source_location_of(^^B::Alias).line() == 34);
|
||||
|
||||
static_assert(type_of(dealias(^^B::m)) == ^^int);
|
||||
static_assert(type_of(underlying_entity_of(^^B::m)) == ^^int);
|
||||
static_assert(parent_of(^^B::m) == ^^B);
|
||||
static_assert(dealias(^^B::Alias) == ^^std::vector<int>);
|
||||
static_assert(template_of(dealias(^^B::Alias)) == ^^std::vector);
|
||||
static_assert(has_template_arguments(dealias(^^B::Alias)));
|
||||
static_assert(underlying_entity_of(^^B::Alias) == ^^std::vector<int>);
|
||||
static_assert(template_of(underlying_entity_of(^^B::Alias)) == ^^std::vector);
|
||||
static_assert(has_template_arguments(underlying_entity_of(^^B::Alias)));
|
||||
static_assert(!has_template_arguments(^^B::Alias));
|
||||
|
||||
static_assert(substitute(dealias(^^D::TCls), {^^D::Inner}) ==
|
||||
static_assert(substitute(underlying_entity_of(^^D::TCls), {^^D::Inner}) ==
|
||||
^^C::TCls<C::Inner>);
|
||||
|
||||
static_assert(identifier_of(members_of(^^D, unchecked)[2]) == "m");
|
||||
@@ -74,7 +75,7 @@ static_assert(is_private(members_of(^^D, unchecked)[2]));
|
||||
static_assert(!is_class_member(^^Enum::Red));
|
||||
static_assert(is_class_member(^^E::Red));
|
||||
static_assert(is_entity_proxy(^^E::Red));
|
||||
static_assert(dealias(^^E::Red) == ^^Enum::Red);
|
||||
static_assert(underlying_entity_of(^^E::Red) == ^^Enum::Red);
|
||||
|
||||
static_assert(!is_namespace_member(^^Enum::Red));
|
||||
static_assert(is_namespace_member(^^InnerNS::Red));
|
||||
@@ -83,7 +84,7 @@ static_assert(extract<int>(annotations_of(^^G::m)[0]) == 32);
|
||||
static_assert(!is_access_specified(^^G::m));
|
||||
static_assert(is_access_specified(^^G::n));
|
||||
|
||||
static_assert(dealias(^^H::n) == ^^F::n);
|
||||
static_assert(underlying_entity_of(^^H::n) == ^^F::n);
|
||||
|
||||
// =================
|
||||
// dependent_proxies
|
||||
@@ -106,14 +107,14 @@ static_assert(is_entity_proxy(S<A>::r));
|
||||
static_assert(is_entity_proxy(S<A>::s));
|
||||
static_assert(parent_of(S<A>::r) == ^^S<A>);
|
||||
static_assert(S<A>::r == S<A>::s);
|
||||
static_assert(dealias(S<A>::r) == ^^A::fn);
|
||||
static_assert(underlying_entity_of(S<A>::r) == ^^A::fn);
|
||||
static_assert(&[:S<A>::r:] == &A::fn);
|
||||
|
||||
static_assert(is_entity_proxy(S<A>::t));
|
||||
static_assert(is_entity_proxy(S<A>::u));
|
||||
static_assert(parent_of(S<A>::t) == ^^S<A>);
|
||||
static_assert(S<A>::t == S<A>::u);
|
||||
static_assert(dealias(S<A>::t) == ^^A::Inner);
|
||||
static_assert(underlying_entity_of(S<A>::t) == ^^A::Inner);
|
||||
|
||||
// ===========
|
||||
// using_enums
|
||||
@@ -125,12 +126,29 @@ struct S { using enum Color; };
|
||||
|
||||
static_assert(^^S::Red != ^^S::Green);
|
||||
static_assert(^^S::Red != ^^Color::Red);
|
||||
static_assert(dealias(^^S::Red) == ^^Color::Red);
|
||||
static_assert(underlying_entity_of(^^S::Red) == ^^Color::Red);
|
||||
static_assert(is_entity_proxy(^^S::Red));
|
||||
static_assert([:^^S::Red:] == Color::Red);
|
||||
|
||||
} // namespace using_enums
|
||||
|
||||
// =============
|
||||
// paper_example
|
||||
// =============
|
||||
|
||||
namespace paper_example {
|
||||
struct B { using Alias = int; };
|
||||
struct D : B { using B::Alias; };
|
||||
|
||||
static_assert(is_type_alias(^^B::Alias));
|
||||
static_assert(is_entity_proxy(^^D::Alias));
|
||||
static_assert(^^B::Alias != ^^D::Alias);
|
||||
static_assert(proxied_entity_of(^^D::Alias) == ^^B::Alias);
|
||||
static_assert(underlying_entity_of(^^D::Alias) == ^^int);
|
||||
static_assert(underlying_entity_of(^^B::Alias) == underlying_entity_of(^^D::Alias));
|
||||
|
||||
} // namespace paper_example
|
||||
|
||||
} // namespace dependent_proxies
|
||||
|
||||
int main() { }
|
||||
|
||||
@@ -329,6 +329,7 @@ struct B1 {};
|
||||
struct B2 {};
|
||||
struct B3 {};
|
||||
struct D1 : public B1, virtual protected B2, private B3 {};
|
||||
using Alias = D1;
|
||||
static_assert(bases_of(^^B1, access_context::unchecked()).size() == 0);
|
||||
static_assert(type_of(bases_of(^^D1, access_context::unchecked())[0]) == ^^B1);
|
||||
static_assert(type_of(bases_of(^^D1, access_context::unchecked())[1]) == ^^B2);
|
||||
@@ -346,6 +347,9 @@ static_assert(!is_protected(bases_of(^^D1, access_context::unchecked())[2]));
|
||||
static_assert(is_private(bases_of(^^D1, access_context::unchecked())[2]));
|
||||
static_assert(!is_virtual(bases_of(^^D1, access_context::unchecked())[2]));
|
||||
|
||||
static_assert(type_of(bases_of(^^Alias,
|
||||
access_context::unchecked())[0]) == ^^B1);
|
||||
|
||||
template <typename... Bases> struct D2 : Bases... {};
|
||||
static_assert(type_of(bases_of(^^D2<B1, B3>, access_context::unchecked())[0]) ==
|
||||
^^B1);
|
||||
|
||||
@@ -70,6 +70,7 @@ static_assert((annotations_of(^^TCls<int>) |
|
||||
std::meta::reflect_value(5),
|
||||
std::meta::reflect_value(6),
|
||||
std::meta::reflect_value(3.0f)});
|
||||
|
||||
static_assert((annotations_of(^^TFn<int>) |
|
||||
std::views::transform(std::meta::value_of) |
|
||||
std::ranges::to<std::vector>()) ==
|
||||
@@ -251,4 +252,19 @@ static_assert(c3 == -1);
|
||||
static_assert(c4 == 4);
|
||||
} // namespace ledger_based_consteval_variable
|
||||
|
||||
// ===========================
|
||||
// templated_class_annotations
|
||||
// ===========================
|
||||
|
||||
namespace templated_class_annotations {
|
||||
template <class T>
|
||||
struct X {
|
||||
struct [[=1]] C;
|
||||
struct [[=2]] D { };
|
||||
};
|
||||
|
||||
static_assert(annotations_of(^^X<int>::C).size() == 1);
|
||||
static_assert(annotations_of(^^X<int>::D).size() == 1);
|
||||
} // namespace templated_class_annotations
|
||||
|
||||
int main() { }
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
|
||||
// ADDITIONAL_COMPILE_FLAGS: -freflection
|
||||
// ADDITIONAL_COMPILE_FLAGS: -Wno-unneeded-internal-declaration
|
||||
|
||||
// <experimental/reflection>
|
||||
//
|
||||
@@ -348,7 +347,7 @@ template <template <typename...> class... Cs>
|
||||
using Alias = [:substitute(^^std::tuple, {substitute(^^Cs, {^^int})...}):];
|
||||
static_assert(dealias(^^Alias<std::queue, std::vector>) ==
|
||||
^^std::tuple<std::queue<int>, std::vector<int>>);
|
||||
} // namespace equality_respects_default_template_arguments
|
||||
} // namespace equality_respects_default_template_arguments
|
||||
|
||||
// ==========================
|
||||
// with_template_arguments_of
|
||||
@@ -462,4 +461,27 @@ template <auto &V> static constexpr auto &Value = V;
|
||||
static_assert([:substitute(^^Value, {members_of(^^Cls, ctx)[0]}):] == 11);
|
||||
} // namespace non_type_ref_regression_test
|
||||
|
||||
// ===============
|
||||
// wording_example
|
||||
// ===============
|
||||
|
||||
namespace wording_example {
|
||||
template <typename T>
|
||||
auto fn1();
|
||||
|
||||
static_assert(!can_substitute(^^fn1, {^^int}));
|
||||
constexpr auto r1 = substitute(^^fn1, {^^int});
|
||||
// expected-error@-1 {{must be initialized by a constant expression}} \
|
||||
// expected-note@-1 {{undeduced placeholder}}
|
||||
|
||||
template <typename T>
|
||||
auto fn2() {
|
||||
static_assert(^^T != ^^int); // expected-error {{static assertion failed}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr auto r2 = substitute(^^fn2, {^^int});
|
||||
// expected-note@-1 {{requested here}}
|
||||
} // namespace wording_example
|
||||
|
||||
int main() { }
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
|
||||
// ADDITIONAL_COMPILE_FLAGS: -freflection
|
||||
// ADDITIONAL_COMPILE_FLAGS: -Wno-unneeded-internal-declaration
|
||||
|
||||
// <experimental/reflection>
|
||||
//
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Copyright 2024 Bloomberg Finance L.P.
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
|
||||
// ADDITIONAL_COMPILE_FLAGS: -freflection
|
||||
|
||||
// <experimental/reflection>
|
||||
//
|
||||
// [reflection]
|
||||
|
||||
#include <experimental/meta>
|
||||
|
||||
|
||||
// ==================
|
||||
// disallowed_results
|
||||
// ==================
|
||||
|
||||
namespace disallowed_results {
|
||||
constexpr auto v1 = std::meta::reflect_value((const char *)"fails");
|
||||
// expected-error@-1 {{must be initialized by a constant expression}} \
|
||||
// expected-note@-1 {{provided value cannot be represented}}
|
||||
|
||||
struct HoldsTemporary {
|
||||
const int &tmp;
|
||||
};
|
||||
constexpr HoldsTemporary htmp{42};
|
||||
constexpr auto v2 = std::meta::reflect_value(htmp);
|
||||
// expected-error@-1 {{must be initialized by a constant expression}} \
|
||||
// expected-note@-1 {{provided value cannot be represented}}
|
||||
|
||||
} // namespace disallowed_results
|
||||
|
||||
|
||||
int main() { }
|
||||
Reference in New Issue
Block a user