diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e2e98924333..c7b9352b083 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1925,6 +1925,8 @@ enum reflect_kind : addr_space_t { REFLECT_OBJECT, /* The reflection represents a function parameter. */ REFLECT_PARM, + /* The reflection represents a data member description. */ + REFLECT_DATA_MEMBER_SPEC, }; /* The reflect_kind of a REFLECT_EXPR. */ diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 15f192fefcc..24e84eac1c3 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -398,8 +398,6 @@ fail_ret: minidx = tree_to_uhwi (TREE_OPERAND (data, 1)); data = TREE_OPERAND (data, 0); } - if (TREE_CODE (data) != VAR_DECL) - goto non_contiguous; data = cxx_eval_constant_expression (ctx, data, vc_prvalue, non_constant_p, overflow_p, jump_target); @@ -432,7 +430,7 @@ fail_ret: if (!tree_fits_uhwi_p (lo) || !tree_fits_uhwi_p (hi)) goto non_contiguous; unsigned HOST_WIDE_INT m = tree_to_uhwi (hi); - for (j = tree_to_uhwi (lo); j < m; ++j) + for (j = tree_to_uhwi (lo); j <= m; ++j) if (j >= minidx && j - minidx < sz) TREE_VEC_ELT (ret, j - minidx) = value; } @@ -1151,6 +1149,22 @@ eval_is_function_parameter (const_tree r, reflect_kind kind) return boolean_false_node; } +/* Process std::meta::is_data_member_spec. + Returns: true if r represents a data member description. + Otherwise, false. */ + +static tree +eval_is_data_member_spec (const_tree r, reflect_kind kind) +{ + if (kind == REFLECT_DATA_MEMBER_SPEC) + { + gcc_checking_assert (TREE_CODE (r) == TREE_VEC); + return boolean_true_node; + } + else + return boolean_false_node; +} + /* Process std::meta::is_explicit_object_parameter. Returns: true if r represents a function parameter that is an explicit object parameter. Otherwise, false. */ @@ -1339,14 +1353,15 @@ eval_is_explicit (tree r) /* Process std::meta::is_bit_field. Returns: true if r represents a bit-field, or if r represents a data member - description (T,N,A,W,NUA) for which W is not _|_.. Otherwise, false. */ + description (T,N,A,W,NUA) for which W is not _|_. Otherwise, false. */ static tree -eval_is_bit_field (const_tree r) +eval_is_bit_field (const_tree r, reflect_kind kind) { if (TREE_CODE (r) == FIELD_DECL && DECL_C_BIT_FIELD (r)) return boolean_true_node; - // TODO: Handle data member description. + else if (kind == REFLECT_DATA_MEMBER_SPEC && TREE_VEC_ELT (r, 3)) + return boolean_true_node; else return boolean_false_node; } @@ -1939,9 +1954,10 @@ has_type (tree r, reflect_kind kind) || TREE_CODE (r) == FIELD_DECL || eval_is_annotation (r) == boolean_true_node || eval_is_function_parameter (r, kind) == boolean_true_node - || eval_is_object (kind) == boolean_true_node) + || eval_is_object (kind) == boolean_true_node + || kind == REFLECT_DATA_MEMBER_SPEC) return true; - // TODO: direct base class relationship, data member description. + // TODO: direct base class relationship. return false; } @@ -1965,6 +1981,8 @@ type_of (tree r, reflect_kind kind) } r = TREE_VALUE (type); } + else if (kind == REFLECT_DATA_MEMBER_SPEC) + r = TREE_VEC_ELT (r, 0); 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))); @@ -2163,7 +2181,10 @@ eval_template_of (location_t loc, const constexpr_ctx *ctx, tree r, static tree eval_has_parent (tree r, reflect_kind kind) { - if (kind == REFLECT_OBJECT || CONSTANT_CLASS_P (r) || r == global_namespace) + if (kind == REFLECT_OBJECT + || CONSTANT_CLASS_P (r) + || r == global_namespace + || kind == REFLECT_DATA_MEMBER_SPEC) return boolean_false_node; if (TYPE_P (r)) { @@ -2178,8 +2199,7 @@ eval_has_parent (tree r, reflect_kind kind) } r = MAYBE_BASELINK_FUNCTIONS (r); r = OVL_FIRST (r); - // TODO: Handle direct base class relationship and punt on data member - // description. + // TODO: Handle direct base class relationship. if (!DECL_P (r)) return boolean_false_node; if (TREE_CODE (r) != NAMESPACE_DECL && DECL_LANGUAGE (r) == lang_c) @@ -2413,7 +2433,8 @@ eval_size_of (location_t loc, const constexpr_ctx *ctx, tree r, && (eval_is_variable (r, kind) != boolean_true_node || TYPE_REF_P (TREE_TYPE (r))) && (TREE_CODE (r) != FIELD_DECL || DECL_C_BIT_FIELD (r)) - /* TODO: direct base class relationship, data member description. */) + && (kind != REFLECT_DATA_MEMBER_SPEC || TREE_VEC_ELT (r, 3)) + /* TODO: direct base class relationship. */) return throw_exception (loc, ctx, N_("reflection not suitable for size_of"), r, jump_target); @@ -2467,7 +2488,8 @@ eval_bit_size_of (location_t loc, const constexpr_ctx *ctx, tree r, && (eval_is_variable (r, kind) != boolean_true_node || TYPE_REF_P (TREE_TYPE (r))) && TREE_CODE (r) != FIELD_DECL - /* TODO: direct base class relationship, data member description. */) + && kind != REFLECT_DATA_MEMBER_SPEC + /* TODO: direct base class relationship. */) return throw_exception (loc, ctx, N_("reflection not suitable for bit_size_of"), r, jump_target); @@ -2484,6 +2506,8 @@ eval_bit_size_of (location_t loc, const constexpr_ctx *ctx, tree r, type = r; else if (TREE_CODE (r) == FIELD_DECL) type = TREE_TYPE (r); + else if (kind == REFLECT_DATA_MEMBER_SPEC && TREE_VEC_ELT (r, 3)) + return fold_convert (ret_type, TREE_VEC_ELT (r, 3)); else type = type_of (r, kind); if (type == error_mark_node || !COMPLETE_TYPE_P (type)) @@ -2623,7 +2647,9 @@ eval_has_identifier (tree r, reflect_kind kind) || TREE_CODE (r) == FIELD_DECL || (TREE_CODE (r) == NAMESPACE_DECL && r != global_namespace)) return boolean_true_node; - // TODO: direct base class relationship and data member description. + // TODO: direct base class relationship. + if (kind == REFLECT_DATA_MEMBER_SPEC && TREE_VEC_ELT (r, 1)) + return boolean_true_node; return boolean_false_node; } @@ -2686,7 +2712,9 @@ eval_identifier_of (location_t loc, const constexpr_ctx *ctx, tree r, else name = IDENTIFIER_POINTER (TYPE_NAME (r)); } - // TODO: direct base class relationship and data member description. + // TODO: direct base class relationship. + else if (kind == REFLECT_DATA_MEMBER_SPEC) + name = IDENTIFIER_POINTER (TREE_VEC_ELT (r, 1)); else gcc_unreachable (); tree str = temp_string_literal (name, elt_type); @@ -4402,15 +4430,15 @@ eval_can_substitute (location_t loc, const constexpr_ctx *ctx, auto kind = static_cast (REFLECT_EXPR_KIND (ra)); // TODO: It is unclear on what kinds of reflections we should throw // and what kinds of exceptions should merely result in can_substitute - // returning false. Direct base class relationship, data member - // description? + // returning false. Direct base class relationship? if (a == unknown_type_node || kind == REFLECT_PARM || eval_is_namespace (a) == boolean_true_node || eval_is_constructor (a) == boolean_true_node || eval_is_destructor (a) == boolean_true_node || eval_is_annotation (a) == boolean_true_node - || (TREE_CODE (a) == FIELD_DECL && !DECL_UNNAMED_BIT_FIELD (a))) + || (TREE_CODE (a) == FIELD_DECL && !DECL_UNNAMED_BIT_FIELD (a)) + || kind == REFLECT_DATA_MEMBER_SPEC) return throw_exception (loc, ctx, N_("invalid argument to can_substitute"), a, jump_target); @@ -4505,6 +4533,389 @@ eval_substitute (location_t loc, const constexpr_ctx *ctx, return get_reflection_raw (loc, ret); } +/* Process std::meta::data_member_spec. + Returns: A reflection of a data member description (T,N,A,W,NUA) where + -- T is the type represented by dealias(type), + -- N is either the identifier encoded by options.name or _|_ if + options.name does not contain a value, + -- A is either the alignment value held by options.alignment or _|_ if + options.alignment does not contain a value, + -- W is either the value held by options.bit_width or _|_ if + options.bit_width does not contain a value, and + -- NUA is the value held by options.no_unique_address. + Throws: meta::exception unless the following conditions are met: + -- dealias(type) represents either an object type or a reference type; + -- if options.name contains a value, then: + -- holds_alternative(options.name->contents) is true and + get(options.name->contents) contains a valid identifier + that is not a keyword when interpreted with UTF-8, or + -- holds_alternative(options.name->contents) is true and + get(options.name->contents) contains a valid identifier + that is not a keyword when interpreted with the ordinary literal + encoding; + -- if options.name does not contain a value, then options.bit_width + contains a value; + -- if options.bit_width contains a value V, then + -- is_integral_type(type) || is_enum_type(type) is true, + -- options.alignment does not contain a value, + -- options.no_unique_address is false, and + -- if V equals 0, then options.name does not contain a value; and + -- if options.alignment contains a value, it is an alignment value not less + than alignment_of(type). */ + +static tree +eval_data_member_spec (location_t loc, const constexpr_ctx *ctx, + tree type, tree opts, tree call, + bool *non_constant_p, bool *overflow_p, + tree *jump_target) +{ + if (eval_is_type (type) != boolean_true_node) + return throw_exception_nontype (loc, ctx, type, jump_target); + type = strip_typedefs (type); + if (!TYPE_OBJ_P (type) && !TYPE_REF_P (type)) + return throw_exception (loc, ctx, + N_("type is not object or reference type"), + type, jump_target); + opts = convert_from_reference (opts); + if (!CLASS_TYPE_P (TREE_TYPE (opts))) + { + fail: + error_at (loc, "unexpected % argument"); + *non_constant_p = true; + return error_mark_node; + } + tree args[5] = { type, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; + for (tree field = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (opts))); + field; field = next_aggregate_field (DECL_CHAIN (field))) + if (tree name = DECL_NAME (field)) + { + if (id_equal (name, "name")) + args[1] = field; + else if (id_equal (name, "alignment")) + args[2] = field; + else if (id_equal (name, "bit_width")) + args[3] = field; + else if (id_equal (name, "no_unique_address")) + args[4] = field; + } + for (int i = 1; i < 5; ++i) + { + if (args[i] == NULL_TREE) + goto fail; + tree opt = build3 (COMPONENT_REF, TREE_TYPE (args[i]), opts, args[i], + NULL_TREE); + if (i == 4) + { + /* The no_unique_address handling is simple. */ + if (TREE_CODE (TREE_TYPE (opt)) != BOOLEAN_TYPE) + goto fail; + opt = cxx_eval_constant_expression (ctx, opt, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + if (TREE_CODE (opt) != INTEGER_CST) + goto fail; + if (integer_zerop (opt)) + args[i] = boolean_false_node; + else + args[i] = boolean_true_node; + continue; + } + /* Otherwise the member is optional. */ + if (!CLASS_TYPE_P (TREE_TYPE (opt))) + goto fail; + tree has_value = build_static_cast (loc, boolean_type_node, opt, + tf_warning_or_error); + if (error_operand_p (has_value)) + goto fail; + has_value = cxx_eval_constant_expression (ctx, has_value, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + if (TREE_CODE (has_value) != INTEGER_CST) + goto fail; + if (integer_zerop (has_value)) + { + /* If it doesn't have value, store NULL_TREE. */ + args[i] = NULL_TREE; + continue; + } + tree deref = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, opt, + NULL_TREE, tf_warning_or_error); + if (error_operand_p (deref)) + goto fail; + if (i != 1) + { + /* For alignment and bit_width otherwise it should be int. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (deref)) != integer_type_node) + goto fail; + deref = cxx_eval_constant_expression (ctx, deref, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + if (TREE_CODE (deref) != INTEGER_CST) + goto fail; + args[i] = deref; + continue; + } + /* Otherwise it is a name. */ + if (!CLASS_TYPE_P (TREE_TYPE (deref))) + goto fail; + tree fields[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; + for (tree field = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (deref))); + field; field = next_aggregate_field (DECL_CHAIN (field))) + if (tree name = DECL_NAME (field)) + { + if (id_equal (name, "_M_is_u8")) + fields[0] = field; + else if (id_equal (name, "_M_u8s")) + fields[1] = field; + else if (id_equal (name, "_M_s")) + fields[2] = field; + } + for (int j = 0; j < 3; ++j) + { + if (fields[j] == NULL_TREE) + goto fail; + if (j && j == (fields[0] == boolean_true_node ? 2 : 1)) + continue; + tree f = build3 (COMPONENT_REF, TREE_TYPE (fields[j]), deref, + fields[j], NULL_TREE); + if (j == 0) + { + /* The _M_is_u8 handling is simple. */ + if (TREE_CODE (TREE_TYPE (f)) != BOOLEAN_TYPE) + goto fail; + f = cxx_eval_constant_expression (ctx, f, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + if (TREE_CODE (f) != INTEGER_CST) + goto fail; + if (integer_zerop (f)) + fields[0] = boolean_false_node; + else + fields[0] = boolean_true_node; + continue; + } + /* _M_u8s/_M_s handling is the same except for encoding. */ + if (!CLASS_TYPE_P (TREE_TYPE (f))) + goto fail; + tree fns = lookup_qualified_name (TREE_TYPE (f), + get_identifier ("c_str")); + if (error_operand_p (fns)) + goto fail; + f = build_new_method_call (f, fns, NULL, NULL_TREE, LOOKUP_NORMAL, + NULL, tf_warning_or_error); + if (error_operand_p (f)) + goto fail; + f = cxx_eval_constant_expression (ctx, f, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + STRIP_NOPS (f); + if (TREE_CODE (f) != ADDR_EXPR) + goto fail; + f = TREE_OPERAND (f, 0); + f = cxx_eval_constant_expression (ctx, f, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + if (TREE_CODE (f) != CONSTRUCTOR + || TREE_CODE (TREE_TYPE (f)) != ARRAY_TYPE) + goto fail; + tree eltt = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f))); + if (eltt != (j == 1 ? char8_type_node : char_type_node)) + goto fail; + tree field, value; + unsigned k; + unsigned HOST_WIDE_INT l = 0; + bool ntmbs = false; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (f), k, field, value) + if (!tree_fits_shwi_p (value)) + goto fail; + else if (field == NULL_TREE) + { + if (integer_zerop (value)) + { + ntmbs = true; + break; + } + ++l; + } + else if (TREE_CODE (field) == RANGE_EXPR) + { + tree lo = TREE_OPERAND (field, 0); + tree hi = TREE_OPERAND (field, 1); + if (!tree_fits_uhwi_p (lo) || !tree_fits_uhwi_p (hi)) + goto fail; + if (integer_zerop (value)) + { + l = tree_to_uhwi (lo); + ntmbs = true; + break; + } + l = tree_to_uhwi (hi) + 1; + } + else if (tree_fits_uhwi_p (field)) + { + l = tree_to_uhwi (field); + if (integer_zerop (value)) + { + ntmbs = true; + break; + } + ++l; + } + else + goto fail; + if (!ntmbs || l > INT_MAX - 1) + goto fail; + char *namep; + unsigned len = l; + if (l < 64) + namep = XALLOCAVEC (char, l + 1); + else + namep = XNEWVEC (char, l + 1); + memset (namep, 0, l + 1); + l = 0; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (f), k, field, value) + if (field == NULL_TREE) + { + if (integer_zerop (value)) + break; + namep[l] = tree_to_shwi (value); + ++l; + } + else if (TREE_CODE (field) == RANGE_EXPR) + { + tree lo = TREE_OPERAND (field, 0); + tree hi = TREE_OPERAND (field, 1); + if (integer_zerop (value)) + break; + unsigned HOST_WIDE_INT m = tree_to_uhwi (hi); + for (l = tree_to_uhwi (lo); l <= m; ++l) + namep[l] = tree_to_shwi (value); + } + else + { + l = tree_to_uhwi (field); + namep[l++] = tree_to_shwi (value); + } + namep[len] = '\0'; + /* Convert namep from execution charset to SOURCE_CHARSET. */ + cpp_string istr, ostr; + istr.len = strlen (namep) + 1; + istr.text = (const unsigned char *) namep; + if (!cpp_translate_string (parse_in, &istr, &ostr, + j == 2 ? CPP_STRING : CPP_UTF8STRING, + true)) + { + if (len >= 64) + XDELETEVEC (namep); + if (j == 1) + return throw_exception (loc, ctx, + N_("conversion from ordinary literal " + "encoding to source charset " + "failed"), + type, jump_target); + else + return throw_exception (loc, ctx, + N_("conversion from UTF-8 encoding to " + "source charset failed"), + type, jump_target); + } + if (len >= 64) + XDELETEVEC (namep); + if (!cpp_valid_identifier (parse_in, ostr.text)) + return throw_exception (loc, ctx, + N_("name is not a valid identifier"), + type, jump_target); + args[i] = get_identifier ((const char *) ostr.text); + switch (get_identifier_kind (args[i])) + { + case cik_keyword: + return throw_exception (loc, ctx, + N_("name is a keyword"), + type, jump_target); + case cik_trait: + return throw_exception (loc, ctx, + N_("name is a built-in trait"), + type, jump_target); + default: + break; + } + } + } + if (args[1] == NULL_TREE && args[3] == NULL_TREE) + return throw_exception (loc, ctx, + N_("neither name nor bit_width specified"), + type, jump_target); + if (args[3]) + { + if (!CP_INTEGRAL_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE) + return throw_exception (loc, ctx, + N_("bit_width specified with non-integral " + "and non-enumeration type"), + type, jump_target); + if (args[2]) + return throw_exception (loc, ctx, + N_("both alignment and bit_width specified"), + type, jump_target); + if (args[4] == boolean_true_node) + return throw_exception (loc, ctx, + N_("bit_width specified with " + "no_unique_address true"), + type, jump_target); + if (integer_zerop (args[3]) && args[1]) + return throw_exception (loc, ctx, + N_("bit_width 0 with specified name"), + type, jump_target); + if (tree_int_cst_sgn (args[3]) < 0) + return throw_exception (loc, ctx, N_("bit_width is negative"), + type, jump_target); + } + if (args[2]) + { + if (!integer_pow2p (args[2])) + return throw_exception (loc, ctx, + N_("alignment is not power of two"), + type, jump_target); + if (tree_int_cst_sgn (args[2]) < 0) + return throw_exception (loc, ctx, N_("alignment is negative"), + type, jump_target); + tree al = cxx_sizeof_or_alignof_type (loc, type, ALIGNOF_EXPR, true, + tf_none); + if (TREE_CODE (al) == INTEGER_CST + && wi::to_widest (al) > wi::to_widest (args[2])) + return throw_exception (loc, ctx, + N_("alignment is smaller than alignment_of"), + type, jump_target); + } + tree ret = make_tree_vec (5); + for (int i = 0; i < 5; ++i) + TREE_VEC_ELT (ret, i) = args[i]; + return get_reflection_raw (loc, ret, REFLECT_DATA_MEMBER_SPEC); +} + /* Expand a call to a metafunction. CALL is the CALL_EXPR. JUMP_TARGET is set if we are throwing std::meta::exception. */ @@ -4622,7 +5033,7 @@ process_metafunction (const constexpr_ctx *ctx, tree call, if (!strcmp (ident, "explicit")) return eval_is_explicit (h); if (!strcmp (ident, "bit_field")) - return eval_is_bit_field (h); + return eval_is_bit_field (h, kind); if (!strcmp (ident, "enumerator")) return eval_is_enumerator (h); if (!strcmp (ident, "complete_type")) @@ -4961,6 +5372,8 @@ process_metafunction (const constexpr_ctx *ctx, tree call, return eval_is_nothrow_assignable_type (loc, ctx, h, h1, jump_target); } + if (!strcmp (ident, "data_member_spec")) + return eval_is_data_member_spec (h, kind); goto not_found; } @@ -5104,7 +5517,6 @@ process_metafunction (const constexpr_ctx *ctx, tree call, if (id_equal (name, "extent")) { tree i = get_nth_callarg (call, 1); - location_t loc = cp_expr_loc_or_input_loc (i); i = cxx_eval_constant_expression (ctx, i, vc_prvalue, non_constant_p, overflow_p, jump_target); @@ -5157,6 +5569,19 @@ process_metafunction (const constexpr_ctx *ctx, tree call, return call; return eval_substitute (loc, ctx, h, hvec, jump_target); } + if (id_equal (name, "data_member_spec")) + { + tree opts = get_nth_callarg (call, 1); + opts = cxx_eval_constant_expression (ctx, opts, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + return eval_data_member_spec (loc, ctx, h, opts, call, + non_constant_p, overflow_p, jump_target); + } not_found: sorry ("%qE", name); @@ -5395,6 +5820,14 @@ compare_reflections (tree lhs, tree rhs) lhs = maybe_update_function_parm (lhs); rhs = maybe_update_function_parm (rhs); } + else if (kind == REFLECT_DATA_MEMBER_SPEC) + return (TREE_VEC_ELT (lhs, 0) == TREE_VEC_ELT (rhs, 0) + && TREE_VEC_ELT (lhs, 1) == TREE_VEC_ELT (rhs, 1) + && tree_int_cst_equal (TREE_VEC_ELT (lhs, 2), + TREE_VEC_ELT (rhs, 2)) + && tree_int_cst_equal (TREE_VEC_ELT (lhs, 3), + TREE_VEC_ELT (rhs, 3)) + && TREE_VEC_ELT (lhs, 4) == TREE_VEC_ELT (rhs, 4)); return lhs == rhs; } diff --git a/gcc/testsuite/g++.dg/reflect/bit_size_of1.C b/gcc/testsuite/g++.dg/reflect/bit_size_of1.C index 53e4b5b6fd8..bc341adcf20 100644 --- a/gcc/testsuite/g++.dg/reflect/bit_size_of1.C +++ b/gcc/testsuite/g++.dg/reflect/bit_size_of1.C @@ -64,7 +64,8 @@ static_assert (!has_bit_size_of (^^Concept)); static_assert (!has_bit_size_of (^^NSAlias)); static_assert (!has_bit_size_of (^^NS)); //static_assert (!has_bit_size_of (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!has_bit_size_of (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (has_bit_size_of (std::meta::data_member_spec (^^int, { .name = "member" }))); +static_assert (has_bit_size_of (std::meta::data_member_spec (^^int, { .name = "member2", .bit_width = 6 }))); static_assert (!has_bit_size_of (^^arr2)); static_assert (has_bit_size_of (^^arr3)); static_assert (!has_bit_size_of (^^ref)); @@ -118,3 +119,5 @@ static_assert (bit_size_of (^^V::f) == CHAR_BIT * sizeof (long long)); static_assert (bit_size_of (^^V::g) == 3); static_assert (bit_size_of (^^V::h) == CHAR_BIT * sizeof (int *)); static_assert (bit_size_of (^^V::i) == CHAR_BIT * sizeof (long long) - 3); +static_assert (bit_size_of (std::meta::data_member_spec (^^int, { .name = "member" })) == CHAR_BIT * sizeof (int)); +static_assert (bit_size_of (std::meta::data_member_spec (^^int, { .name = "member2", .bit_width = 6 })) == 6); diff --git a/gcc/testsuite/g++.dg/reflect/can_substitute1.C b/gcc/testsuite/g++.dg/reflect/can_substitute1.C index f51ce2632d9..e9e8570278d 100644 --- a/gcc/testsuite/g++.dg/reflect/can_substitute1.C +++ b/gcc/testsuite/g++.dg/reflect/can_substitute1.C @@ -88,8 +88,8 @@ static_assert (!could_substitute (^^decomp, {})); static_assert (!could_substitute (^^decomp_ref, {})); static_assert (!could_substitute (^^arr, {})); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!could_substitute (dms, {})); +constexpr auto dms = data_member_spec (^^int, { .name = "a" }); +static_assert (!could_substitute (dms, {})); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec1.C b/gcc/testsuite/g++.dg/reflect/data_member_spec1.C new file mode 100644 index 00000000000..fb2d7e7c363 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/data_member_spec1.C @@ -0,0 +1,115 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::data_member_spec. + +#include + +using namespace std::meta; + +enum E { E0, E1 }; +struct S {}; + +consteval bool +valid_data_member_spec (info r, data_member_options opts) +{ + try { data_member_spec (r, opts); } + catch (std::meta::exception &) { return false; } + return true; +} + +consteval bool +foo () +{ + std::string n1 = "bar"; + data_member_options a = { .name = n1 }; + auto dmsa = data_member_spec (^^S, a); + if (!is_data_member_spec (dmsa)) + throw 1; + std::u8string_view n2 = u8"baz"; + data_member_options b = { .name = n2, .alignment = 2 * alignof (long), .no_unique_address = true }; + auto dmsb = data_member_spec (^^long, b); + if (!is_data_member_spec (dmsb)) + throw 2; + data_member_options c = { .bit_width = 7 }; + auto dmsc = data_member_spec (^^int, c); + if (!is_data_member_spec (dmsc)) + throw 3; + data_member_options d = { .name = "extremely_long_identifier1", .bit_width = 6 }; + auto dmsd = data_member_spec (^^E, d); + if (!is_data_member_spec (dmsd)) + throw 4; + data_member_options e = { .bit_width = 0 }; + auto dmse = data_member_spec (^^int, e); + if (!is_data_member_spec (dmse)) + throw 5; + data_member_options f = { .name = u8"extremely_long_identifier2", .alignment = 2 * alignof (E) }; + auto dmsf = data_member_spec (^^E &, f); + if (!is_data_member_spec (dmsf)) + throw 6; + if (dmsa != data_member_spec (^^S, { .name = "bar" })) + throw 7; + if (dmsb != data_member_spec (^^long, { .name = u8"baz", .alignment = 2 * alignof (long), .no_unique_address = true })) + throw 8; + if (dmsc != data_member_spec (^^int, { .bit_width = 7ULL })) + throw 9; + if (dmsd != data_member_spec (^^E, { .name = "extremely_long_identifier1", .bit_width = 6 })) + throw 10; + if (dmse != data_member_spec (^^int, { .bit_width = 0U })) + throw 11; + if (dmsf != data_member_spec (^^E &, { .name = u8"extremely_long_identifier2", .alignment = 2 * alignof (E) })) + throw 12; + if (dmsa == data_member_spec (^^const S, { .name = "bar" })) + throw 13; + if (dmsa == data_member_spec (^^S, { .name = "foo" })) + throw 14; + if (dmsb == data_member_spec (^^long, { .name = u8"baz", .alignment = 4 * alignof (long), .no_unique_address = true })) + throw 15; + if (dmsb == data_member_spec (^^long, { .name = u8"baz", .alignment = 2 * alignof (long), .no_unique_address = false })) + throw 16; + if (dmsc == data_member_spec (^^int, { .bit_width = 8 })) + throw 17; + if (dmsd == data_member_spec (^^E, { .name = "extremely_long_identifier3", .bit_width = 6 })) + throw 18; + if (dmsd == data_member_spec (^^E, { .name = "extremely_long_identifier", .bit_width = 5 })) + throw 19; + if (dmse == data_member_spec (^^int, { .name = "a" })) + throw 20; + if (data_member_spec (^^int, { .name = "a" }) == data_member_spec (^^int, { .name = "a", .no_unique_address = true })) + throw 21; + return true; +} + +static_assert (foo ()); + +static_assert (!valid_data_member_spec (^^void, { .name = "a" })); +static_assert (!valid_data_member_spec (^^int (int), { .name = "a" })); +static_assert (!valid_data_member_spec (^^int, {})); +static_assert (!valid_data_member_spec (^^int, { .alignment = alignof (int) })); +static_assert (!valid_data_member_spec (^^int, { .no_unique_address = true })); +static_assert (!valid_data_member_spec (^^int, { .name = "for" })); +static_assert (!valid_data_member_spec (^^int, { .name = "if" })); +static_assert (!valid_data_member_spec (^^int, { .name = "char8_t" })); +static_assert (!valid_data_member_spec (^^int, { .name = "virtual" })); +static_assert (!valid_data_member_spec (^^int, { .name = "static_assert" })); +static_assert (!valid_data_member_spec (^^int, { .name = "__is_convertible" })); +static_assert (!valid_data_member_spec (^^int, { .name = "__builtin_is_nothrow_relocatable" })); +static_assert (!valid_data_member_spec (^^int, { .name = "007" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"\u00AA" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"\u00AB" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"\u00B6" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"\u00BA" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"\u00C0" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"\u00D6" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"\u0384" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"\u0669" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"A\u0669" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"\u0E59" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"A\u0E59" })); +static_assert (!valid_data_member_spec (^^S, { .name = "a", .bit_width = 4 })); +static_assert (!valid_data_member_spec (^^int, { .name = "a", .alignment = alignof (int), .bit_width = 4 })); +static_assert (!valid_data_member_spec (^^int, { .name = "a", .bit_width = 4, .no_unique_address = true })); +static_assert (!valid_data_member_spec (^^int, { .name = "a", .bit_width = 0 })); +static_assert (!valid_data_member_spec (^^int, { .name = "a", .bit_width = -42 })); +static_assert (!valid_data_member_spec (^^int, { .name = "a", .alignment = 41 })); +static_assert (!valid_data_member_spec (^^int, { .name = "a", .alignment = -__INT_MAX__ - 1 })); +static_assert (!valid_data_member_spec (^^long long, { .name = "a", .alignment = alignof (long long) / 2 })); diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec2.C b/gcc/testsuite/g++.dg/reflect/data_member_spec2.C new file mode 100644 index 00000000000..3167e809673 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/data_member_spec2.C @@ -0,0 +1,113 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::data_member_spec. + +#include + +using namespace std::meta; + +consteval bool +valid_data_member_spec (info r, data_member_options opts) +{ + try { data_member_spec (r, opts); } + catch (std::meta::exception &) { return false; } + return true; +} + +constexpr info null_reflection; +struct cls { + int dm; + static int static_dm; + void mem_fun (); + static void static_mem_fun (); + int &ref_dm = dm; + using type = int; +} cls_var; +union onion { }; +static union { int anon; }; +using alias = cls; +void fun (); +int var; +int &ref = var; +int &&rref = 42; +int *ptr = &var; +namespace ns {} +namespace ns_alias = ns; +enum Enum { A }; +enum class Enum_class { A }; + +template struct incomplete_cls; +template struct cls_tmpl {}; +template void fun_tmpl (); +template concept conc = requires { true; }; +template int var_tmpl; +template using cls_tmpl_alias = cls_tmpl; + +int arr[] = { 42 }; +auto [ decomp ] = arr; +auto &[ decomp_ref ] = arr; + +static_assert (!valid_data_member_spec (null_reflection, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^::, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^ns, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^ns_alias, { .name = "dms" })); +static_assert (!valid_data_member_spec (reflect_constant (3), { .name = "dms" })); +static_assert (valid_data_member_spec (^^cls, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls::dm, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls::ref_dm, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls::static_dm, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls::mem_fun, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls::static_mem_fun, { .name = "dms" })); +static_assert (valid_data_member_spec (^^cls::type, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls_var, { .name = "dms" })); +static_assert (valid_data_member_spec (^^onion, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^anon, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^fun, { .name = "dms" })); +static_assert (valid_data_member_spec (^^alias, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^var, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^ref, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^rref, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^ptr, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls_tmpl, { .name = "dms" })); +static_assert (valid_data_member_spec (^^cls_tmpl, { .name = "dms" })); +static_assert (valid_data_member_spec (^^incomplete_cls, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^fun_tmpl, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^fun_tmpl, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^conc, { .name = "dms" })); +static_assert (!valid_data_member_spec (substitute (^^conc, { ^^int }), { .name = "dms" })); +static_assert (!valid_data_member_spec (^^var_tmpl, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^var_tmpl, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^cls_tmpl_alias, { .name = "dms" })); +static_assert (valid_data_member_spec (^^cls_tmpl_alias, { .name = "dms" })); +static_assert (valid_data_member_spec (^^Enum, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^Enum::A, { .name = "dms" })); +static_assert (valid_data_member_spec (^^Enum_class, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^Enum_class::A, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^decomp, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^decomp_ref, { .name = "dms" })); +static_assert (!valid_data_member_spec (^^arr, { .name = "dms" })); + +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!valid_data_member_spec (dms, { .name = "dms" })); + +struct Base {}; +struct Derived : Base {}; +//static_assert (!valid_data_member_spec (bases_of (^^Derived, ctx)[0], { .name = "dms" })); + +template +void +f () +{ + static_assert (valid_data_member_spec (^^T, { .name = "dms" })); + static_assert (!valid_data_member_spec (R, { .name = "dms" })); + static_assert (!valid_data_member_spec (R2, { .name = "dms" })); + static_assert (valid_data_member_spec (R3, { .name = "dms" })); +} + +void +g (int p, cls c) +{ + f(); + static_assert (!valid_data_member_spec (^^p, { .name = "dms" })); + static_assert (!valid_data_member_spec (^^c, { .name = "dms" })); +} diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec3.C b/gcc/testsuite/g++.dg/reflect/data_member_spec3.C new file mode 100644 index 00000000000..e29013da32d --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/data_member_spec3.C @@ -0,0 +1,29 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::data_member_spec. + +#include + +using namespace std::meta; + +consteval bool +valid_data_member_spec (info r, data_member_options opts) +{ + try { data_member_spec (r, opts); } + catch (std::meta::exception &) { return false; } + return true; +} + +static_assert (!valid_data_member_spec (^^int, { .name = u8"👷" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"👷.♀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"⏰" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"🕐" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"☠" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"💀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"✋" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"👊" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"✈" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"🚀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"☹" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"😀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"💩" })); diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec4.C b/gcc/testsuite/g++.dg/reflect/data_member_spec4.C new file mode 100644 index 00000000000..49c6b9b2873 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/data_member_spec4.C @@ -0,0 +1,29 @@ +// { dg-do compile { target c++26 } } +// { dg-options "-freflection" } +// Test std::meta::data_member_spec. + +#include + +using namespace std::meta; + +consteval bool +valid_data_member_spec (info r, data_member_options opts) +{ + try { data_member_spec (r, opts); } + catch (std::meta::exception &) { return false; } + return true; +} + +static_assert (valid_data_member_spec (^^int, { .name = u8"👷" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"👷.♀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"⏰" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"🕐" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"☠" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"💀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"✋" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"👊" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"✈" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"🚀" })); +static_assert (!valid_data_member_spec (^^int, { .name = u8"☹" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"😀" })); +static_assert (valid_data_member_spec (^^int, { .name = u8"💩" })); diff --git a/gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C index f80e530eb8c..191547701d3 100644 --- a/gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C +++ b/gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C @@ -82,8 +82,8 @@ static_assert (!has_c_language_linkage (^^decomp)); static_assert (!has_c_language_linkage (^^decomp_ref)); static_assert (!has_c_language_linkage (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_c_language_linkage (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "a" }); +static_assert (!has_c_language_linkage (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/has_default_argument1.C b/gcc/testsuite/g++.dg/reflect/has_default_argument1.C index f1a5bc4c52c..98ca6e59e06 100644 --- a/gcc/testsuite/g++.dg/reflect/has_default_argument1.C +++ b/gcc/testsuite/g++.dg/reflect/has_default_argument1.C @@ -79,8 +79,8 @@ static_assert (!has_default_argument (^^decomp)); static_assert (!has_default_argument (^^decomp_ref)); static_assert (!has_default_argument (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_default_argument (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "n" }); +static_assert (!has_default_argument (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C b/gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C index 9a5ce859c48..bf091004e7b 100644 --- a/gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C +++ b/gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C @@ -109,8 +109,8 @@ static_assert (!has_default_member_initializer (^^decomp)); static_assert (!has_default_member_initializer (^^decomp_ref)); static_assert (!has_default_member_initializer (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_default_member_initializer (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "a" }); +static_assert (!has_default_member_initializer (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C b/gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C index b8e331d4acd..3d57e59f6f3 100644 --- a/gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C +++ b/gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C @@ -122,8 +122,8 @@ static_assert (has_ellipsis_parameter (^^funt2)); static_assert (has_ellipsis_parameter (^^funt3)); static_assert (!has_ellipsis_parameter (^^funt4)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_ellipsis_parameter (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = u8"a" }); +static_assert (!has_ellipsis_parameter (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/has_external_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_external_linkage1.C index cb87e4e457a..803cdddb498 100644 --- a/gcc/testsuite/g++.dg/reflect/has_external_linkage1.C +++ b/gcc/testsuite/g++.dg/reflect/has_external_linkage1.C @@ -81,8 +81,8 @@ static_assert (!has_external_linkage (^^decomp)); static_assert (!has_external_linkage (^^decomp_ref)); static_assert (has_external_linkage (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_external_linkage (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_external_linkage (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/has_identifier1.C b/gcc/testsuite/g++.dg/reflect/has_identifier1.C index 78a3ff81612..a0a2e868682 100644 --- a/gcc/testsuite/g++.dg/reflect/has_identifier1.C +++ b/gcc/testsuite/g++.dg/reflect/has_identifier1.C @@ -33,6 +33,10 @@ static_assert (has_identifier (^^E1)); //static_assert (has_identifier (^^E)); [[=1]] int w; static_assert (!has_identifier (annotations_of (^^w)[0])); +static_assert (!has_identifier (data_member_spec (^^int, { .bit_width = 0 }))); +static_assert (!has_identifier (data_member_spec (^^long, { .bit_width = 6 }))); +static_assert (has_identifier (data_member_spec (^^long, { .name = "dms", .bit_width = 6 }))); +static_assert (has_identifier (data_member_spec (^^long, { .name = u8"dms", .alignment = 2 * alignof (long) }))); namespace N {} namespace NA = N; diff --git a/gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C index ebe7d5a9b76..ec6e80a72f1 100644 --- a/gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C +++ b/gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C @@ -81,8 +81,8 @@ static_assert (!has_internal_linkage (^^decomp)); static_assert (!has_internal_linkage (^^decomp_ref)); static_assert (!has_internal_linkage (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_internal_linkage (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_internal_linkage (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/has_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_linkage1.C index 53bea761c50..b7ded9ccd0b 100644 --- a/gcc/testsuite/g++.dg/reflect/has_linkage1.C +++ b/gcc/testsuite/g++.dg/reflect/has_linkage1.C @@ -81,8 +81,8 @@ static_assert (!has_linkage (^^decomp)); static_assert (!has_linkage (^^decomp_ref)); static_assert (has_linkage (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_linkage (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_linkage (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/has_module_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_module_linkage1.C index 68231514e6b..1cc550434b7 100644 --- a/gcc/testsuite/g++.dg/reflect/has_module_linkage1.C +++ b/gcc/testsuite/g++.dg/reflect/has_module_linkage1.C @@ -81,8 +81,8 @@ static_assert (!has_module_linkage (^^decomp)); static_assert (!has_module_linkage (^^decomp_ref)); static_assert (!has_module_linkage (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_module_linkage (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_module_linkage (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/has_parent1.C b/gcc/testsuite/g++.dg/reflect/has_parent1.C index c29beb87271..e80379be7d2 100644 --- a/gcc/testsuite/g++.dg/reflect/has_parent1.C +++ b/gcc/testsuite/g++.dg/reflect/has_parent1.C @@ -79,8 +79,8 @@ static_assert (has_parent (^^decomp)); static_assert (has_parent (^^decomp_ref)); static_assert (has_parent (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_parent (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_parent (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/has_template_arguments1.C b/gcc/testsuite/g++.dg/reflect/has_template_arguments1.C index f5de3d7f6a2..04f498a0215 100644 --- a/gcc/testsuite/g++.dg/reflect/has_template_arguments1.C +++ b/gcc/testsuite/g++.dg/reflect/has_template_arguments1.C @@ -85,8 +85,8 @@ static_assert (!has_template_arguments (^^arr)); static_assert (!has_template_arguments (^^U)); static_assert (!has_template_arguments (^^TYPE)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_template_arguments (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_template_arguments (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/identifier_of1.C b/gcc/testsuite/g++.dg/reflect/identifier_of1.C index c7eb89a611a..f300ae95001 100644 --- a/gcc/testsuite/g++.dg/reflect/identifier_of1.C +++ b/gcc/testsuite/g++.dg/reflect/identifier_of1.C @@ -29,6 +29,8 @@ static_assert (identifier_of (^^E1) == std::string_view ("E1")); // 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")); +static_assert (identifier_of (data_member_spec (^^long, { .name = "foo", .bit_width = 6 })) == std::string_view ("foo")); +static_assert (identifier_of (data_member_spec (^^long, { .name = "extremely_long_string_used_as_identifier" })) == std::string_view ("extremely_long_string_used_as_identifier")); namespace N {} namespace NA = N; diff --git a/gcc/testsuite/g++.dg/reflect/is_alias_template1.C b/gcc/testsuite/g++.dg/reflect/is_alias_template1.C index 7a509c6ea38..92f45522221 100644 --- a/gcc/testsuite/g++.dg/reflect/is_alias_template1.C +++ b/gcc/testsuite/g++.dg/reflect/is_alias_template1.C @@ -79,8 +79,8 @@ static_assert (!is_alias_template (^^decomp)); static_assert (!is_alias_template (^^decomp_ref)); static_assert (!is_alias_template (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_alias_template (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_alias_template (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_bit_field1.C b/gcc/testsuite/g++.dg/reflect/is_bit_field1.C index c9d73399ee7..56bdbf4dfbc 100644 --- a/gcc/testsuite/g++.dg/reflect/is_bit_field1.C +++ b/gcc/testsuite/g++.dg/reflect/is_bit_field1.C @@ -104,10 +104,12 @@ static_assert (!is_bit_field (^^decomp)); static_assert (!is_bit_field (^^decomp_ref)); static_assert (!is_bit_field (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_bit_field (dms)); -//constexpr auto dms2 = data_member_spec (^^int, { .width = 6 }); -//static_assert (is_bit_field (dms2)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_bit_field (dms)); +constexpr auto dms2 = data_member_spec (^^int, { .bit_width = 6 }); +static_assert (is_bit_field (dms2)); +constexpr auto dms3 = data_member_spec (^^int, { .name = "dms", .bit_width = 15 }); +static_assert (is_bit_field (dms3)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_class_member1.C b/gcc/testsuite/g++.dg/reflect/is_class_member1.C index 9daaae0841c..d0518be23cc 100644 --- a/gcc/testsuite/g++.dg/reflect/is_class_member1.C +++ b/gcc/testsuite/g++.dg/reflect/is_class_member1.C @@ -104,8 +104,8 @@ static_assert (!is_class_member (^^decomp)); static_assert (!is_class_member (^^decomp_ref)); static_assert (!is_class_member (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_class_member (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_class_member (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_class_template1.C b/gcc/testsuite/g++.dg/reflect/is_class_template1.C index 3ab72830a87..a8bc5be74ae 100644 --- a/gcc/testsuite/g++.dg/reflect/is_class_template1.C +++ b/gcc/testsuite/g++.dg/reflect/is_class_template1.C @@ -79,8 +79,8 @@ static_assert (!is_class_template (^^decomp)); static_assert (!is_class_template (^^decomp_ref)); static_assert (!is_class_template (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_class_template (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_class_template (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_complete_type1.C b/gcc/testsuite/g++.dg/reflect/is_complete_type1.C index 57ce28d2a15..42bba99ad80 100644 --- a/gcc/testsuite/g++.dg/reflect/is_complete_type1.C +++ b/gcc/testsuite/g++.dg/reflect/is_complete_type1.C @@ -83,8 +83,8 @@ static_assert (!is_complete_type (^^arr)); static_assert (!is_complete_type (^^inc_arr)); static_assert (is_complete_type (^^com_arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_complete_type (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_complete_type (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_concept1.C b/gcc/testsuite/g++.dg/reflect/is_concept1.C index ece99ecf818..58a70841edc 100644 --- a/gcc/testsuite/g++.dg/reflect/is_concept1.C +++ b/gcc/testsuite/g++.dg/reflect/is_concept1.C @@ -79,8 +79,8 @@ static_assert (!is_concept (^^decomp)); static_assert (!is_concept (^^decomp_ref)); static_assert (!is_concept (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_concept (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_concept (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_const1.C b/gcc/testsuite/g++.dg/reflect/is_const1.C index 895fc131182..fa89d7577af 100644 --- a/gcc/testsuite/g++.dg/reflect/is_const1.C +++ b/gcc/testsuite/g++.dg/reflect/is_const1.C @@ -52,7 +52,7 @@ static_assert (!is_const (^^Concept)); static_assert (!is_const (^^NSAlias)); static_assert (!is_const (^^NS)); //static_assert (!is_const (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!is_const (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (!is_const (std::meta::data_member_spec (^^int, { .name = "member" }))); int foo (int a, const long b, T c, int d[4], T &e) @@ -79,9 +79,6 @@ static_assert (!is_const (^^fn)); static_assert (!is_const (^^Enum::A)); static_assert (!is_const (^^A)); static_assert (!is_const (^^S::mem)); -//static_assert (!is_const (std::meta::members_of (^^S, ctx)[1])); -//static_assert (!is_const (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!is_const (std::meta::data_member_spec (^^int, {.name="member"}))); const int ci = 42; static_assert (is_const (^^ci)); diff --git a/gcc/testsuite/g++.dg/reflect/is_data_member_spec1.C b/gcc/testsuite/g++.dg/reflect/is_data_member_spec1.C new file mode 100644 index 00000000000..3cfb52c9eaa --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/is_data_member_spec1.C @@ -0,0 +1,105 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::is_data_member_spec. + +#include + +using namespace std::meta; + +constexpr info null_reflection; +struct cls { + int dm; + static int static_dm; + void mem_fun (); + static void static_mem_fun (); + int &ref_dm = dm; + using type = int; +} cls_var; +union onion { }; +static union { int anon; }; +using alias = cls; +void fun (); +int var; +int &ref = var; +int &&rref = 42; +int *ptr = &var; +namespace ns {} +namespace ns_alias = ns; +enum Enum { A }; +enum class Enum_class { A }; + +template struct incomplete_cls; +template struct cls_tmpl {}; +template void fun_tmpl (); +template concept conc = requires { true; }; +template int var_tmpl; +template using cls_tmpl_alias = cls_tmpl; + +int arr[] = { 42 }; +auto [ decomp ] = arr; +auto &[ decomp_ref ] = arr; + +static_assert (!is_data_member_spec (null_reflection)); +static_assert (!is_data_member_spec (^^::)); +static_assert (!is_data_member_spec (^^ns)); +static_assert (!is_data_member_spec (^^ns_alias)); +static_assert (!is_data_member_spec (reflect_constant (3))); +static_assert (!is_data_member_spec (^^cls)); +static_assert (!is_data_member_spec (^^cls::dm)); +static_assert (!is_data_member_spec (^^cls::ref_dm)); +static_assert (!is_data_member_spec (^^cls::static_dm)); +static_assert (!is_data_member_spec (^^cls::mem_fun)); +static_assert (!is_data_member_spec (^^cls::static_mem_fun)); +static_assert (!is_data_member_spec (^^cls::type)); +static_assert (!is_data_member_spec (^^cls_var)); +static_assert (!is_data_member_spec (^^onion)); +static_assert (!is_data_member_spec (^^anon)); +static_assert (!is_data_member_spec (^^fun)); +static_assert (!is_data_member_spec (^^alias)); +static_assert (!is_data_member_spec (^^var)); +static_assert (!is_data_member_spec (^^ref)); +static_assert (!is_data_member_spec (^^rref)); +static_assert (!is_data_member_spec (^^ptr)); +static_assert (!is_data_member_spec (^^cls_tmpl)); +static_assert (!is_data_member_spec (^^cls_tmpl)); +static_assert (!is_data_member_spec (^^incomplete_cls)); +static_assert (!is_data_member_spec (^^fun_tmpl)); +static_assert (!is_data_member_spec (^^fun_tmpl)); +static_assert (!is_data_member_spec (^^conc)); +static_assert (!is_data_member_spec (substitute (^^conc, { ^^int }))); +static_assert (!is_data_member_spec (^^var_tmpl)); +static_assert (!is_data_member_spec (^^var_tmpl)); +static_assert (!is_data_member_spec (^^cls_tmpl_alias)); +static_assert (!is_data_member_spec (^^cls_tmpl_alias)); +static_assert (!is_data_member_spec (^^Enum)); +static_assert (!is_data_member_spec (^^Enum::A)); +static_assert (!is_data_member_spec (^^Enum_class)); +static_assert (!is_data_member_spec (^^Enum_class::A)); +static_assert (!is_data_member_spec (^^decomp)); +static_assert (!is_data_member_spec (^^decomp_ref)); +static_assert (!is_data_member_spec (^^arr)); + +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (is_data_member_spec (dms)); + +struct Base {}; +struct Derived : Base {}; +//static_assert (!is_data_member_spec (bases_of (^^Derived, ctx)[0])); + +template +void +f () +{ + static_assert (!is_data_member_spec (^^T)); + static_assert (!is_data_member_spec (R)); + static_assert (!is_data_member_spec (R2)); + static_assert (!is_data_member_spec (R3)); +} + +void +g (int p, cls c) +{ + f(); + static_assert (!is_data_member_spec (^^p)); + static_assert (!is_data_member_spec (^^c)); +} diff --git a/gcc/testsuite/g++.dg/reflect/is_defaulted1.C b/gcc/testsuite/g++.dg/reflect/is_defaulted1.C index ccc92c259bc..5d3bb1fc76e 100644 --- a/gcc/testsuite/g++.dg/reflect/is_defaulted1.C +++ b/gcc/testsuite/g++.dg/reflect/is_defaulted1.C @@ -104,8 +104,8 @@ static_assert (!is_defaulted (^^decomp)); static_assert (!is_defaulted (^^decomp_ref)); static_assert (!is_defaulted (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_defaulted (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_defaulted (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_deleted1.C b/gcc/testsuite/g++.dg/reflect/is_deleted1.C index f5170984e0e..0e5b2651cc7 100644 --- a/gcc/testsuite/g++.dg/reflect/is_deleted1.C +++ b/gcc/testsuite/g++.dg/reflect/is_deleted1.C @@ -104,8 +104,8 @@ static_assert (!is_deleted (^^decomp)); static_assert (!is_deleted (^^decomp_ref)); static_assert (!is_deleted (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_deleted (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = u8"dms" }); +static_assert (!is_deleted (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_enumerator1.C b/gcc/testsuite/g++.dg/reflect/is_enumerator1.C index 16627581e08..c9198428cfe 100644 --- a/gcc/testsuite/g++.dg/reflect/is_enumerator1.C +++ b/gcc/testsuite/g++.dg/reflect/is_enumerator1.C @@ -79,8 +79,8 @@ static_assert (!is_enumerator (^^decomp)); static_assert (!is_enumerator (^^decomp_ref)); static_assert (!is_enumerator (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_enumerator (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_enumerator (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C b/gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C index 1289894975b..f739568d1ad 100644 --- a/gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C +++ b/gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C @@ -79,8 +79,8 @@ static_assert (!is_explicit_object_parameter (^^decomp)); static_assert (!is_explicit_object_parameter (^^decomp_ref)); static_assert (!is_explicit_object_parameter (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_explicit_object_parameter (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_explicit_object_parameter (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_function1.C b/gcc/testsuite/g++.dg/reflect/is_function1.C index 69211d4c76e..bfe4d677f42 100644 --- a/gcc/testsuite/g++.dg/reflect/is_function1.C +++ b/gcc/testsuite/g++.dg/reflect/is_function1.C @@ -79,8 +79,8 @@ static_assert (!is_function (^^decomp)); static_assert (!is_function (^^decomp_ref)); static_assert (!is_function (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_function (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_function (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_function_parameter1.C b/gcc/testsuite/g++.dg/reflect/is_function_parameter1.C index 620e1ef36a9..4d8b2a138ae 100644 --- a/gcc/testsuite/g++.dg/reflect/is_function_parameter1.C +++ b/gcc/testsuite/g++.dg/reflect/is_function_parameter1.C @@ -79,8 +79,8 @@ static_assert (!is_function_parameter (^^decomp)); static_assert (!is_function_parameter (^^decomp_ref)); static_assert (!is_function_parameter (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_function_parameter (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_function_parameter (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_function_template1.C b/gcc/testsuite/g++.dg/reflect/is_function_template1.C index 056a1f97933..23bff076d2b 100644 --- a/gcc/testsuite/g++.dg/reflect/is_function_template1.C +++ b/gcc/testsuite/g++.dg/reflect/is_function_template1.C @@ -79,8 +79,8 @@ static_assert (!is_function_template (^^decomp)); static_assert (!is_function_template (^^decomp_ref)); static_assert (!is_function_template (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_function_template (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_function_template (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_mutable_member1.C b/gcc/testsuite/g++.dg/reflect/is_mutable_member1.C index ee0d2239d7c..cd3dbb693a0 100644 --- a/gcc/testsuite/g++.dg/reflect/is_mutable_member1.C +++ b/gcc/testsuite/g++.dg/reflect/is_mutable_member1.C @@ -110,8 +110,8 @@ static_assert (!is_mutable_member (^^decomp)); static_assert (!is_mutable_member (^^decomp_ref)); static_assert (!is_mutable_member (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_mutable_member (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_mutable_member (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_namespace1.C b/gcc/testsuite/g++.dg/reflect/is_namespace1.C index 3c5f67f54c1..96bbf682d2a 100644 --- a/gcc/testsuite/g++.dg/reflect/is_namespace1.C +++ b/gcc/testsuite/g++.dg/reflect/is_namespace1.C @@ -79,8 +79,8 @@ static_assert (!is_namespace (^^decomp)); static_assert (!is_namespace (^^decomp_ref)); static_assert (!is_namespace (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_namespace (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_namespace (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C b/gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C index b904a9b97ce..667047d4f87 100644 --- a/gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C +++ b/gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C @@ -79,8 +79,8 @@ static_assert (!is_namespace_alias (^^decomp)); static_assert (!is_namespace_alias (^^decomp_ref)); static_assert (!is_namespace_alias (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_namespace_alias (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_namespace_alias (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_namespace_member1.C b/gcc/testsuite/g++.dg/reflect/is_namespace_member1.C index 529184610fd..0793cb13815 100644 --- a/gcc/testsuite/g++.dg/reflect/is_namespace_member1.C +++ b/gcc/testsuite/g++.dg/reflect/is_namespace_member1.C @@ -124,8 +124,8 @@ static_assert (is_namespace_member (^^NN::ns_alias)); static_assert (is_namespace_member (^^NN::E)); static_assert (is_namespace_member (^^NN::F)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_namespace_member (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_namespace_member (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C b/gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C index b18d4a5a914..9812510b65d 100644 --- a/gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C +++ b/gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C @@ -104,8 +104,8 @@ static_assert (!is_nonstatic_data_member (^^decomp)); static_assert (!is_nonstatic_data_member (^^decomp_ref)); static_assert (!is_nonstatic_data_member (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_nonstatic_data_member (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_nonstatic_data_member (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_object1.C b/gcc/testsuite/g++.dg/reflect/is_object1.C index 29dd6a359ce..cb15b11ad76 100644 --- a/gcc/testsuite/g++.dg/reflect/is_object1.C +++ b/gcc/testsuite/g++.dg/reflect/is_object1.C @@ -79,8 +79,8 @@ static_assert (!is_object (^^decomp)); static_assert (!is_object (^^decomp_ref)); static_assert (!is_object (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_object (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_object (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_static_member1.C b/gcc/testsuite/g++.dg/reflect/is_static_member1.C index 2bde50b02d3..c3b800cf65a 100644 --- a/gcc/testsuite/g++.dg/reflect/is_static_member1.C +++ b/gcc/testsuite/g++.dg/reflect/is_static_member1.C @@ -104,8 +104,8 @@ static_assert (!is_static_member (^^decomp)); static_assert (!is_static_member (^^decomp_ref)); static_assert (!is_static_member (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_static_member (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_static_member (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_template1.C b/gcc/testsuite/g++.dg/reflect/is_template1.C index 110a9e22d85..98e74fa7061 100644 --- a/gcc/testsuite/g++.dg/reflect/is_template1.C +++ b/gcc/testsuite/g++.dg/reflect/is_template1.C @@ -79,8 +79,8 @@ static_assert (!is_template (^^decomp)); static_assert (!is_template (^^decomp_ref)); static_assert (!is_template (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_template (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_template (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_type1.C b/gcc/testsuite/g++.dg/reflect/is_type1.C index abc6c400ef0..559e4a424e7 100644 --- a/gcc/testsuite/g++.dg/reflect/is_type1.C +++ b/gcc/testsuite/g++.dg/reflect/is_type1.C @@ -79,8 +79,8 @@ static_assert (!is_type (^^decomp)); static_assert (!is_type (^^decomp_ref)); static_assert (!is_type (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_type (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_type (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_type_alias1.C b/gcc/testsuite/g++.dg/reflect/is_type_alias1.C index 358e69a4ce1..9e3df0cbca9 100644 --- a/gcc/testsuite/g++.dg/reflect/is_type_alias1.C +++ b/gcc/testsuite/g++.dg/reflect/is_type_alias1.C @@ -79,8 +79,8 @@ static_assert (!is_type_alias (^^decomp)); static_assert (!is_type_alias (^^decomp_ref)); static_assert (!is_type_alias (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_type_alias (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_type_alias (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_user_declared1.C b/gcc/testsuite/g++.dg/reflect/is_user_declared1.C index a2b1b724e80..1a58a8399e7 100644 --- a/gcc/testsuite/g++.dg/reflect/is_user_declared1.C +++ b/gcc/testsuite/g++.dg/reflect/is_user_declared1.C @@ -104,8 +104,8 @@ static_assert (!is_user_declared (^^decomp)); static_assert (!is_user_declared (^^decomp_ref)); static_assert (!is_user_declared (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_user_declared (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_user_declared (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_user_provided1.C b/gcc/testsuite/g++.dg/reflect/is_user_provided1.C index 18f66ce9e9a..b452d5c529f 100644 --- a/gcc/testsuite/g++.dg/reflect/is_user_provided1.C +++ b/gcc/testsuite/g++.dg/reflect/is_user_provided1.C @@ -104,8 +104,8 @@ static_assert (!is_user_provided (^^decomp)); static_assert (!is_user_provided (^^decomp_ref)); static_assert (!is_user_provided (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_user_provided (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_user_provided (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_variable1.C b/gcc/testsuite/g++.dg/reflect/is_variable1.C index 59303016a9f..4260a44ced2 100644 --- a/gcc/testsuite/g++.dg/reflect/is_variable1.C +++ b/gcc/testsuite/g++.dg/reflect/is_variable1.C @@ -80,8 +80,8 @@ static_assert (!is_variable (^^decomp)); static_assert (!is_variable (^^decomp_ref)); static_assert (is_variable (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_variable (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_variable (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/is_variable_template1.C b/gcc/testsuite/g++.dg/reflect/is_variable_template1.C index 4532864ba8a..af349a4cce1 100644 --- a/gcc/testsuite/g++.dg/reflect/is_variable_template1.C +++ b/gcc/testsuite/g++.dg/reflect/is_variable_template1.C @@ -79,8 +79,8 @@ static_assert (!is_variable_template (^^decomp)); static_assert (!is_variable_template (^^decomp_ref)); static_assert (!is_variable_template (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_variable_template (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_variable_template (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/is_volatile1.C b/gcc/testsuite/g++.dg/reflect/is_volatile1.C index 2430f66bc7d..4093189fa31 100644 --- a/gcc/testsuite/g++.dg/reflect/is_volatile1.C +++ b/gcc/testsuite/g++.dg/reflect/is_volatile1.C @@ -52,7 +52,7 @@ static_assert (!is_volatile (^^Concept)); static_assert (!is_volatile (^^NSAlias)); static_assert (!is_volatile (^^NS)); //static_assert (!is_volatile (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!is_volatile (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (!is_volatile (std::meta::data_member_spec (^^int, { .name = "member" }))); int foo (int a, const long b, T c, int d[4], T &e) @@ -79,9 +79,6 @@ static_assert (!is_volatile (^^fn)); static_assert (!is_volatile (^^Enum::A)); static_assert (!is_volatile (^^A)); static_assert (!is_volatile (^^S::mem)); -//static_assert (!is_volatile (std::meta::members_of (^^S, ctx)[1])); -//static_assert (!is_volatile (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!is_volatile (std::meta::data_member_spec (^^int, {.name="member"}))); volatile int vi = 42; static_assert (is_volatile (^^vi)); diff --git a/gcc/testsuite/g++.dg/reflect/offset_of1.C b/gcc/testsuite/g++.dg/reflect/offset_of1.C index 9cbdd136d61..a79e9b1bb2f 100644 --- a/gcc/testsuite/g++.dg/reflect/offset_of1.C +++ b/gcc/testsuite/g++.dg/reflect/offset_of1.C @@ -61,7 +61,7 @@ static_assert (!has_offset_of (^^Concept)); static_assert (!has_offset_of (^^NSAlias)); static_assert (!has_offset_of (^^NS)); //static_assert (!has_offset_of (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!has_offset_of (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (!has_offset_of (std::meta::data_member_spec (^^int, { .name = "member" }))); void bar (long, const T f, int g[2], T &); int diff --git a/gcc/testsuite/g++.dg/reflect/operator_of1.C b/gcc/testsuite/g++.dg/reflect/operator_of1.C index aa6e424c5ee..1a42d9b4f76 100644 --- a/gcc/testsuite/g++.dg/reflect/operator_of1.C +++ b/gcc/testsuite/g++.dg/reflect/operator_of1.C @@ -87,8 +87,8 @@ static_assert (!is_operator (^^decomp)); static_assert (!is_operator (^^decomp_ref)); static_assert (!is_operator (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!is_operator (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!is_operator (dms)); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/p2996-5.C b/gcc/testsuite/g++.dg/reflect/p2996-5.C index a934a89ca51..d9b20cae21c 100644 --- a/gcc/testsuite/g++.dg/reflect/p2996-5.C +++ b/gcc/testsuite/g++.dg/reflect/p2996-5.C @@ -46,5 +46,5 @@ constexpr auto r16 = ^^NS; // represents a namespace //constexpr auto r17 = std::meta::bases_of(^^S)[0]; // represents a direct base class relationship -//constexpr auto r18 = std::meta::data_member_spec(^^int, {.name="member"}); +constexpr auto r18 = std::meta::data_member_spec(^^int, {.name="member"}); // represents a data member description diff --git a/gcc/testsuite/g++.dg/reflect/parent_of1.C b/gcc/testsuite/g++.dg/reflect/parent_of1.C index d2c40be50c4..95d4970d634 100644 --- a/gcc/testsuite/g++.dg/reflect/parent_of1.C +++ b/gcc/testsuite/g++.dg/reflect/parent_of1.C @@ -90,8 +90,8 @@ static_assert (parent_of (^^decomp) == ^^::); static_assert (parent_of (^^decomp_ref) == ^^::); static_assert (parent_of (^^arr) == ^^::); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_parent_of (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_parent_of (dms)); //constexpr auto ctx = std::meta::access_context::current (); diff --git a/gcc/testsuite/g++.dg/reflect/return_type_of1.C b/gcc/testsuite/g++.dg/reflect/return_type_of1.C index 8cad96e9b31..10c8cc1d6f2 100644 --- a/gcc/testsuite/g++.dg/reflect/return_type_of1.C +++ b/gcc/testsuite/g++.dg/reflect/return_type_of1.C @@ -77,7 +77,7 @@ static_assert (!has_return_type_of (^^Concept)); static_assert (!has_return_type_of (^^NSAlias)); static_assert (!has_return_type_of (^^NS)); //static_assert (!has_return_type_of (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!has_return_type_of (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (!has_return_type_of (std::meta::data_member_spec (^^int, { .name = "member" }))); struct V { diff --git a/gcc/testsuite/g++.dg/reflect/size_of1.C b/gcc/testsuite/g++.dg/reflect/size_of1.C index f6074308728..f503713bb83 100644 --- a/gcc/testsuite/g++.dg/reflect/size_of1.C +++ b/gcc/testsuite/g++.dg/reflect/size_of1.C @@ -63,7 +63,9 @@ static_assert (!has_size_of (^^Concept)); static_assert (!has_size_of (^^NSAlias)); static_assert (!has_size_of (^^NS)); //static_assert (!has_size_of (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!has_size_of (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (has_size_of (std::meta::data_member_spec (^^int, { .name = "member" }))); +static_assert (!has_size_of (std::meta::data_member_spec (^^int, { .name = "member", .bit_width = 6 }))); +static_assert (!has_size_of (std::meta::data_member_spec (^^int, { .bit_width = 15 }))); static_assert (!has_size_of (^^arr2)); static_assert (has_size_of (^^arr3)); static_assert (!has_size_of (^^ref)); diff --git a/gcc/testsuite/g++.dg/reflect/storage_duration2.C b/gcc/testsuite/g++.dg/reflect/storage_duration2.C index cf6218ab515..62d045c7a44 100644 --- a/gcc/testsuite/g++.dg/reflect/storage_duration2.C +++ b/gcc/testsuite/g++.dg/reflect/storage_duration2.C @@ -188,8 +188,10 @@ static_assert (has_static_storage_duration (^^arr)); static_assert (!has_thread_storage_duration (^^arr)); static_assert (!has_automatic_storage_duration (^^arr)); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!has_static_storage_duration (dms)); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!has_static_storage_duration (dms)); +static_assert (!has_thread_storage_duration (dms)); +static_assert (!has_automatic_storage_duration (dms)); template void diff --git a/gcc/testsuite/g++.dg/reflect/substitute1.C b/gcc/testsuite/g++.dg/reflect/substitute1.C index 0dcff1e6fa2..ef7be9800a8 100644 --- a/gcc/testsuite/g++.dg/reflect/substitute1.C +++ b/gcc/testsuite/g++.dg/reflect/substitute1.C @@ -90,8 +90,8 @@ static_assert (!could_substitute (^^decomp, {})); static_assert (!could_substitute (^^decomp_ref, {})); static_assert (!could_substitute (^^arr, {})); -//constexpr auto dms = data_member_spec (^^int, {}); -//static_assert (!could_substitute (dms, {})); +constexpr auto dms = data_member_spec (^^int, { .name = "dms" }); +static_assert (!could_substitute (dms, {})); struct Base {}; struct Derived : Base {}; diff --git a/gcc/testsuite/g++.dg/reflect/type_of1.C b/gcc/testsuite/g++.dg/reflect/type_of1.C index 5e8ecbe7cf4..c4a43a90f36 100644 --- a/gcc/testsuite/g++.dg/reflect/type_of1.C +++ b/gcc/testsuite/g++.dg/reflect/type_of1.C @@ -60,7 +60,10 @@ 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"}))); +static_assert (has_type (std::meta::data_member_spec (^^int, { .name = "member" }))); +static_assert (has_type (std::meta::data_member_spec (^^int, { .name = "member", .bit_width = 6 }))); +static_assert (has_type (std::meta::data_member_spec (^^int, { .bit_width = 0 }))); +static_assert (has_type (std::meta::data_member_spec (^^int, { .bit_width = 5 }))); void bar (long, const T f, int g[2], T &); int @@ -112,7 +115,11 @@ 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"})) == ??); +static_assert (type_of (std::meta::data_member_spec (^^int, { .name = "member" })) == ^^int); +static_assert (type_of (std::meta::data_member_spec (^^const long, { .name = "member", .bit_width = 8 })) == ^^const long); +static_assert (type_of (std::meta::data_member_spec (^^int3, { .name = "member" })) == ^^int[3]); +static_assert (type_of (std::meta::data_member_spec (^^int, { .bit_width = 7 })) == ^^int); +static_assert (type_of (std::meta::data_member_spec (^^int, { .bit_width = 0 })) == ^^int); consteval int test (info x, info y) diff --git a/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C b/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C index 23a4a3515b6..c01ed283003 100644 --- a/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C +++ b/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C @@ -29,6 +29,8 @@ static_assert (u8identifier_of (^^E1) == std::u8string_view (u8"E1")); // 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")); +static_assert (u8identifier_of (data_member_spec (^^long, { .name = u8"foo", .bit_width = 6 })) == std::u8string_view (u8"foo")); +static_assert (u8identifier_of (data_member_spec (^^long, { .name = u8"extremely_long_string_used_as_identifier" })) == std::u8string_view (u8"extremely_long_string_used_as_identifier")); namespace N {} namespace NA = N; diff --git a/gcc/testsuite/g++.dg/reflect/variable_of1.C b/gcc/testsuite/g++.dg/reflect/variable_of1.C index cfcb17d0b57..b2b5d8820ac 100644 --- a/gcc/testsuite/g++.dg/reflect/variable_of1.C +++ b/gcc/testsuite/g++.dg/reflect/variable_of1.C @@ -60,7 +60,7 @@ static_assert (!has_variable_of (^^Concept)); static_assert (!has_variable_of (^^NSAlias)); static_assert (!has_variable_of (^^NS)); //static_assert (!has_variable_of (std::meta::bases_of (^^S, ctx)[0])); -//static_assert (!has_variable_of (std::meta::data_member_spec (^^int, {.name="member"}))); +static_assert (!has_variable_of (std::meta::data_member_spec (^^int, { .name = "member" }))); void bar (long, const T f, int g[2], T &) diff --git a/libcpp/charset.cc b/libcpp/charset.cc index b5689f8765b..f07052087a8 100644 --- a/libcpp/charset.cc +++ b/libcpp/charset.cc @@ -840,6 +840,10 @@ _cpp_destroy_iconv (cpp_reader *pfile) iconv_close (pfile->char32_cset_desc.cd); if (pfile->wide_cset_desc.func == convert_using_iconv) iconv_close (pfile->wide_cset_desc.cd); + if (pfile->reverse_narrow_cset_desc.func == convert_using_iconv) + iconv_close (pfile->narrow_cset_desc.cd); + if (pfile->reverse_utf8_cset_desc.func == convert_using_iconv) + iconv_close (pfile->utf8_cset_desc.cd); } } @@ -2726,6 +2730,110 @@ cpp_interpret_string_notranslate (cpp_reader *pfile, const cpp_string *from, return retval; } +/* Convert a string FROM to TO, without handling of any UCNs etc., just + pure character set conversion. If !REVERSE, convert from SOURCE_CHARSET + to execution charset corresponding to TYPE, if REVERSE, convert from the + execution charset corresponding to TYPE to SOURCE_CHARSET. Return false + on error. */ + +bool +cpp_translate_string (cpp_reader *pfile, const cpp_string *from, + cpp_string *to, enum cpp_ttype type, bool reverse) +{ + struct cset_converter cvt = converter_for_type (pfile, type); + struct _cpp_strbuf tbuf; + if (reverse) + { + struct cset_converter *pcvt; + switch (type) + { + default: + pcvt = &pfile->reverse_narrow_cset_desc; + break; + case CPP_UTF8CHAR: + case CPP_UTF8STRING: + pcvt = &pfile->reverse_utf8_cset_desc; + break; + case CPP_CHAR16: + case CPP_STRING16: + case CPP_CHAR32: + case CPP_STRING32: + case CPP_WCHAR: + case CPP_WSTRING: + return false; + } + if (pcvt->func == NULL) + { + *pcvt = init_iconv_desc (pfile, cvt.from, cvt.to); + pcvt->width = cvt.width; + } + cvt = *pcvt; + } + tbuf.asize = MAX (OUTBUF_BLOCK_SIZE, from->len); + tbuf.text = XNEWVEC (uchar, tbuf.asize); + tbuf.len = 0; + if (!APPLY_CONVERSION (cvt, from->text, from->len, &tbuf)) + { + XDELETEVEC (tbuf.text); + return false; + } + tbuf.text = XRESIZEVEC (uchar, tbuf.text, tbuf.len); + to->text = tbuf.text; + to->len = tbuf.len; + return true; +} + +/* Return true if ID is a valid identifier, false otherwise. Without any + diagnostics. */ + +bool +cpp_valid_identifier (cpp_reader *pfile, const unsigned char *id) +{ + normalize_state nst = INITIAL_NORMALIZE_STATE; + const unsigned char *p = id; + if (*p == '\0') + return false; + const unsigned char *limit + = (const unsigned char *) strchr ((const char *) p, '\0'); + static const cppchar_t utf8_signifier = 0xC0; + if (ISIDST (*p)) + { + NORMALIZE_STATE_UPDATE_IDNUM (&nst, *p); + ++p; + } + while (*p) + { + if (p != id && ISIDNUM (*p)) + { + while (ISIDNUM (*p)) + ++p; + NORMALIZE_STATE_UPDATE_IDNUM (&nst, *(p - 1)); + continue; + } + if (CPP_OPTION (pfile, extended_identifiers) && *p >= utf8_signifier) + { + const unsigned char *base = p; + size_t inbytesleft = limit - p; + cppchar_t c; + if (one_utf8_to_cppchar (&p, &inbytesleft, &c)) + return false; + switch (ucn_valid_in_identifier (pfile, c, &nst)) + { + default: + return false; + case 1: + continue; + case 2: + if (base == id) + return false; + continue; + } + } + return false; + } + return true; +} + /* Return number of source characters in STR. */ static unsigned diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index d69e0024b92..bc0d7714e96 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -1309,6 +1309,9 @@ extern const char *cpp_interpret_string_ranges (cpp_reader *pfile, extern bool cpp_interpret_string_notranslate (cpp_reader *, const cpp_string *, size_t, cpp_string *, enum cpp_ttype); +extern bool cpp_translate_string (cpp_reader *, const cpp_string *, + cpp_string *, enum cpp_ttype, bool); +extern bool cpp_valid_identifier (cpp_reader *, const unsigned char *); /* Convert a host character constant to the execution character set. */ extern cppchar_t cpp_host_to_exec_charset (cpp_reader *, cppchar_t); diff --git a/libcpp/internal.h b/libcpp/internal.h index df607de4bd8..017e980a964 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -543,6 +543,14 @@ struct cpp_reader wide execution character set. */ struct cset_converter wide_cset_desc; + /* Descriptor for converting from the execution character set to the + source character set. */ + struct cset_converter reverse_narrow_cset_desc; + + /* Descriptor for converting from the UTF-8 execution character set to the + source character set. */ + struct cset_converter reverse_utf8_cset_desc; + /* Date and time text. Calculated together if either is requested. */ const unsigned char *date; const unsigned char *time; diff --git a/libstdc++-v3/include/std/meta b/libstdc++-v3/include/std/meta index 01f195d199f..86b094788b5 100644 --- a/libstdc++-v3/include/std/meta +++ b/libstdc++-v3/include/std/meta @@ -303,6 +303,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires (is_function_v>) consteval info reflect_function(_Tp&); + // [meta.reflection.define.aggregate], class definition generation + struct data_member_options { + struct _Name { + template + requires constructible_from + consteval _Name(_Tp&& __n) : _M_is_u8(true), _M_u8s((_Tp&&) __n) {} + + template + requires constructible_from + consteval _Name(_Tp&& __n) : _M_is_u8(false), _M_s((_Tp&&) __n) {} + + private: + bool _M_is_u8; + u8string _M_u8s; + string _M_s; + info _M_unused = {}; + }; + + optional<_Name> name; + optional alignment; + optional bit_width; + bool no_unique_address = false; + }; + consteval info data_member_spec(info, data_member_options); + consteval bool is_data_member_spec(info); + // associated with [meta.unary.cat], primary type categories consteval bool is_void_type(info); consteval bool is_null_pointer_type(info);