Skip to content

Commit

Permalink
Purely library implementations of 'define_static_*'-functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
katzdm committed Oct 30, 2024
1 parent 4992006 commit 5a5e1a4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 181 deletions.
143 changes: 0 additions & 143 deletions clang/lib/AST/ExprConstantMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,16 +505,6 @@ static bool alignment_of(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args);

static bool define_static_string(APValue &Result, ASTContext &C,
MetaActions &Meta, EvalFn Evaluator,
DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args);

static bool define_static_array(APValue &Result, ASTContext &C,
MetaActions &Meta, EvalFn Evaluator,
DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args);

// -----------------------------------------------------------------------------
// P3096 Metafunction declarations
// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -682,8 +672,6 @@ static constexpr Metafunction Metafunctions[] = {
{ Metafunction::MFRK_sizeT, 1, 1, bit_offset_of },
{ Metafunction::MFRK_sizeT, 1, 1, bit_size_of },
{ Metafunction::MFRK_sizeT, 1, 1, alignment_of },
{ Metafunction::MFRK_spliceFromArg, 5, 5, define_static_string },
{ Metafunction::MFRK_spliceFromArg, 4, 4, define_static_array },

// P3096 metafunction extensions
{ Metafunction::MFRK_metaInfo, 3, 3, get_ith_parameter_of },
Expand Down Expand Up @@ -5417,137 +5405,6 @@ bool alignment_of(APValue &Result, ASTContext &C, MetaActions &Meta,
llvm_unreachable("unknown reflection kind");
}

bool define_static_string(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args) {
assert(Args[0]->getType()->isReflectionType());
assert(Args[1]->getType()->isReflectionType());

APValue Scratch;

// Evaluate the character type.
if (!Evaluator(Scratch, Args[1], true))
return true;
QualType CharTy = Scratch.getReflectedType();

// Evaluate the length of the string provided.
std::string Contents;
if (!Evaluator(Scratch, Args[2], true))
return true;
size_t Length = Scratch.getInt().getExtValue();
Contents.resize(Length);

// Evaluate the given name. Miserably inefficient, but gets the job done.
for (uint64_t k = 0; k < Length; ++k) {
llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false);
Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(),
Args[3]->getExprLoc());

Synthesized = new (C) ArraySubscriptExpr(Args[3], Synthesized, CharTy,
VK_LValue, OK_Ordinary,
Range.getBegin());
if (Synthesized->isValueDependent() || Synthesized->isTypeDependent())
return true;

if (!Evaluator(Scratch, Synthesized, true))
return true;

Contents[k] = static_cast<char>(Scratch.getInt().getExtValue());
}

if (!Evaluator(Scratch, Args[4], true))
return true;
bool IsUtf8 = Scratch.getInt().getBoolValue();

VarDecl *AnonArr = C.getGeneratedCharArray(Contents, IsUtf8);
if (!AnonArr->hasInit()) {
Expr *StrLit = makeStrLiteral(Contents, C, IsUtf8);

AnonArr->setConstexpr(true);
Meta.AttachInitializer(AnonArr, StrLit);

Meta.BroadcastInjectedDecl(AnonArr);
}
assert(AnonArr->getFormalLinkage() == Linkage::Internal);

APValue::LValuePathEntry Path[1] = {APValue::LValuePathEntry::ArrayIndex(0)};
return SetAndSucceed(Result,
APValue(AnonArr, CharUnits::Zero(), Path, false));
}

bool define_static_array(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args) {
assert(Args[0]->getType()->isReflectionType());
assert(Args[1]->getType()->isReflectionType());

APValue Scratch;

// Evaluate the value type.
if (!Evaluator(Scratch, Args[1], true))
return true;
QualType ValueTy = Scratch.getReflectedType();

// Evaluate the number of elements provided.
SmallVector<Expr *, 4> Elems;
if (!Evaluator(Scratch, Args[2], true))
return true;
size_t Length = Scratch.getInt().getExtValue();
Elems.resize(Length);

for (uint64_t k = 0; k < Length; ++k) {
llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false);
Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(),
Args[3]->getExprLoc());

Synthesized = new (C) ArraySubscriptExpr(Args[3], Synthesized, ValueTy,
VK_LValue, OK_Ordinary,
Range.getBegin());
if (Synthesized->isValueDependent() || Synthesized->isTypeDependent())
return true;

