Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions src/Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,113 @@
Version 7.1

10/8/26
std::meta::type_of for nonstatic member functions

For a reflection of a nonstatic member function, std::meta::type_of returned
a type that still carried the class of the function, so it did not compare
equal to the reflection of the corresponding function type, and the spliced
type did not match a partial specialization for function types. The type of
a nonstatic member function is a plain function type ([dcl.fct]), including
its cv-qualifiers and ref-qualifier; type_of now returns that type. For
example:

#include <experimental/meta>
struct M {
int f(int, double);
void g() const noexcept;
};
static_assert(type_of(^^M::f) == ^^int(int, double));
// Previously failed.
static_assert(type_of(^^M::g) == ^^void() const noexcept);
// Previously failed.


10/8/26
std::meta::parent_of for namespaces

std::meta::parent_of and std::meta::has_parent did not accept a reflection
of a namespace or of a namespace alias: parent_of was not a constant
expression for one, and has_parent returned false. As specified in P2996R13
([meta.reflection.scope]), parent_of now returns the enclosing namespace for
any namespace or namespace alias other than the global namespace. For
example:

#include <experimental/meta>
namespace outer { namespace inner {} }
static_assert(std::meta::parent_of(^^outer::inner) == ^^outer);
// Previously an error.
static_assert(std::meta::parent_of(^^outer) == ^^::);
// Previously an error.


10/8/26
std::meta::source_location_of for reflections without a declaration

As specified in P2996R13 ([meta.reflection.names]),
std::meta::source_location_of is now a constant expression for every
reflection. For a reflection of a value, of a type other than a class or
enumeration type, of the global namespace, or of a data member description,
the result is a value-initialized std::source_location; the same is true for
other reflections that have no declaration position. Previously, those calls
were not constant expressions. For example:

static_assert(std::meta::source_location_of(^^int).line() == 0);
// Previously an error.
static_assert(std::meta::source_location_of(^^const S).line() != 0);
// Previously an error (S is a
// class).


10/8/26
std::meta::members_of: declaration order

std::meta::members_of returned the members of a class grouped by kind: the
nonstatic data members first, then the member functions, the member types
and type aliases, the static data members, and the member templates. The
members of a namespace were grouped by kind in the same way. As specified in
P2996R13 ([meta.reflection.member.queries]), the members of a class are now
returned in the order in which they are declared, with the
implicitly-declared special members after all the others. The members of a
namespace are now also returned in declaration order. For example:

#include <experimental/meta>
struct S {
int a;
void f();
int b;
};
// Previously a, b, f; now a, f, b (then the implicit members).
constexpr auto members = std::define_static_array(
std::meta::members_of(^^S, std::meta::access_context::unchecked()));


10/8/26
Protected members designated by splice-expressions

A class member designated by a splice-expression is accessible from any
point ([class.access.base]), and, as clarified by CWG 3109, the additional
access check for protected members ([class.protected]) does not apply to it.
The front end skipped the ordinary access check for such a member but still
did the protected member check, so forming a pointer to a protected member
with &[:r:], or naming it with obj.[:r:] or p->[:r:], was usually rejected
outside of the members and friends of the class of the member. For example,
with --c++26 --set_flag=reflection:

#include <experimental/meta>
class C {
protected:
int prot = 1;
};
constexpr std::meta::info r = std::meta::nonstatic_data_members_of(
^^C, std::meta::access_context::unchecked())[0];
int C::*pm = &[:r:]; // Previously an error
int f(C &c) {
return c.[:r:]; // Previously an error
}

This is now fixed.


10/7/26 [GH #176]
C-generating back end: always_inline attribute and inlined setjmp calls

Expand Down
8 changes: 6 additions & 2 deletions src/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -11465,7 +11465,8 @@ case).
operand_1, is_arrow_operator, member_sym,
projection_member_sym,
(a_boolean)locator.access_control_error_reported,
/*do_protected_member_check=*/TRUE, &member_position);
/*do_protected_member_check=*/!locator.is_splicer,
&member_position);
do_field_selection_operation(operand_1, orig_class_struct_union_type,
is_arrow_operator,
/*compiler_generated=*/FALSE,
Expand Down Expand Up @@ -11553,7 +11554,8 @@ case).
projection_member_sym,
(a_boolean)locator.
access_control_error_reported,
/*do_protected_member_check=*/TRUE,
/*do_protected_member_check=*/
!locator.is_splicer,
&member_position);
} /* if */
/* Make an operand for the function with the selector bound
Expand Down Expand Up @@ -41763,6 +41765,7 @@ FIXME: This is currently incomplete.
(a_ref_entry*)NULL,
result);
result->is_id_expression = TRUE;
result->designated_by_splice = TRUE;
} else if (iek == iek_variable) {
vp = (a_variable*)rvp->entity.ptr;
variable_case:
Expand All @@ -41785,6 +41788,7 @@ FIXME: This is currently incomplete.
(a_ref_entry*)NULL,
result);
result->is_id_expression = TRUE;
result->designated_by_splice = TRUE;
} else {
make_function_designator_operand(symbol_for(rp),
/*is_qualified_name=*/FALSE,
Expand Down
9 changes: 7 additions & 2 deletions src/exprutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -3486,6 +3486,7 @@ values.
operand->is_qualified_name = FALSE;
operand->is_microsoft_deferred_name = FALSE;
operand->access_control_error_reported = FALSE;
operand->designated_by_splice = FALSE;
operand->is_operand_of_address_of = FALSE;
operand->has_required_ptr_to_member_form = FALSE;
operand->is_template_id = FALSE;
Expand Down Expand Up @@ -23550,7 +23551,7 @@ by an "&" in the source, and *ampersand_position gives its position.
{
an_operand orig_operand;
a_symbol_ptr member_sym, fund_sym;
a_boolean has_required_ampersand;
a_boolean has_required_ampersand, check_protected_access;
a_boolean allow_addr_of_managed_member = FALSE, force_node = FALSE;

has_required_ampersand = (ampersand_position != NULL &&
Expand Down Expand Up @@ -23578,11 +23579,15 @@ by an "&" in the source, and *ampersand_position gives its position.
#if MICROSOFT_EXTENSIONS_ALLOWED
allow_addr_of_managed_member = operand->allow_addr_of_managed_member;
#endif /* MICROSOFT_EXTENSIONS_ALLOWED */
/* The protected member access check does not apply to a member designated
by a splice-expression ([class.protected]). */
check_protected_access = !operand->access_control_error_reported &&
!operand->designated_by_splice;
/* Make an operand for a pointer-to-member constant. */
make_ptr_to_member_constant_operand(member_sym, member_sym,
&orig_operand.position,
end_position_of_operand(&orig_operand),
!operand->access_control_error_reported,
check_protected_access,
(a_boolean)operand->is_qualified_name,
has_required_ampersand,
allow_addr_of_managed_member,
Expand Down
9 changes: 9 additions & 0 deletions src/exprutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,15 @@ typedef struct an_operand {
essentially still just a representation for
an identifier, e.g., ok_indefinite_function and
ok_sym_for_member. */
a_bit_field designated_by_splice:1;
/* TRUE if this operand was generated from a
splice-expression designating a class member.
Such a member is accessible from any point, and
the additional protected member access check
([class.protected]) does not apply to it. Like
access_control_error_reported, this remains
meaningful only for ok_sym_for_member
operands. */
a_bit_field is_operand_of_address_of:1;
/* TRUE if this operand is the immediate operand
of an "&" address-of operator. This is
Expand Down
Loading
Loading