mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
Implement std::meta::{,u8}identifier_of.
This commit is contained in:
committed by
Marek Polacek
parent
2e8b6092f5
commit
c80c5aba39
@@ -2366,7 +2366,7 @@ eval_bit_size_of (location_t loc, const constexpr_ctx *ctx, tree r,
|
||||
namespace, or namespace alias, then true.
|
||||
-- Otherwise, if r represents a direct base class relationship, then
|
||||
has_identifier(type_of(r)).
|
||||
-- Otherwise, r represents a data member description (T,N,A,W,NUA), true if
|
||||
-- Otherwise, r represents a data member description (T,N,A,W,NUA); true if
|
||||
N is not _|_. Otherwise, false. */
|
||||
|
||||
static tree
|
||||
@@ -2461,6 +2461,87 @@ eval_has_identifier (tree r, reflect_kind kind)
|
||||
return boolean_false_node;
|
||||
}
|
||||
|
||||
/* Process std::meta::{,u8}identifier_of.
|
||||
Let E be UTF-8 for u8identifier_of, and otherwise the ordinary literal
|
||||
encoding.
|
||||
Returns: An NTMBS, encoded with E, determined as follows:
|
||||
-- If r represents an entity with a typedef name for linkage purposes,
|
||||
then that name.
|
||||
-- Otherwise, if r represents a literal operator or literal operator
|
||||
template, then the ud-suffix of the operator or operator template.
|
||||
-- Otherwise, if r represents the parameter P of a function F, then let S
|
||||
be the set of declarations, ignoring any explicit instantiations, that
|
||||
precede some point in the evaluation context and that declare either F
|
||||
or a templated function of which F is a specialization; the name that
|
||||
was introduced by a declaration in S for the parameter corresponding
|
||||
to P.
|
||||
-- Otherwise, if r represents an entity, then the identifier introduced by
|
||||
the declaration of that entity.
|
||||
-- Otherwise, if r represents a direct base class relationship, then
|
||||
identifier_of(type_of(r)) or u8identifier_of(type_of(r)), respectively.
|
||||
-- Otherwise, r represents a data member description (T,N,A,W,NUA);
|
||||
a string_view or u8string_view, respectively, containing the identifier
|
||||
N.
|
||||
Throws: meta::exception unless has_identifier(r) is true and the identifier
|
||||
that would be returned (see above) is representable by E. */
|
||||
|
||||
static tree
|
||||
eval_identifier_of (location_t loc, const constexpr_ctx *ctx, tree r,
|
||||
reflect_kind kind, tree *jump_target,
|
||||
tree elt_type, tree ret_type)
|
||||
{
|
||||
if (eval_has_identifier (r, kind) == boolean_false_node)
|
||||
return throw_exception (loc, ctx, N_("reflection with has_identifier "
|
||||
"false"),
|
||||
r, jump_target);
|
||||
r = MAYBE_BASELINK_FUNCTIONS (r);
|
||||
r = OVL_FIRST (r);
|
||||
const char *name = NULL;
|
||||
if (eval_is_function_parameter (r, kind) == boolean_true_node)
|
||||
{
|
||||
r = maybe_update_function_parm (r);
|
||||
if (DECL_NAME (r))
|
||||
name = IDENTIFIER_POINTER (DECL_NAME (r));
|
||||
else
|
||||
{
|
||||
tree opn = lookup_attribute ("old parm name", DECL_ATTRIBUTES (r));
|
||||
opn = TREE_VALUE (TREE_VALUE (opn));
|
||||
name = IDENTIFIER_POINTER (opn);
|
||||
}
|
||||
}
|
||||
else if (DECL_P (r) && UDLIT_OPER_P (DECL_NAME (r)))
|
||||
name = UDLIT_OP_SUFFIX (DECL_NAME (r));
|
||||
else if (DECL_P (r))
|
||||
name = IDENTIFIER_POINTER (DECL_NAME (r));
|
||||
else if (TYPE_P (r))
|
||||
{
|
||||
if (DECL_P (TYPE_NAME (r)))
|
||||
name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (r)));
|
||||
else
|
||||
name = IDENTIFIER_POINTER (TYPE_NAME (r));
|
||||
}
|
||||
// TODO: direct base class relationship and data member description.
|
||||
else
|
||||
gcc_unreachable ();
|
||||
tree str = temp_string_literal (name, elt_type);
|
||||
if (str == NULL_TREE)
|
||||
{
|
||||
if (elt_type == char_type_node)
|
||||
return throw_exception (loc, ctx, N_("identifier_of not representable"
|
||||
" in ordinary literal encoding"),
|
||||
r, jump_target);
|
||||
else
|
||||
return throw_exception (loc, ctx, N_("u8identifier_of not representable"
|
||||
" in UTF-8"),
|
||||
r, jump_target);
|
||||
}
|
||||
releasing_vec args (make_tree_vector_single (str));
|
||||
tree ret = build_special_member_call (NULL_TREE, complete_ctor_identifier,
|
||||
&args, ret_type, LOOKUP_NORMAL,
|
||||
tf_warning_or_error);
|
||||
return build_cplus_new (ret_type, ret, tf_warning_or_error);
|
||||
}
|
||||
|
||||
/* Get the reflection of template argument ARG as per
|
||||
std::meta::template_arguments_of. */
|
||||
|
||||
@@ -4675,6 +4756,12 @@ process_metafunction (const constexpr_ctx *ctx, tree call,
|
||||
tree h1 = REFLECT_EXPR_HANDLE (i1);
|
||||
return eval_type_order (loc, ctx, h, h1, jump_target);
|
||||
}
|
||||
if (id_equal (name, "identifier_of"))
|
||||
return eval_identifier_of (loc, ctx, h, kind, jump_target, char_type_node,
|
||||
TREE_TYPE (call));
|
||||
if (id_equal (name, "u8identifier_of"))
|
||||
return eval_identifier_of (loc, ctx, h, kind, jump_target,
|
||||
char8_type_node, TREE_TYPE (call));
|
||||
|
||||
not_found:
|
||||
sorry ("%qE", name);
|
||||
|
||||
@@ -4,11 +4,152 @@
|
||||
|
||||
#include <meta>
|
||||
|
||||
using namespace std::meta;
|
||||
|
||||
struct C { };
|
||||
|
||||
#if 0
|
||||
constexpr std::string_view sv = std::meta::identifier_of(^^C);
|
||||
static_assert(sv == "C");
|
||||
static_assert(sv.data()[0] == 'C');
|
||||
static_assert(sv.data()[1] == '\0');
|
||||
#endif
|
||||
constexpr std::string_view sv = identifier_of (^^C);
|
||||
static_assert (sv == "C");
|
||||
static_assert (sv.data ()[0] == 'C');
|
||||
static_assert (sv.data ()[1] == '\0');
|
||||
|
||||
struct S { };
|
||||
using T = int;
|
||||
using U = S;
|
||||
enum E { E1, E2 };
|
||||
|
||||
static_assert (identifier_of (^^T) == std::string_view ("T"));
|
||||
static_assert (identifier_of (^^S) == std::string_view ("S"));
|
||||
static_assert (identifier_of (^^U) == std::string_view ("U"));
|
||||
static_assert (identifier_of (^^std) == std::string_view ("std"));
|
||||
static_assert (identifier_of (^^std::meta) == std::string_view ("meta"));
|
||||
static_assert (identifier_of (^^E1) == std::string_view ("E1"));
|
||||
// TODO: the standard doesn't specify what happens on enumeral types.
|
||||
// nor annotations nor non-class non-type alias types.
|
||||
// We probably want identifier_of on enumeral types unless they
|
||||
// are unnamed, but I think not on other types and not on annotations.
|
||||
//static_assert (identifier_of (^^E) == std::string_view ("E"));
|
||||
|
||||
namespace N {}
|
||||
namespace NA = N;
|
||||
static_assert (identifier_of (^^N) == std::string_view ("N"));
|
||||
static_assert (identifier_of (^^NA) == std::string_view ("NA"));
|
||||
|
||||
namespace {
|
||||
int a;
|
||||
namespace M {}
|
||||
static_assert (identifier_of (^^a) == std::string_view ("a"));
|
||||
static_assert (identifier_of (^^M) == std::string_view ("M"));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
static_assert (identifier_of (^^a) == std::string_view ("a"));
|
||||
} SV;
|
||||
static_assert (identifier_of (^^SV) == std::string_view ("SV"));
|
||||
static_assert (identifier_of (parent_of (^^SV::a)) == std::string_view ("SV"));
|
||||
|
||||
template <int N>
|
||||
struct ST
|
||||
{
|
||||
static_assert (identifier_of (^^ST) == std::string_view ("ST"));
|
||||
};
|
||||
|
||||
struct V
|
||||
{
|
||||
void foo () { int a; static_assert (identifier_of (parent_of (^^a)) == std::string_view ("foo")); }
|
||||
template <int N>
|
||||
void bar () { int a; static_assert (identifier_of (parent_of (^^a)) == std::string_view ("bar")); }
|
||||
};
|
||||
|
||||
int
|
||||
operator ""_a (const char *)
|
||||
{
|
||||
int a;
|
||||
static_assert (identifier_of (parent_of (^^a)) == std::string_view ("_a"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v;
|
||||
static_assert (identifier_of (^^V::foo) == std::string_view ("foo"));
|
||||
static_assert (identifier_of (^^V::bar) == std::string_view ("bar"));
|
||||
|
||||
void foo (int);
|
||||
static_assert (identifier_of (^^foo) == std::string_view ("foo"));
|
||||
|
||||
int arr[3];
|
||||
|
||||
void
|
||||
foo (int a)
|
||||
{
|
||||
auto [b, c, d] = arr;
|
||||
static_assert (identifier_of (^^foo) == std::string_view ("foo"));
|
||||
static_assert (identifier_of (^^a) == std::string_view ("a"));
|
||||
static_assert (identifier_of (^^b) == std::string_view ("b"));
|
||||
static_assert (identifier_of (^^c) == std::string_view ("c"));
|
||||
static_assert (identifier_of (^^d) == std::string_view ("d"));
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
bar (int a)
|
||||
{
|
||||
auto [...b, c] = arr;
|
||||
static_assert (identifier_of (^^a) == std::string_view ("a"));
|
||||
static_assert (identifier_of (^^c) == std::string_view ("c"));
|
||||
}
|
||||
|
||||
void
|
||||
baz ()
|
||||
{
|
||||
auto a = [] {
|
||||
int a;
|
||||
static_assert (identifier_of (^^a) == std::string_view ("a"));
|
||||
static_assert (identifier_of (parent_of (parent_of (parent_of (^^a)))) == std::string_view ("baz"));
|
||||
};
|
||||
using t = decltype (a);
|
||||
static_assert (identifier_of (^^t) == std::string_view ("t"));
|
||||
}
|
||||
|
||||
void qux (int, int b, int c, int d, int);
|
||||
constexpr auto p0 = parameters_of (^^qux)[0];
|
||||
constexpr auto p1 = parameters_of (^^qux)[1];
|
||||
constexpr auto p2 = parameters_of (^^qux)[2];
|
||||
constexpr auto p3 = parameters_of (^^qux)[3];
|
||||
constexpr auto p4 = parameters_of (^^qux)[4];
|
||||
static_assert (identifier_of (p1) == std::string_view ("b"));
|
||||
static_assert (identifier_of (p2) == std::string_view ("c"));
|
||||
static_assert (identifier_of (p3) == std::string_view ("d"));
|
||||
void qux (int a, int, int c, int e, int);
|
||||
static_assert (identifier_of (p0) == std::string_view ("a"));
|
||||
static_assert (identifier_of (p1) == std::string_view ("b"));
|
||||
static_assert (identifier_of (p2) == std::string_view ("c"));
|
||||
|
||||
void
|
||||
qux (int a, int, int, int e, int)
|
||||
{
|
||||
static_assert (identifier_of (p0) == std::string_view ("a"));
|
||||
static_assert (identifier_of (p1) == std::string_view ("b"));
|
||||
static_assert (identifier_of (p2) == std::string_view ("c"));
|
||||
static_assert (identifier_of (variable_of (p0)) == std::string_view ("a"));
|
||||
static_assert (identifier_of (variable_of (p3)) == std::string_view ("e"));
|
||||
}
|
||||
|
||||
void qux (int f, int, int, int, int g);
|
||||
static_assert (identifier_of (p1) == std::string_view ("b"));
|
||||
static_assert (identifier_of (p2) == std::string_view ("c"));
|
||||
static_assert (identifier_of (p4) == std::string_view ("g"));
|
||||
|
||||
template <typename... T>
|
||||
void
|
||||
freddy (int a, T... b)
|
||||
{
|
||||
}
|
||||
|
||||
static_assert (identifier_of (parameters_of (^^freddy <int, long, char>)[0]) == std::string_view ("a"));
|
||||
|
||||
struct {
|
||||
int a;
|
||||
} s;
|
||||
|
||||
static_assert (identifier_of (^^s) == std::string_view ("s"));
|
||||
|
||||
6
gcc/testsuite/g++.dg/reflect/identifier_of2.C
Normal file
6
gcc/testsuite/g++.dg/reflect/identifier_of2.C
Normal file
@@ -0,0 +1,6 @@
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-iconv "IBM1047" }
|
||||
// { dg-additional-options "-freflection -fexec-charset=IBM1047" }
|
||||
// Test std::meta::identifier_of.
|
||||
|
||||
#include "identifier_of1.C"
|
||||
159
gcc/testsuite/g++.dg/reflect/u8identifier_of1.C
Normal file
159
gcc/testsuite/g++.dg/reflect/u8identifier_of1.C
Normal file
@@ -0,0 +1,159 @@
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-additional-options "-freflection" }
|
||||
// Test std::meta::u8identifier_of.
|
||||
|
||||
#include <meta>
|
||||
|
||||
using namespace std::meta;
|
||||
|
||||
struct C { };
|
||||
|
||||
constexpr std::u8string_view sv = std::meta::u8identifier_of (^^C);
|
||||
static_assert (sv == u8"C");
|
||||
static_assert (sv.data ()[0] == u8'C');
|
||||
static_assert (sv.data ()[1] == u8'\0');
|
||||
|
||||
struct S { };
|
||||
using T = int;
|
||||
using U = S;
|
||||
enum E { E1, E2 };
|
||||
|
||||
static_assert (u8identifier_of (^^T) == std::u8string_view (u8"T"));
|
||||
static_assert (u8identifier_of (^^S) == std::u8string_view (u8"S"));
|
||||
static_assert (u8identifier_of (^^U) == std::u8string_view (u8"U"));
|
||||
static_assert (u8identifier_of (^^std) == std::u8string_view (u8"std"));
|
||||
static_assert (u8identifier_of (^^std::meta) == std::u8string_view (u8"meta"));
|
||||
static_assert (u8identifier_of (^^E1) == std::u8string_view (u8"E1"));
|
||||
// TODO: the standard doesn't specify what happens on enumeral types.
|
||||
// nor annotations nor non-class non-type alias types.
|
||||
// We probably want u8identifier_of on enumeral types unless they
|
||||
// are unnamed, but I think not on other types and not on annotations.
|
||||
//static_assert (u8identifier_of (^^E) == std::u8string_view (u8"E"));
|
||||
|
||||
namespace N {}
|
||||
namespace NA = N;
|
||||
static_assert (u8identifier_of (^^N) == std::u8string_view (u8"N"));
|
||||
static_assert (u8identifier_of (^^NA) == std::u8string_view (u8"NA"));
|
||||
|
||||
namespace {
|
||||
int a;
|
||||
namespace M {}
|
||||
static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (^^M) == std::u8string_view (u8"M"));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
|
||||
} SV;
|
||||
static_assert (u8identifier_of (^^SV) == std::u8string_view (u8"SV"));
|
||||
static_assert (u8identifier_of (parent_of (^^SV::a)) == std::u8string_view (u8"SV"));
|
||||
|
||||
template <int N>
|
||||
struct ST
|
||||
{
|
||||
static_assert (u8identifier_of (^^ST) == std::u8string_view (u8"ST"));
|
||||
};
|
||||
|
||||
struct V
|
||||
{
|
||||
void foo () { int a; static_assert (u8identifier_of (parent_of (^^a)) == std::u8string_view (u8"foo")); }
|
||||
template <int N>
|
||||
void bar () { int a; static_assert (u8identifier_of (parent_of (^^a)) == std::u8string_view (u8"bar")); }
|
||||
};
|
||||
|
||||
int
|
||||
operator ""_a (const char *)
|
||||
{
|
||||
int a;
|
||||
static_assert (u8identifier_of (parent_of (^^a)) == std::u8string_view (u8"_a"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v;
|
||||
static_assert (u8identifier_of (^^V::foo) == std::u8string_view (u8"foo"));
|
||||
static_assert (u8identifier_of (^^V::bar) == std::u8string_view (u8"bar"));
|
||||
|
||||
void foo (int);
|
||||
static_assert (u8identifier_of (^^foo) == std::u8string_view (u8"foo"));
|
||||
|
||||
int arr[3];
|
||||
|
||||
void
|
||||
foo (int a)
|
||||
{
|
||||
auto [b, c, d] = arr;
|
||||
static_assert (u8identifier_of (^^foo) == std::u8string_view (u8"foo"));
|
||||
static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (^^b) == std::u8string_view (u8"b"));
|
||||
static_assert (u8identifier_of (^^c) == std::u8string_view (u8"c"));
|
||||
static_assert (u8identifier_of (^^d) == std::u8string_view (u8"d"));
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
bar (int a)
|
||||
{
|
||||
auto [...b, c] = arr;
|
||||
static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (^^c) == std::u8string_view (u8"c"));
|
||||
}
|
||||
|
||||
void
|
||||
baz ()
|
||||
{
|
||||
auto a = [] {
|
||||
int a;
|
||||
static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (parent_of (parent_of (parent_of (^^a)))) == std::u8string_view (u8"baz"));
|
||||
};
|
||||
using t = decltype (a);
|
||||
static_assert (u8identifier_of (^^t) == std::u8string_view (u8"t"));
|
||||
}
|
||||
|
||||
void qux (int, int b, int c, int d, int);
|
||||
constexpr auto p0 = parameters_of (^^qux)[0];
|
||||
constexpr auto p1 = parameters_of (^^qux)[1];
|
||||
constexpr auto p2 = parameters_of (^^qux)[2];
|
||||
constexpr auto p3 = parameters_of (^^qux)[3];
|
||||
constexpr auto p4 = parameters_of (^^qux)[4];
|
||||
static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
|
||||
static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
|
||||
static_assert (u8identifier_of (p3) == std::u8string_view (u8"d"));
|
||||
void qux (int a, int, int c, int e, int);
|
||||
static_assert (u8identifier_of (p0) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
|
||||
static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
|
||||
|
||||
void
|
||||
qux (int a, int, int, int e, int)
|
||||
{
|
||||
static_assert (u8identifier_of (p0) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
|
||||
static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
|
||||
static_assert (u8identifier_of (variable_of (p0)) == std::u8string_view (u8"a"));
|
||||
static_assert (u8identifier_of (variable_of (p3)) == std::u8string_view (u8"e"));
|
||||
}
|
||||
|
||||
void qux (int f, int, int, int, int g);
|
||||
static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
|
||||
static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
|
||||
static_assert (u8identifier_of (p4) == std::u8string_view (u8"g"));
|
||||
|
||||
template <typename... T>
|
||||
void
|
||||
freddy (int a, T... b)
|
||||
{
|
||||
}
|
||||
|
||||
static_assert (u8identifier_of (parameters_of (^^freddy <int, long, char>)[0]) == std::u8string_view (u8"a"));
|
||||
|
||||
struct {
|
||||
int a;
|
||||
} s;
|
||||
|
||||
static_assert (u8identifier_of (^^s) == std::u8string_view (u8"s"));
|
||||
|
||||
int qu\u00E6 = 1;
|
||||
|
||||
static_assert (u8identifier_of (^^qu\u00E6) == std::u8string_view (u8"qu\N{LATIN SMALL LETTER AE}"));
|
||||
@@ -167,6 +167,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
// [meta.reflection.names], reflection names and locations
|
||||
consteval bool has_identifier(info);
|
||||
consteval string_view identifier_of(info);
|
||||
consteval u8string_view u8identifier_of(info);
|
||||
|
||||
consteval source_location source_location_of(info);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user