https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119064
Jakub Jelinek <jakub at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jason at gcc dot gnu.org,
| |redi at gcc dot gnu.org
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
The patch is on top of the
https://gcc.gnu.org/pipermail/gcc-patches/2025-June/686210.html
https://gcc.gnu.org/pipermail/gcc-patches/2025-June/686211.html
https://gcc.gnu.org/pipermail/gcc-patches/2025-June/686212.html
patches.
Jason, could I ask for guidance on 4 issues?
1) https://eel.is/c++draft/diff.cpp23.dcl.dcl#1 notes that
struct C {}; struct C replaceable_if_eligible {};
and
struct C {}; struct C trivially_relocatable_if_eligible {};
are valid in C++11 to C++23. Seems clang 21 didn't bother with this
when implementing P2786R13 and just made those invalid even in the
older modes (similarly how we've tried override in C++98
for years until the pending patch).
What should I do about that:
a) ignore like clang and make those invalid
b) only support __replaceable_if_eligible and
__trivially_relocatable_if_eligible
contextual keywords in C++11 to C++23 and leave the non-__ prefixed ones
to
C++26 and later
c) the patch has quite ugly #if 0 part which tries to silently check if it
would
be a type redefinition before committing to the tentative parse and in
that
case giving up; it is basically a duplication of later parts of the
function,
some xref_tag parts and some functions it calls, but still missing trying
to
duplicate parts of resolve_typename_type and
maybe_process_partial_specialization
The intent is to see if the function or what it calls would diagnose a
redefinition error or some other kind of error and fail because of that
and in that case for C++ < 26 when there is a single newly C++26
contextual
keyword without __ prefix just punt and let the callers try to parse it
as variable definition (similarly how it is parsed if the contextual
keyword is not followed by { or : ).
d) perhaps (but haven't tried to implement it) instead of the #if 0 ugliness
just for the single new non-__ prefixed contextual keywords in C++ < 26
arrange not to commit to tentative parse just yet, continue up to the
point
where we'd diagnose type redefinition and at that point fail the parse
or commit to it; disadvantage is that we could raise errors twice I
guess,
but it wouldn't require duplicating tons of conditionals
e) something else?
Testcase I was playing with was:
namespace U {
struct A {};
struct A trivially_relocatable_if_eligible {};
}
namespace V {
template <int N>
struct B {};
template <int N>
struct B<N> trivially_relocatable_if_eligible {};
}
struct C {
struct D {};
struct D trivially_relocatable_if_eligible {};
};
namespace W {
struct E { struct F {}; };
struct E::F trivially_relocatable_if_eligible {};
}
template <int N>
struct V::B<N> trivially_relocatable_if_eligible {};
2) naming question for the builtin traits; the patch uses
__is_trivially_relocatable, __is_nothrow_relocatable and __is_replaceable
builtin traits; looking at clang which implemented this paper recently
in https://github.com/llvm/llvm-project/pull/127636
clang seems to use wild __builtin_is_cpp_trivially_relocatable
and __builtin_is_replaceable (apparently because they've implemented it too
early with different semantics; why one has the _cpp infix and the other
one doesn't is unclear); at least for libstdc++-v3 I think there are
no reasons to be afraid of older __is_trivially_relocatable or
__is_replaceable
or __is_nothrow_relocatable non-builtin traits
3) for the
https://eel.is/c++draft/class.prop#2.1
https://eel.is/c++draft/class.prop#2.2
https://eel.is/c++draft/class.prop#6.3
https://eel.is/c++draft/class.prop#6.4
the patch tries hard to avoid synthetizing lazy move or copy ctors and
move or copy assignment operators when trying to determine if a class type
is default-movable or not eligible for replacement because of my fear that
when this is done at the check_bases_and_members time at least for classes
which aren't trivially relocatable or replaceable for other reasons it will
basically kill the lazy stuff; is that doable that way at all?
Initially I didn't have the classtype_has_const_or_ref_members hack in there
and then e.g. struct S { const int s; }; __is_trivially_relocatable (S) was
incorrectly true, even when the lazily declared implicit move assignment
operator
is deleted; the hack fixes that, but I think e.g. walk_field_subobs has also
deleted case for copy/move ctor if there are rvalue reference type
non-static
data members; maybe that will be covered also by the same function, and
perhaps
e.g. using deleted special member functions on the bases or members;
on one side, at least without the new contextual keywords being present and
with the exception of the union exception, trivially relocatable or
replaceable
types should imply default-movable on the base types and in those cases
those
shouldn't have the deleted special member functions.
Anyway, perhaps another option would be stop computing this during type
completion,
and instead compute it on demand with caching, so either have 2 bits for the
trivially_relocatable and replaceable bitfields, 0 unknown, 1 no, 2 yes, or
just add one bit and compute both trivial relocatability and replaceability
at the same time; in that case synthetize whatever lazy methods we actually
need to check for deletion
4) so far I've been only concentrating on the new traits, seems clang has also
__builtin_trivially_relocate type-generic builtin which acts similarly to
__builtin_memmove, just perhaps works differently during constant expression
evaluation and has some extra checks plus the third argument is count, so
for memmove needs to be multiplied by sizeof (T); do you think we need this
too?