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?

Reply via email to