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?