APValue Val;
if (!Evaluator(Val, Synthesized, true))
return true;

Synthesized = new (C) OpaqueValueExpr(Range.getBegin(), ValueTy,
VK_PRValue);
Synthesized = ConstantExpr::Create(C, Synthesized, Val);

Elems[k] = Synthesized;
}

std::string Name;
{
static int gen_id = 0;
llvm::raw_string_ostream NameOut(Name);
NameOut << "__gen_array_" << (gen_id++);
}

QualType ArrTy = C.getConstantArrayType(ValueTy, llvm::APSInt::get(Length),
Args[2], ArraySizeModifier::Normal,
/*IndexTypeQuals=*/0);
VarDecl *AnonArr = VarDecl::Create(C, C.getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&C.Idents.get(Name), ArrTy, nullptr,
SC_Static);
{
Expr *ILE = Meta.CreateInitList(Elems, Range);
if (!ILE)
return true;
AnonArr->setConstexpr(true);
Meta.AttachInitializer(AnonArr, ILE);

Meta.BroadcastInjectedDecl(AnonArr);
}
assert(AnonArr->getFormalLinkage() == Linkage::Internal);

APValue::LValuePathEntry Path[1] = {APValue::LValuePathEntry::ArrayIndex(0)};
return SetAndSucceed(Result,
APValue(AnonArr, CharUnits::Zero(), Path, false));
}


