diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index eec06cd5887..0febbbb5e57 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -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); diff --git a/gcc/testsuite/g++.dg/reflect/identifier_of1.C b/gcc/testsuite/g++.dg/reflect/identifier_of1.C index fd5add1f683..c7eb89a611a 100644 --- a/gcc/testsuite/g++.dg/reflect/identifier_of1.C +++ b/gcc/testsuite/g++.dg/reflect/identifier_of1.C @@ -4,11 +4,152 @@ #include +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 +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 + 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 +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 +void +freddy (int a, T... b) +{ +} + +static_assert (identifier_of (parameters_of (^^freddy )[0]) == std::string_view ("a")); + +struct { + int a; +} s; + +static_assert (identifier_of (^^s) == std::string_view ("s")); diff --git a/gcc/testsuite/g++.dg/reflect/identifier_of2.C b/gcc/testsuite/g++.dg/reflect/identifier_of2.C new file mode 100644 index 00000000000..115382fb5a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/identifier_of2.C @@ -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" diff --git a/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C b/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C new file mode 100644 index 00000000000..23a4a3515b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C @@ -0,0 +1,159 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::u8identifier_of. + +#include + +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 +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 + 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 +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 +void +freddy (int a, T... b) +{ +} + +static_assert (u8identifier_of (parameters_of (^^freddy )[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}")); diff --git a/libstdc++-v3/include/std/meta b/libstdc++-v3/include/std/meta index b70ac7f8b42..9a31b1561c8 100644 --- a/libstdc++-v3/include/std/meta +++ b/libstdc++-v3/include/std/meta @@ -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);