diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index bb02bed415b..a58f940e01f 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1589,17 +1589,6 @@ save_fundef_copy (tree fun, tree copy)
*slot = copy;
}
-/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST),
- a glvalue (e.g. VAR_DECL or _REF), or nothing. */
-
-enum value_cat {
- vc_prvalue = 0,
- vc_glvalue = 1,
- vc_discard = 2
-};
-
-static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
- value_cat, bool *, bool *, tree *);
static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree,
value_cat, bool *, bool *, tree *);
static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree,
@@ -3805,8 +3794,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- tree e = process_metafunction (ctx, t, jump_target);
- if (throws (jump_target))
+ tree e = process_metafunction (ctx, t, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
return NULL_TREE;
e = cxx_eval_constant_expression (ctx, e, vc_prvalue,
non_constant_p, overflow_p,
@@ -8886,7 +8876,7 @@ merge_jump_target (location_t loc, const constexpr_ctx *ctx, tree r,
/* FIXME unify with c_fully_fold */
/* FIXME overflow_p is too global */
-static tree
+tree
cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
bool *non_constant_p, bool *overflow_p,
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a89bc9cacc8..0d5a2997ff1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9163,6 +9163,18 @@ extern bool replace_decl (tree *, tree, tree);
extern tree cxa_allocate_and_throw_exception (location_t, const constexpr_ctx *,
tree);
+/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST),
+ a glvalue (e.g. VAR_DECL or _REF), or nothing. */
+enum value_cat {
+ vc_prvalue = 0,
+ vc_glvalue = 1,
+ vc_discard = 2
+};
+
+extern tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
+ value_cat, bool *, bool *,
+ tree *);
+
/* An RAII sentinel used to restrict constexpr evaluation so that it
doesn't do anything that causes extra DECL_UID generation. */
@@ -9212,7 +9224,8 @@ extern void coro_set_ramp_function (tree, tree);
/* In reflect.cc */
extern void init_reflection ();
extern bool metafunction_p (tree) ATTRIBUTE_PURE;
-extern tree process_metafunction (const constexpr_ctx *, tree, tree *);
+extern tree process_metafunction (const constexpr_ctx *, tree,
+ bool *, bool *, tree *);
extern tree get_reflection (location_t, tree) ATTRIBUTE_PURE;
extern tree get_null_reflection () ATTRIBUTE_PURE;
extern tree splice (tree);
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index d07944851d5..c1f7e665421 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -237,12 +237,17 @@ metafunction_p (tree fndecl)
/* Extract the N-th reflection argument from a metafunction call CALL. */
static tree
-get_info (tree call, int n)
+get_info (const constexpr_ctx *ctx, tree call, int n, bool *non_constant_p,
+ bool *overflow_p, tree *jump_target)
{
gcc_checking_assert (call_expr_nargs (call) > n);
tree info = get_nth_callarg (call, n);
gcc_checking_assert (REFLECTION_TYPE_P (TREE_TYPE (info)));
- info = cxx_constant_value (info);
+ info = cxx_eval_constant_expression (ctx, info, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
return info;
}
@@ -732,6 +737,83 @@ eval_is_conversion_function_template (const_tree)
gcc_assert (!"TODO");
}
+/* has-type (exposition only).
+ Returns: true if r represents a value, annotation, object, variable,
+ function whose type does not contain an undeduced placeholder type and
+ that is not a constructor or destructor, enumerator, non-static data
+ member, unnamed bit-field, direct base class relationship, data member
+ description, or function parameter. Otherwise, false. */
+
+static bool
+has_type (tree r)
+{
+ r = MAYBE_BASELINK_FUNCTIONS (r);
+ if (TREE_CODE (r) == FUNCTION_DECL)
+ {
+ if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
+ return false;
+ if (undeduced_auto_decl (r))
+ return false;
+ return true;
+ }
+ if (CONSTANT_CLASS_P (r)
+ || eval_is_variable (r) == boolean_true_node
+ || eval_is_enumerator (r) == boolean_true_node
+ || TREE_CODE (r) == FIELD_DECL
+ || eval_is_annotation (r) == boolean_true_node)
+ return true;
+ // TODO: object, direct base class relationship, data member description.
+ return false;
+}
+
+/* Process std::meta::type_of. Returns:
+ -- If r represents the ith parameter of a function F, then the ith type
+ in the parameter-type-list of F.
+ -- Otherwise, if r represents a value, object, variable, function,
+ non-static data member, or unnamed bit-field, then the type of what is
+ represented by r.
+ -- Otherwise, if r represents an annotation, then type_of(constant_of(r)).
+ -- Otherwise, if r represents an enumerator N of an enumeration E, then:
+ -- If E is defined by a declaration D that precedes a point P in the
+ evaluation context and P does not occur within an enum-specifier of
+ D, then a reflection of E.
+ -- Otherwise, a reflection of the type of N prior to the closing brace
+ of the enum-specifier as specified in [dcl.enum].
+ -- Otherwise, if r represents a direct base class relationship (D,B), then
+ a reflection of B.
+ -- Otherwise, for a data member description (T,N,A,W,NUA), a reflection of
+ the type T. */
+
+static tree
+eval_type_of (location_t loc, const constexpr_ctx *ctx, tree r,
+ tree *jump_target)
+{
+ if (!has_type (r))
+ return throw_exception (loc, ctx, N_("reflection does not have a type"),
+ r, jump_target);
+ r = MAYBE_BASELINK_FUNCTIONS (r);
+ if (TREE_CODE (r) == PARM_DECL)
+ {
+ tree fn = DECL_CONTEXT (r);
+ tree args = FUNCTION_FIRST_USER_PARM (fn);
+ tree type = FUNCTION_FIRST_USER_PARMTYPE (fn);
+ while (r != args)
+ {
+ args = DECL_CHAIN (args);
+ type = TREE_CHAIN (type);
+ }
+ r = TREE_VALUE (type);
+ }
+ else if (TREE_CODE (r) == FUNCTION_DECL)
+ r = TREE_TYPE (TREE_TYPE (r));
+ else if (eval_is_annotation (r) == boolean_true_node)
+ // TODO: or do we need to reflect_constant and get type of that?
+ r = TREE_TYPE (TREE_VALUE (TREE_VALUE (r)));
+ else
+ r = TREE_TYPE (r);
+ return get_reflection_raw (loc, r);
+}
+
/* Process std::meta::dealias.
Returns: A reflection representing the underlying entity of what r
represents.
@@ -1437,7 +1519,9 @@ eval_add_cv (location_t loc, const constexpr_ctx *ctx, tree type,
// TODO Use gperf?
tree
-process_metafunction (const constexpr_ctx *ctx, tree call, tree *jump_target)
+process_metafunction (const constexpr_ctx *ctx, tree call,
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree name = DECL_NAME (cp_get_callee_fndecl_nofold (call));
const char *ident = IDENTIFIER_POINTER (name);
@@ -1446,10 +1530,17 @@ process_metafunction (const constexpr_ctx *ctx, tree call, tree *jump_target)
{
tree expr = get_nth_callarg (call, 0);
location_t loc = cp_expr_loc_or_input_loc (expr);
+ expr = cxx_eval_constant_expression (ctx, expr, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
return eval_reflect_constant (loc, ctx, expr, jump_target);
}
- tree info = get_info (call, 0);
+ tree info = get_info (ctx, call, 0, non_constant_p, overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
tree h = REFLECT_EXPR_HANDLE (info);
const location_t loc = cp_expr_loc_or_input_loc (info);
@@ -1542,38 +1633,66 @@ process_metafunction (const constexpr_ctx *ctx, tree call, tree *jump_target)
return eval_is_arithmetic_type (loc, ctx, h, jump_target);
if (!strcmp (ident, "same_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_same_type (loc, ctx, h, h1, jump_target);
}
if (!strcmp (ident, "base_of_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_base_of_type (loc, ctx, h, h1, jump_target);
}
if (!strcmp (ident, "virtual_base_of_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_virtual_base_of_type (loc, ctx, h, h1, jump_target);
}
if (!strcmp (ident, "convertible_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_convertible_type (loc, ctx, h, h1, jump_target);
}
if (!strcmp (ident, "nothrow_convertible_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_nothrow_convertible_type (loc, ctx, h, h1,
jump_target);
}
if (!strcmp (ident, "layout_compatible_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_layout_compatible_type (loc, ctx, h, h1, jump_target);
}
if (!strcmp (ident, "pointer_interconvertible_base_of_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_is_pointer_interconvertible_base_of_type (loc, ctx, h, h1,
jump_target);
}
@@ -1615,9 +1734,15 @@ process_metafunction (const constexpr_ctx *ctx, tree call, tree *jump_target)
return eval_annotations_of (loc, ctx, h, NULL_TREE, jump_target);
if (id_equal (name, "annotations_of_with_type"))
{
- tree h1 = REFLECT_EXPR_HANDLE (get_info (call, 1));
+ tree i1 = get_info (ctx, call, 1, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ tree h1 = REFLECT_EXPR_HANDLE (i1);
return eval_annotations_of (loc, ctx, h, h1, jump_target);
}
+ if (id_equal (name, "type_of"))
+ return eval_type_of (loc, ctx, h, jump_target);
not_found:
sorry ("%qE", name);
diff --git a/gcc/testsuite/g++.dg/reflect/type_of1.C b/gcc/testsuite/g++.dg/reflect/type_of1.C
new file mode 100644
index 00000000000..d350c3d12ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/type_of1.C
@@ -0,0 +1,151 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::type_of.
+
+#include
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+ int mem;
+ int : 0;
+};
+struct T {
+ T ();
+ T (const T &);
+ ~T ();
+};
+struct U {
+ int u;
+};
+template struct TCls {};
+template void TFn();
+template int TVar;
+template concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+// constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_type (info r)
+{
+ try { type_of (r); }
+ catch (std::meta::exception &) { return false; }
+ return true;
+}
+
+static_assert (has_type (std::meta::reflect_constant (42)));
+//static_assert (has_type (std::meta::reflect_object (arr[1])));
+static_assert (has_type (^^arr));
+static_assert (!has_type (^^a3));
+static_assert (has_type (^^fn));
+static_assert (!has_type (^^fn2));
+static_assert (has_type (^^Enum::A));
+static_assert (!has_type (^^Alias));
+static_assert (!has_type (^^S));
+static_assert (has_type (^^S::mem));
+//static_assert (has_type (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!has_type (^^TCls));
+static_assert (!has_type (^^TFn));
+static_assert (!has_type (^^TVar));
+static_assert (!has_type (^^Concept));
+static_assert (!has_type (^^NSAlias));
+static_assert (!has_type (^^NS));
+//static_assert (has_type (std::meta::bases_of (^^S, ctx)[0]));
+//static_assert (has_type (std::meta::data_member_spec (^^int, {.name="member"})));
+
+int
+foo (int a, const long b, T c, int d[4], T &e)
+{
+ static_assert (has_type (^^a));
+ static_assert (has_type (^^b));
+ static_assert (has_type (^^c));
+ static_assert (has_type (^^d));
+ static_assert (has_type (^^e));
+ static_assert (type_of (^^a) == ^^int);
+ static_assert (type_of (^^b) == ^^long);
+ static_assert (type_of (^^c) == ^^T);
+ using ptr = int *;
+ static_assert (type_of (^^d) == dealias (^^ptr));
+ using ref = T &;
+ static_assert (type_of (^^e) == dealias (^^ref));
+ return 0;
+}
+
+static_assert (type_of (std::meta::reflect_constant (42)) == ^^int);
+static_assert (type_of (std::meta::reflect_constant (42.0)) == ^^double);
+//static_assert (type_of (std::meta::reflect_constant (U { 42 })) == ^^U);
+//static_assert (type_of (std::meta::reflect_object (arr[1])) == ^int);
+using int3 = int[3];
+static_assert (type_of (^^arr) == dealias (^^int3));
+static_assert (type_of (^^fn) == ^^void);
+static_assert (type_of (^^Enum::A) == ^^Enum);
+static_assert (type_of (^^A) == ^^Enum);
+static_assert (type_of (^^S::mem) == ^^int);
+//static_assert (type_of (std::meta::members_of (^^S, ctx)[1]) == ??);
+//static_assert (type_of (std::meta::bases_of (^^S, ctx)[0]) == ??);
+//static_assert (type_of (std::meta::data_member_spec (^^int, {.name="member"})) == ??);
+
+consteval int
+test (info x, info y)
+{
+ if (x == y)
+ return 0;
+ throw 1;
+}
+
+using ull = unsigned long long;
+
+enum Enum2 {
+ E21,
+ E22,
+ E23 = 3L,
+ E24,
+ E25 = 5ULL,
+ E26,
+ E27 = 7 + test (type_of (^^E21), ^^int)
+ + test (type_of (^^E22), ^^int)
+ + test (type_of (^^E23), ^^long)
+ + test (type_of (^^E24), ^^long)
+ + test (type_of (^^E25), dealias (^^ull))
+ + test (type_of (^^E26), dealias (^^ull))
+};
+
+static_assert (type_of (^^E21) == ^^Enum2);
+static_assert (type_of (^^E22) == ^^Enum2);
+static_assert (type_of (^^E23) == ^^Enum2);
+static_assert (type_of (^^E24) == ^^Enum2);
+static_assert (type_of (^^E25) == ^^Enum2);
+static_assert (type_of (^^E26) == ^^Enum2);
+static_assert (type_of (^^E27) == ^^Enum2);
+
+enum Enum3 : long {
+ E31,
+ E32,
+ E33 = 3L,
+ E34,
+ E35 = 5ULL,
+ E36,
+ E37 = 7 + test (type_of (^^E31), ^^long)
+ + test (type_of (^^E32), ^^long)
+ + test (type_of (^^E33), ^^long)
+ + test (type_of (^^E34), ^^long)
+ + test (type_of (^^E35), ^^long)
+ + test (type_of (^^E36), ^^long)
+};
+
+static_assert (type_of (^^E31) == ^^Enum3);
+static_assert (type_of (^^E32) == ^^Enum3);
+static_assert (type_of (^^E33) == ^^Enum3);
+static_assert (type_of (^^E34) == ^^Enum3);
+static_assert (type_of (^^E35) == ^^Enum3);
+static_assert (type_of (^^E36) == ^^Enum3);
+static_assert (type_of (^^E37) == ^^Enum3);
diff --git a/libstdc++-v3/include/std/meta b/libstdc++-v3/include/std/meta
index 67b756ddd61..b13f5a6b438 100644
--- a/libstdc++-v3/include/std/meta
+++ b/libstdc++-v3/include/std/meta
@@ -89,6 +89,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
consteval bool has_identifier(info);
// [meta.reflection.queries], reflection queries
+ consteval info type_of(info);
consteval bool is_enumerator(info);
consteval bool is_annotation(info);