bool get_ith_parameter_of(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args) {
Expand Down
93 changes: 56 additions & 37 deletions libcxx/include/experimental/meta
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,6 @@ enum : unsigned {
__metafn_bit_offset_of,
__metafn_bit_size_of,
__metafn_alignment_of,
__metafn_define_static_string,
__metafn_define_static_array,

// P3096 metafunctions
__metafn_get_ith_parameter_of,
Expand Down Expand Up @@ -1438,7 +1436,7 @@ consteval auto reflect_value(T r) -> info {
constexpr info Ty = type_of(LIFT(r));

return __metafunction(detail::__metafn_reflect_result, Ty,
static_cast<typename [:Ty:]>(r));
static_cast<typename [:Ty:] &&>(r));
}

// Returns a reflection of the object designated by the provided argument.
Expand Down Expand Up @@ -1625,31 +1623,52 @@ consteval auto bit_size_of(info r) -> size_t {
return __metafunction(detail::__metafn_bit_size_of, r);
}

// Returns a static string having the provided contents.
consteval auto define_static_string(string_view in) -> const char * {
return __metafunction(detail::__metafn_define_static_string,
LIFT(const char *), LIFT(char), in.size(), in.data(),
/*IsUtf8=*/false);
}
namespace __define_static {

consteval auto define_static_string(u8string_view in) -> const char8_t * {
return __metafunction(detail::__metafn_define_static_string,
LIFT(const char8_t *), LIFT(char8_t),
in.size(), in.data(), /*IsUtf8=*/true);
template <typename ValTy, ValTy... Vals>
inline constexpr ValTy FixedArray[sizeof...(Vals)] = {Vals...};

template <auto &S>
inline constexpr span StaticSpan(S, size(S));

template <typename ValTy>
consteval span<const ValTy> impl(const span<const ValTy> &in) {
if (in.size() == 0)
return {};

vector Args = {^^ValTy};
for (const auto &V : in)
Args.push_back(reflect_value(V));

return extract<span<const ValTy>>(
substitute(^^StaticSpan, { substitute(^^FixedArray, Args) }));
}
} // namespace __define_static

template <ranges::input_range R>
requires (is_constructible_v<ranges::range_value_t<R>,
ranges::range_reference_t<R>>)
consteval auto define_static_array(R &&elems)
-> span<const ranges::range_value_t<R>> {
vector vec(from_range, elems);
using ValTy = ranges::range_value_t<R>;
using ImplTy = span<const ValTy>(*)(const span<const ValTy> &);
auto impl = extract<ImplTy>(substitute(^^__define_static::impl, {^^ValTy}));

using value_t = ranges::range_value_t<R>;
const value_t *arr = __metafunction(detail::__metafn_define_static_array,
LIFT(const value_t *), LIFT(value_t),
vec.size(), vec.data());
return span<const ranges::range_value_t<R>>(arr, vec.size());
vector<ValTy> vals(from_range, elems);
return impl(vals);
}

// Returns a static string having the provided contents.
consteval auto define_static_string(string_view in) -> const char * {
const char nullterm[1] = {0};
vector<span<const char>> v = {in, nullterm};
return define_static_array(views::join(v)).data();
}

consteval auto define_static_string(u8string_view in) -> const char8_t * {
const char8_t nullterm[1] = {0};
vector<span<const char8_t>> v = {in, nullterm};
return define_static_array(views::join(v)).data();
}


Expand Down Expand Up @@ -2149,7 +2168,7 @@ consteval auto type_tuple_size(info type) -> size_t {

consteval auto type_tuple_element(size_t index, info type) -> info {
return dealias(substitute(LIFT(tuple_element_t),
{std::meta::reflect_value(index), type}));
{reflect_value(index), type}));
}

consteval auto type_variant_size(info type) -> size_t {
Expand All @@ -2158,7 +2177,7 @@ consteval auto type_variant_size(info type) -> size_t {

consteval auto type_variant_alternative(size_t index, info type) -> info {
return dealias(substitute(LIFT(variant_alternative_t),
{std::meta::reflect_value(index), type}));
{reflect_value(index), type}));
}


Expand Down Expand Up @@ -2241,7 +2260,7 @@ consteval auto annotations_of(info r, info ty) -> vector<info> {

template<typename T>
consteval optional<T> annotation_of_type(info r) {
auto v = annotations_of(r, ^^T);
auto v = annotations_of(r, LIFT(T));
optional<T> result{};
for (info a: v) {
if (result.has_value()) {
Expand Down Expand Up @@ -2325,13 +2344,13 @@ struct pretty_printer {

using string_t = basic_string<CharT>;

static consteval const CharT *string_constant(std::string_view contents) {
static consteval const CharT *string_constant(string_view contents) {
if constexpr (IsUtf8) {
std::u8string result(contents.size(), 0);
u8string result(contents.size(), 0);
for (size_t idx = 0; char c : contents)
result[idx++] = char8_t(c);

return std::meta::define_static_string(result);
return define_static_string(result);
} else {
return contents.data();
}
Expand Down Expand Up @@ -2626,15 +2645,15 @@ consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
if constexpr (is_constructor_template(R))
return render<parent_of(R)>();
else if (is_operator_function_template(R)) {
std::meta::operators op = operator_of(R);
operators op = operator_of(R);

string_t result = "operator";
switch (op) {
case std::meta::operators::op_new:
case std::meta::operators::op_delete:
case std::meta::operators::op_array_new:
case std::meta::operators::op_array_delete:
case std::meta::operators::op_co_await:
case operators::op_new:
case operators::op_delete:
case operators::op_array_new:
case operators::op_array_delete:
case operators::op_co_await:
result += " ";
[[fallthrough]];
default:
Expand Down Expand Up @@ -2675,15 +2694,15 @@ consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
} else if constexpr (is_constructor(R)) {
return render<parent_of(R)>();
} else if constexpr (is_operator_function(R)) {
std::meta::operators op = operator_of(R);
operators op = operator_of(R);

result = "operator";
switch (op) {
case std::meta::operators::op_new:
case std::meta::operators::op_delete:
case std::meta::operators::op_array_new:
case std::meta::operators::op_array_delete:
case std::meta::operators::op_co_await:
case operators::op_new:
case operators::op_delete:
case operators::op_array_new:
case operators::op_array_delete:
case operators::op_co_await:
result += " ";
[[fallthrough]];
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct Cls {
};
constexpr auto objs = std::meta::define_static_array(std::vector<Cls>{1, 3, 5});
static_assert(objs.size() == 3);
static_assert(objs[0].k == 3 && objs[1].k == 5 && objs[2].k == 7);
static_assert(objs[0].k == 5 && objs[1].k == 7 && objs[2].k == 9);

constexpr auto infos = std::meta::define_static_array(
nonstatic_data_members_of(^^Cls));
Expand Down

0 comments on commit 5a5e1a4

Please sign in to comment.