Fixes/improvements to 'substitute'.
This commit is contained in:
@@ -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 "
|
||||
|
||||
@@ -146,12 +146,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,
|
||||
@@ -744,8 +738,7 @@ static constexpr Metafunction Metafunctions[] = {
|
||||
{ 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 +873,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());
|
||||
}
|
||||
@@ -2765,71 +2762,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,
|
||||
@@ -2851,6 +2783,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.
|
||||
@@ -2877,8 +2817,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());
|
||||
@@ -2902,9 +2843,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())
|
||||
@@ -2942,6 +2883,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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -446,7 +446,6 @@ enum : unsigned {
|
||||
__metafn_object_of,
|
||||
__metafn_value_of,
|
||||
__metafn_template_of,
|
||||
__metafn_can_substitute,
|
||||
__metafn_substitute,
|
||||
__metafn_extract,
|
||||
__metafn_is_public,
|
||||
@@ -907,14 +906,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 +924,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() { }
|
||||
Reference in New Issue
Block a user