diff options
author | Jakub Jelinek <jakub@redhat.com> | 2025-07-11 19:05:38 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2025-07-11 19:05:38 +0200 |
commit | 981bd3e62cd271f620892cf5db56f00b4df50156 (patch) | |
tree | 82722ba9a728183e98a169066c5ef491cd09064c /gcc/testsuite | |
parent | 1f52396c6fc940224e9d858d49e41310a6dfa43d (diff) | |
download | gcc-981bd3e62cd271f620892cf5db56f00b4df50156.zip gcc-981bd3e62cd271f620892cf5db56f00b4df50156.tar.gz gcc-981bd3e62cd271f620892cf5db56f00b4df50156.tar.bz2 |
c++: Implement C++26 P2786R13 - Trivial Relocatability [PR119064]
The following patch implements the compiler side of the C++26 paper.
Based on the https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119064#c3
feedback, the patch enables the new conditional keywords
trivially_relocatable_if_eligible and replaceable_if_eligible only
for C++26, for older versions those conditional keywords yield
-Wc++26-compat warning and are treated as normal identifiers.
Plus __trivially_relocatable_if_eligible and __replaceable_if_eligible
are handled as conditional keywords always without diagnostics (similarly
to __final in C++98).
The patch uses __builtin_ prefix on the new traits (but unlike clang
which for some weird reason chose to name one __builtin_is_replaceable
and another __builtin_is_cpp_trivially_relocatable this one uses
__builtin_is_replaceable and __builtin_is_trivially_relocatable.
I'll try to convince clang to change, they've only implemented it
recently.
The patch computes these properties on demand, only when something needs
them (at the expense of eating 2 more bits per lang_type, but I've recently
saved 64 bits and a patch to save another 64 bits is pending; and even
4 bits wouldn't fit).
The patch doesn't add __builtin_trivially_relocate builtin that clang has,
std::trivially_relocate is not constexpr and I think we don't need it for
now at least until we implement some kind of vtable pointer signing
__builtin_memmove should do the job. Especially if libstdc++ will for clang
compatibility use the builtin if available and __builtin_memmove otherwise,
we can switch any time.
I've cross-tested all testcases also against the clang++ trunk
implementation, and both compilers agreed in everything except for
https://github.com/llvm/llvm-project/issues/143599
where clang++ was changed already and
https://github.com/llvm/llvm-project/issues/144232
where I believe clang++ got it wrong too.
The first testcase comes from
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2786r13.html#simple-worked-examples
just tweaked so that the classes are named differently each time and that it
compiles. There are 3 differences from the paper vs. the g++ as well as
clang++ implementation, I've added comments into
trivially-relocatable1.C but I think either that part of the paper wasn't
updated through the later changes or it got it wrong.
2025-07-11 Jakub Jelinek <jakub@redhat.com>
PR c++/119064
gcc/
* doc/invoke.texi (Wc++26-compat): Document.
gcc/c-family/
* c.opt (Wc++26-compat): New option.
* c.opt.urls: Regenerate.
* c-opts.cc (c_common_post_options): Clear warn_cxx26_compat for
C++26 or later.
* c-cppbuiltin.cc (c_cpp_builtins): For C++26 predefine
__cpp_trivial_relocatability=202502L.
gcc/cp/
* cp-tree.h: Implement C++26 P2786R13 - Trivial Relocatability.
(struct lang_type): Add trivially_relocatable,
trivially_relocatable_computed, replaceable and replaceable_computed
bitfields. Change width of dummy from 2 to 30.
(CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT,
CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, CLASSTYPE_REPLACEABLE_BIT,
CLASSTYPE_REPLACEABLE_COMPUTED): Define.
(enum virt_specifier): Add VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
and VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE enumerators.
(trivially_relocatable_type_p, replaceable_type_p): Declare.
* cp-trait.def (IS_NOTHROW_RELOCATABLE, IS_REPLACEABLE,
IS_TRIVIALLY_RELOCATABLE): New traits.
* parser.cc (cp_parser_class_property_specifier_seq_opt): Handle
trivially_relocatable_if_eligible,
__trivially_relocatable_if_eligible, replaceable_if_eligible and
__replaceable_if_eligible.
(cp_parser_class_head): Set CLASSTYPE_REPLACEABLE_BIT
and/or CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT if corresponding
conditional keywords were parsed and assert corresponding *_COMPUTED
macro is false.
* pt.cc (instantiate_class_template): Copy over also
CLASSTYPE_TRIVIALLY_RELOCATABLE_{BIT,COMPUTED} and
CLASSTYPE_REPLACEABLE_{BIT,COMPUTED} bits.
* semantics.cc (referenceable_type_p): Move definition earlier.
(trait_expr_value): Handle CPTK_IS_NOTHROW_RELOCATABLE,
CPTK_IS_REPLACEABLE and CPTK_IS_TRIVIALLY_RELOCATABLE.
(finish_trait_expr): Likewise.
* tree.cc (default_movable_type_p): New function.
(union_with_no_declared_special_member_fns): Likewise.
(trivially_relocatable_type_p): Likewise.
(replaceable_type_p): Likewise.
* constraint.cc (diagnose_trait_expr): Handle
CPTK_IS_NOTHROW_RELOCATABLE, CPTK_IS_REPLACEABLE and
CPTK_IS_TRIVIALLY_RELOCATABLE.
gcc/testsuite/
* g++.dg/cpp26/feat-cxx26.C: Add test for
__cpp_trivial_relocatability.
* g++.dg/cpp26/trivially-relocatable1.C: New test.
* g++.dg/cpp26/trivially-relocatable2.C: New test.
* g++.dg/cpp26/trivially-relocatable3.C: New test.
* g++.dg/cpp26/trivially-relocatable4.C: New test.
* g++.dg/cpp26/trivially-relocatable5.C: New test.
* g++.dg/cpp26/trivially-relocatable6.C: New test.
* g++.dg/cpp26/trivially-relocatable7.C: New test.
* g++.dg/cpp26/trivially-relocatable8.C: New test.
* g++.dg/cpp26/trivially-relocatable9.C: New test.
* g++.dg/cpp26/trivially-relocatable10.C: New test.
* g++.dg/cpp26/trivially-relocatable11.C: New test.
Diffstat (limited to 'gcc/testsuite')
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/feat-cxx26.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable1.C | 137 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable10.C | 135 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable11.C | 134 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable2.C | 204 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable3.C | 213 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable4.C | 128 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable5.C | 77 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable6.C | 30 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable7.C | 33 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable8.C | 190 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp26/trivially-relocatable9.C | 134 |
12 files changed, 1421 insertions, 0 deletions
diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C index 97bd36b..cfc5f61 100644 --- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C +++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C @@ -646,3 +646,9 @@ #elif __cpp_constexpr_exceptions != 202411 # error "__cpp_constexpr_exceptions != 202411" #endif + +#ifndef __cpp_trivial_relocatability +# error "__cpp_trivial_relocatability" +#elif __cpp_trivial_relocatability != 202502 +# error "__cpp_trivial_relocatability != 202502" +#endif diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable1.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable1.C new file mode 100644 index 0000000..29ba907 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable1.C @@ -0,0 +1,137 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +struct A {}; + +static_assert (std::is_trivially_relocatable_v <A>, ""); +static_assert (std::is_replaceable_v <A>, ""); + +struct B { + B (); + ~B (); + B (const B &); + B (B &&); + B &operator= (const B &); + B &operator= (B &&); +}; + +static_assert (!std::is_trivially_relocatable_v <B>, ""); +static_assert (!std::is_replaceable_v <B>, ""); + +struct C { + C (C &&) = delete; + C &operator= (C &&) = delete; + C () = default; +}; + +// Note, P2786R13 says it is trivially relocatable, but I think +// it isn't default-movable because overload resolution in both +// cases selects a deleted special member fn. +static_assert (!std::is_trivially_relocatable_v <C>, ""); +static_assert (!std::is_replaceable_v <C>, ""); + +struct D : A {}; + +static_assert (std::is_trivially_relocatable_v <D>, ""); +static_assert (std::is_replaceable_v <D>, ""); + +struct E : virtual A {}; + +static_assert (!std::is_trivially_relocatable_v <E>, ""); +static_assert (std::is_replaceable_v <E>, ""); + +struct F trivially_relocatable_if_eligible : virtual A {}; + +static_assert (!std::is_trivially_relocatable_v <F>, ""); +static_assert (std::is_replaceable_v <F>, ""); + +struct G { B data; }; + +static_assert (!std::is_trivially_relocatable_v <G>, ""); +static_assert (!std::is_replaceable_v <G>, ""); + +struct H { ~H () = default; }; + +static_assert (std::is_trivially_relocatable_v <H>, ""); +static_assert (std::is_replaceable_v <H>, ""); + +struct I { ~I (); }; +I::~I () = default; + +static_assert (!std::is_trivially_relocatable_v <I>, ""); +static_assert (!std::is_replaceable_v <I>, ""); + +struct J { virtual ~J () = default; }; + +// Note, P2786R13 says otherwise for both, but that looks like +// a bug in the paper, it otherwise says that polymorphic types +// can be both trivially relocatable and replaceable. +static_assert (std::is_trivially_relocatable_v <J>, ""); +static_assert (std::is_replaceable_v <J>, ""); + +struct K { ~K () = delete; }; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (!std::is_replaceable_v <K>, ""); + +struct L { L (L &&) = default; }; + +// Note, P2786R13 says otherwise for both, but that looks like +// a bug in the paper to me. While move ctor is trivial here, +// copy assignment operator is implicitly declared as deleted +// and move assignent operator is not declared. +static_assert (!std::is_trivially_relocatable_v <L>, ""); +static_assert (!std::is_replaceable_v <L>, ""); + +struct M { M (M &&); }; +M::M (M &&) = default; + +static_assert (!std::is_trivially_relocatable_v <M>, ""); +static_assert (!std::is_replaceable_v <M>, ""); + +struct N { N (N &&) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <N>, ""); +static_assert (!std::is_replaceable_v <N>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable10.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable10.C new file mode 100644 index 0000000..2ed1d5e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable10.C @@ -0,0 +1,135 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +struct A replaceable_if_eligible { A (A &&); A &operator= (A &&); ~A (); int a; }; + +static_assert (std::is_replaceable_v <A>, ""); +static_assert (!std::is_replaceable_v <const A>, ""); +static_assert (!std::is_replaceable_v <A volatile>, ""); +static_assert (!std::is_replaceable_v <const A volatile>, ""); + +struct B { B (B &&); B &operator= (B &&); ~B (); int a; }; + +static_assert (!std::is_replaceable_v <B>, ""); + +struct C replaceable_if_eligible : public A { C (C &&); C &operator= (C &&); ~C (); int a; }; + +static_assert (std::is_replaceable_v <C>, ""); + +struct D replaceable_if_eligible : public B { D (D &&); D &operator= (D &&); ~D (); int a; }; + +static_assert (!std::is_replaceable_v <D>, ""); + +struct E replaceable_if_eligible { E (E &&); E &operator= (E &&); ~E (); A a; }; + +static_assert (std::is_replaceable_v <E>, ""); + +struct F replaceable_if_eligible { F (F &&); F &operator= (F &&); ~F (); B a; }; + +static_assert (!std::is_replaceable_v <F>, ""); + +struct G replaceable_if_eligible { G (G &&); G &operator= (G &&); ~G () = delete; int a; }; + +static_assert (!std::is_replaceable_v <G>, ""); + +struct H replaceable_if_eligible : virtual A { H (H &&); H &operator= (H &&); ~H (); int a; }; + +static_assert (std::is_replaceable_v <H>, ""); + +struct I replaceable_if_eligible { I (I &&) = delete; I &operator= (I &&); ~I (); int a; }; + +static_assert (!std::is_replaceable_v <I>, ""); + +struct J replaceable_if_eligible { J (J &&); J &operator= (J &&) = delete; ~J (); int a; }; + +static_assert (!std::is_replaceable_v <J>, ""); + +struct K replaceable_if_eligible { K (const K &) = delete; K &operator= (K &&); ~K (); int a; }; + +static_assert (!std::is_replaceable_v <K>, ""); + +struct L replaceable_if_eligible { L (L &&); L &operator= (const L &) = delete; ~L (); int a; }; + +static_assert (!std::is_replaceable_v <L>, ""); + +struct M replaceable_if_eligible { M (); private: M (M &&); M &operator= (M &&); ~M (); int a; }; + +static_assert (std::is_replaceable_v <M>, ""); + +struct N replaceable_if_eligible { N (N &&); N &operator= (N &&); ~N (); const A a; }; + +static_assert (!std::is_replaceable_v <N>, ""); + +struct O replaceable_if_eligible { O (O &&); O &operator= (O &&); ~O (); volatile A a; }; + +static_assert (!std::is_replaceable_v <O>, ""); + +struct P replaceable_if_eligible { P (P &&); P &operator= (P &&); ~P (); const volatile A a; }; + +static_assert (!std::is_replaceable_v <P>, ""); + +struct Q replaceable_if_eligible { Q (Q &&); Q &operator= (Q &&); ~Q (); union { A a; int b; char c; }; }; + +static_assert (!std::is_replaceable_v <Q>, ""); + +struct R replaceable_if_eligible { R (R &&); R &operator= (R &&); ~R (); union { int a; B b; short c; }; }; + +static_assert (!std::is_replaceable_v <R>, ""); + +struct S replaceable_if_eligible { S (S &&); S &operator= (S &&); ~S (); union { int a; const int b; short c; }; }; + +static_assert (!std::is_replaceable_v <S>, ""); + +struct T replaceable_if_eligible { T (T &&); T &operator= (T &&); ~T () = default; int a; }; + +static_assert (std::is_replaceable_v <T>, ""); + +struct U replaceable_if_eligible { U (U &&); U &operator= (U &&); ~U (); union { T a; int b; char c; }; }; + +static_assert (!std::is_replaceable_v <U>, ""); + +struct V replaceable_if_eligible { V (V &&); V &operator= (V &&); ~V (); union { unsigned long long a; int b; char c; }; }; + +static_assert (std::is_replaceable_v <V>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable11.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable11.C new file mode 100644 index 0000000..71fc6f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable11.C @@ -0,0 +1,134 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +struct A { A (A &&) = default; A &operator= (A &&) = default; ~A () = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <A>, ""); +static_assert (std::is_replaceable_v <A>, ""); + +struct B { B (B &&); B &operator= (B &&) = default; ~B () = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <B>, ""); +static_assert (!std::is_replaceable_v <B>, ""); + +union C { int a; A b; }; + +static_assert (std::is_trivially_relocatable_v <C>, ""); +static_assert (std::is_replaceable_v <C>, ""); + +union D { int a; A b; B c; }; + +static_assert (!std::is_trivially_relocatable_v <D>, ""); +static_assert (!std::is_replaceable_v <D>, ""); + +union E { E (); int a; A b; }; + +static_assert (std::is_trivially_relocatable_v <E>, ""); +static_assert (std::is_replaceable_v <E>, ""); + +union F { F () = default; int a; A b; }; + +static_assert (std::is_trivially_relocatable_v <F>, ""); +static_assert (std::is_replaceable_v <F>, ""); + +union G { G (const G &); int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <G>, ""); +static_assert (!std::is_replaceable_v <G>, ""); + +union H { H (const H &) = default; int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <H>, ""); +static_assert (!std::is_replaceable_v <H>, ""); + +union I { I (I &&); int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <I>, ""); +static_assert (!std::is_replaceable_v <I>, ""); + +union J { J (J &&) = default; int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <J>, ""); +static_assert (!std::is_replaceable_v <J>, ""); + +union K { K &operator= (const K &); int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (!std::is_replaceable_v <K>, ""); + +union L { L &operator= (const L &) = default; int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <L>, ""); +static_assert (!std::is_replaceable_v <L>, ""); + +union M { M &operator= (M &&); int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <M>, ""); +static_assert (!std::is_replaceable_v <M>, ""); + +union N { N &operator= (N &&) = default; int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <N>, ""); +static_assert (!std::is_replaceable_v <N>, ""); + +union O { ~O (); int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <O>, ""); +static_assert (!std::is_replaceable_v <O>, ""); + +union P { ~P () = default; int a; A b; }; + +static_assert (!std::is_trivially_relocatable_v <P>, ""); +static_assert (!std::is_replaceable_v <P>, ""); + +union Q { int a; const A b; }; + +static_assert (std::is_trivially_relocatable_v <Q>, ""); +static_assert (!std::is_replaceable_v <Q>, ""); + +union S { volatile int a; A b; }; + +static_assert (std::is_trivially_relocatable_v <S>, ""); +static_assert (!std::is_replaceable_v <S>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable2.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable2.C new file mode 100644 index 0000000..b740061 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable2.C @@ -0,0 +1,204 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +class A {}; + +static_assert (std::is_trivially_relocatable_v <A>, ""); +static_assert (std::is_replaceable_v <A>, ""); +static_assert (std::is_trivially_relocatable <A>::value, ""); +static_assert (std::is_replaceable <A>::value, ""); + +struct B { ~B (); }; +static B z; + +static_assert (!std::is_trivially_relocatable_v <B>, ""); +static_assert (!std::is_replaceable_v <B>, ""); +static_assert (!std::is_trivially_relocatable <B>::value, ""); +static_assert (!std::is_replaceable <B>::value, ""); + +class C trivially_relocatable_if_eligible {}; + +static_assert (std::is_trivially_relocatable_v <C>, ""); +static_assert (std::is_replaceable_v <C>, ""); + +class D trivially_relocatable_if_eligible : A {}; + +static_assert (std::is_trivially_relocatable_v <D>, ""); +static_assert (std::is_replaceable_v <D>, ""); + +class E trivially_relocatable_if_eligible { + int a; + void *b; + int c[3]; + A d[3]; + B &e = z; +}; + +static_assert (std::is_trivially_relocatable_v <E>, ""); +static_assert (!std::is_replaceable_v <E>, ""); + +class F trivially_relocatable_if_eligible : A {}; + +static_assert (std::is_trivially_relocatable_v <F>, ""); +static_assert (std::is_replaceable_v <F>, ""); + +class G trivially_relocatable_if_eligible : virtual A {}; + +static_assert (!std::is_trivially_relocatable_v <G>, ""); +static_assert (std::is_replaceable_v <G>, ""); + +class H trivially_relocatable_if_eligible : B {}; + +static_assert (!std::is_trivially_relocatable_v <H>, ""); +static_assert (!std::is_replaceable_v <H>, ""); + +class I trivially_relocatable_if_eligible { I (I &&); }; + +static_assert (std::is_trivially_relocatable_v <I>, ""); +static_assert (!std::is_replaceable_v <I>, ""); + +class J trivially_relocatable_if_eligible { ~J (); }; + +static_assert (std::is_trivially_relocatable_v <J>, ""); +static_assert (!std::is_replaceable_v <J>, ""); + +class K trivially_relocatable_if_eligible { + B a; + B b[1]; + const B c; + const B d[1]; +}; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (!std::is_replaceable_v <K>, ""); + +class L trivially_relocatable_if_eligible: virtual A, B { B a; }; + +static_assert (!std::is_trivially_relocatable_v <L>, ""); +static_assert (!std::is_replaceable_v <L>, ""); + +static_assert (!std::is_trivially_relocatable_v <void>, ""); +static_assert (!std::is_trivially_relocatable_v <const void>, ""); +static_assert (std::is_trivially_relocatable_v <int>, ""); +static_assert (std::is_trivially_relocatable_v <const int>, ""); +static_assert (std::is_trivially_relocatable_v <char>, ""); +static_assert (std::is_trivially_relocatable_v <char const volatile>, ""); +static_assert (std::is_trivially_relocatable_v <unsigned long long>, ""); +static_assert (std::is_trivially_relocatable_v <void *>, ""); +static_assert (std::is_trivially_relocatable_v <const int *>, ""); +static_assert (!std::is_trivially_relocatable_v <int &>, ""); +static_assert (!std::is_trivially_relocatable_v <A &>, ""); +static_assert (std::is_trivially_relocatable_v <const A>, ""); +static_assert (std::is_trivially_relocatable_v <A [1]>, ""); +static_assert (std::is_trivially_relocatable_v <A []>, ""); +static_assert (!std::is_replaceable_v <void>, ""); +static_assert (!std::is_replaceable_v <const void>, ""); +static_assert (std::is_replaceable_v <int>, ""); +static_assert (!std::is_replaceable_v <const int>, ""); +static_assert (std::is_replaceable_v <char>, ""); +static_assert (!std::is_replaceable_v <char const volatile>, ""); +static_assert (std::is_replaceable_v <unsigned long long>, ""); +static_assert (std::is_replaceable_v <void *>, ""); +static_assert (std::is_replaceable_v <const int *>, ""); +static_assert (!std::is_replaceable_v <int &>, ""); +static_assert (!std::is_replaceable_v <A &>, ""); +static_assert (!std::is_replaceable_v <const A>, ""); +static_assert (std::is_replaceable_v <A [1]>, ""); +static_assert (std::is_replaceable_v <A []>, ""); + +struct M { const int i; }; + +static_assert (!std::is_trivially_relocatable_v <M>, ""); +static_assert (!std::is_replaceable_v <M>, ""); + +struct N trivially_relocatable_if_eligible { const int i; }; + +static_assert (std::is_trivially_relocatable_v <N>, ""); +static_assert (!std::is_replaceable_v <N>, ""); + +struct O { ~O (); }; + +static_assert (!std::is_trivially_relocatable_v <O>, ""); +static_assert (!std::is_replaceable_v <O>, ""); + +struct P { ~P () = default; }; + +static_assert (std::is_trivially_relocatable_v <P>, ""); +static_assert (std::is_replaceable_v <P>, ""); + +struct Q { Q (Q &&); Q (const Q &) = default; }; + +static_assert (!std::is_trivially_relocatable_v <Q>, ""); +static_assert (!std::is_replaceable_v <Q>, ""); + +struct R { R (R &&); }; + +static_assert (!std::is_trivially_relocatable_v <R>, ""); +static_assert (!std::is_replaceable_v <R>, ""); + +struct S { S (S &&) = default; }; + +static_assert (!std::is_trivially_relocatable_v <S>, ""); +static_assert (!std::is_replaceable_v <S>, ""); + +struct T { T (T &&) = default; T &operator= (T &&) = default; }; + +static_assert (std::is_trivially_relocatable_v <T>, ""); +static_assert (std::is_replaceable_v <T>, ""); + +struct U { U (const U &); }; + +static_assert (!std::is_trivially_relocatable_v <U>, ""); +static_assert (!std::is_replaceable_v <U>, ""); + +struct V { V (const V&) = default; }; + +static_assert (std::is_trivially_relocatable_v <V>, ""); +static_assert (std::is_replaceable_v <V>, ""); + +struct W { W (W &&) = delete; W (const W &) = default; }; + +static_assert (!std::is_trivially_relocatable_v <W>, ""); +static_assert (!std::is_replaceable_v <W>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable3.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable3.C new file mode 100644 index 0000000..312c11b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable3.C @@ -0,0 +1,213 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +class A {}; + +struct B { ~B (); }; + +class C trivially_relocatable_if_eligible { C (C &&); }; + +template <typename T> +class D trivially_relocatable_if_eligible : T {}; +D<A> a; +D<B> b; + +static_assert (std::is_trivially_relocatable_v <D<A>>, ""); +static_assert (!std::is_trivially_relocatable_v <D<B>>, ""); +static_assert (std::is_replaceable_v <D<A>>, ""); +static_assert (!std::is_replaceable_v <D<B>>, ""); + +struct E { E (E &&) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <E>, ""); +static_assert (!std::is_replaceable_v <E>, ""); + +struct F { F (const F &) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <F>, ""); +static_assert (!std::is_replaceable_v <F>, ""); + +struct G { G &operator= (G &&) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <G>, ""); +static_assert (!std::is_replaceable_v <G>, ""); + +struct H { ~H () = delete; }; + +static_assert (!std::is_trivially_relocatable_v <H>, ""); +static_assert (!std::is_replaceable_v <H>, ""); + +union U { C u; }; + +static_assert (std::is_trivially_relocatable_v <U>, ""); +static_assert (!std::is_replaceable_v <U>, ""); + +template <typename T> +struct I { int s; T t; }; + +static_assert (std::is_trivially_relocatable_v <I<int>>, ""); +static_assert (std::is_trivially_relocatable_v <I<volatile int>>, ""); +static_assert (!std::is_trivially_relocatable_v <I<const int>>, ""); +static_assert (!std::is_trivially_relocatable_v <I<const int &>>, ""); +static_assert (!std::is_trivially_relocatable_v <I<int &>>, ""); +static_assert (std::is_trivially_relocatable_v <I<int [2]>>, ""); +static_assert (!std::is_trivially_relocatable_v <I<const int [2]>>, ""); +static_assert (std::is_trivially_relocatable_v <I<int []>>, ""); +static_assert (std::is_replaceable_v <I<int>>, ""); +static_assert (!std::is_replaceable_v <I<volatile int>>, ""); +static_assert (!std::is_replaceable_v <I<const int>>, ""); +static_assert (!std::is_replaceable_v <I<const int &>>, ""); +static_assert (!std::is_replaceable_v <I<int &>>, ""); +static_assert (std::is_replaceable_v <I<int [2]>>, ""); +static_assert (!std::is_replaceable_v <I<const int [2]>>, ""); + +template <typename T> +struct J trivially_relocatable_if_eligible { int s; T t; }; + +static_assert (std::is_trivially_relocatable_v <J<int>>, ""); +static_assert (std::is_trivially_relocatable_v <J<volatile int>>, ""); +static_assert (std::is_trivially_relocatable_v <J<const int>>, ""); +static_assert (std::is_trivially_relocatable_v <J<const int &>>, ""); +static_assert (std::is_trivially_relocatable_v <J<int &>>, ""); +static_assert (std::is_trivially_relocatable_v <J<int [2]>>, ""); +static_assert (std::is_trivially_relocatable_v <J<const int [2]>>, ""); +static_assert (std::is_trivially_relocatable_v <J<int []>>, ""); +static_assert (std::is_replaceable_v <J<int>>, ""); +static_assert (!std::is_replaceable_v <J<volatile int>>, ""); +static_assert (!std::is_replaceable_v <J<const int>>, ""); +static_assert (!std::is_replaceable_v <J<const int &>>, ""); +static_assert (!std::is_replaceable_v <J<int &>>, ""); +static_assert (std::is_replaceable_v <J<int [2]>>, ""); +static_assert (!std::is_replaceable_v <J<const int [2]>>, ""); +static_assert (std::is_replaceable_v <J<int []>>, ""); + +struct K { K (K &&) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (!std::is_replaceable_v <K>, ""); + +struct L { L (const L &) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <L>, ""); +static_assert (!std::is_replaceable_v <L>, ""); + +struct M { M &operator= (M &&) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <M>, ""); +static_assert (!std::is_replaceable_v <M>, ""); + +struct N { N (N &&) = default; N &operator= (N &&) = default; }; + +static_assert (std::is_trivially_relocatable_v <N>, ""); +static_assert (std::is_replaceable_v <N>, ""); + +struct O { + O (const O &) = default; + O (O &&) = default; + O &operator= (O &&) = default; +}; + +static_assert (std::is_trivially_relocatable_v <O>, ""); +static_assert (std::is_replaceable_v <O>, ""); + +struct P { P (P &&) = default; P &operator= (P &&) = default; }; + +static_assert (std::is_trivially_relocatable_v <P>, ""); +static_assert (std::is_replaceable_v <P>, ""); + +struct Q { Q (Q &&) {} }; + +static_assert (!std::is_trivially_relocatable_v <Q>, ""); +static_assert (!std::is_replaceable_v <Q>, ""); + +struct R { R (const R &) {} }; + +static_assert (!std::is_trivially_relocatable_v <R>, ""); +static_assert (!std::is_replaceable_v <R>, ""); + +struct S { S &operator= (const S &) { return *this; }; }; + +static_assert (!std::is_trivially_relocatable_v <S>, ""); +static_assert (!std::is_replaceable_v <S>, ""); + +struct T {}; + +static_assert (std::is_trivially_relocatable_v <T>, ""); +static_assert (std::is_replaceable_v <T>, ""); + +struct V replaceable_if_eligible {}; + +static_assert (std::is_trivially_relocatable_v <V>, ""); +static_assert (std::is_replaceable_v <V>, ""); + +struct W { template <typename U> W (const U &) = delete; }; + +static_assert (std::is_trivially_relocatable_v <W>, ""); +static_assert (std::is_replaceable_v <W>, ""); + +template <typename T> +struct X : T {}; + +static_assert (!std::is_trivially_relocatable_v <X<Q>>, ""); +static_assert (!std::is_replaceable_v <X<Q>>, ""); + +template <typename T> +struct Y : virtual T {}; + +static_assert (!std::is_trivially_relocatable_v <Y<I<int>>>, ""); +static_assert (!std::is_trivially_relocatable_v <Y<I<const int>>>, ""); +static_assert (!std::is_trivially_relocatable_v <Y<Q>>, ""); +static_assert (std::is_replaceable_v <Y<I<int>>>, ""); +static_assert (!std::is_replaceable_v <Y<I<const int>>>, ""); +static_assert (!std::is_replaceable_v <Y<Q>>, ""); + +struct Z { + virtual ~Z () = default; + Z (Z &&) = default; + Z &operator= (Z &&) = default; +}; + +static_assert (std::is_trivially_relocatable_v <Z>, ""); +static_assert (std::is_replaceable_v <Z>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable4.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable4.C new file mode 100644 index 0000000..10aafc1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable4.C @@ -0,0 +1,128 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +struct A replaceable_if_eligible { + ~A () = delete; + A (A &&) = default; + A &operator= (A &&) = default; +}; + +static_assert (!std::is_trivially_relocatable_v <A>, ""); +static_assert (!std::is_replaceable_v <A>, ""); + +struct B replaceable_if_eligible { B (const B &) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <B>, ""); +static_assert (!std::is_replaceable_v <B>, ""); + +template <typename T> +struct C replaceable_if_eligible : virtual T {}; + +static_assert (!std::is_trivially_relocatable_v <C<A>>, ""); +static_assert (!std::is_trivially_relocatable_v <C<B>>, ""); +static_assert (!std::is_replaceable_v <C<A>>, ""); +static_assert (!std::is_replaceable_v <C<B>>, ""); + +template <typename T> +struct D { int s; T t; }; + +static_assert (!std::is_trivially_relocatable_v <C<D<int>>>, ""); +static_assert (std::is_replaceable_v <C<D<int>>>, ""); + +struct E trivially_relocatable_if_eligible replaceable_if_eligible { + E (E &&); + E &operator= (E &&) = default; +}; + +static_assert (std::is_trivially_relocatable_v <E>, ""); +static_assert (std::is_replaceable_v <E>, ""); + +struct F trivially_relocatable_if_eligible replaceable_if_eligible { + F (F &&) = default; + F &operator= (F &&); +}; + +static_assert (std::is_trivially_relocatable_v <F>, ""); +static_assert (std::is_replaceable_v <F>, ""); + +struct G replaceable_if_eligible { G (G const &) = default; }; + +static_assert (std::is_trivially_relocatable_v <G>, ""); +static_assert (std::is_replaceable_v <G>, ""); + +struct H { H (H const &) = default; }; + +static_assert (std::is_trivially_relocatable_v <H>, ""); +static_assert (std::is_replaceable_v <H>, ""); + +struct I replaceable_if_eligible { I &operator= (const I &) = default; }; + +static_assert (std::is_trivially_relocatable_v <I>, ""); +static_assert (std::is_replaceable_v <I>, ""); + +struct J { J &operator= (J const &) = default; }; + +static_assert (std::is_trivially_relocatable_v <J>, ""); +static_assert (std::is_replaceable_v <J>, ""); + +struct K { K (const K &) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (!std::is_replaceable_v <K>, ""); + +struct L { L (L&&) = delete; }; + +static_assert (!std::is_trivially_relocatable_v <L>, ""); +static_assert (!std::is_replaceable_v <L>, ""); + +struct M { M operator= (M); }; + +static_assert (!std::is_trivially_relocatable_v <M>, ""); +static_assert (!std::is_replaceable_v <M>, ""); + +struct N { N operator= (N &&); }; + +static_assert (!std::is_trivially_relocatable_v <N>, ""); +static_assert (!std::is_replaceable_v <N>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable5.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable5.C new file mode 100644 index 0000000..0416137 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable5.C @@ -0,0 +1,77 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wc++26-compat" } + +struct A __trivially_relocatable_if_eligible { A (const A &&); }; +struct B __replaceable_if_eligible { B (const B &&); B &operator= (B &&); }; +struct C __replaceable_if_eligible __final __trivially_relocatable_if_eligible { C (const C &&); C &operator= (C &&); }; +#if __cpp_trivial_relocatability >= 202502L +struct D trivially_relocatable_if_eligible { D (const D &&); }; +struct E replaceable_if_eligible { E (const E &&); E &operator= (E &&); }; +struct F trivially_relocatable_if_eligible replaceable_if_eligible final { F (const F &&); F &operator= (F &&); }; +#else +struct D trivially_relocatable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +// { dg-error "variable 'D trivially_relocatable_if_eligible' has initializer but incomplete type" "" { target c++23_down } .-1 } +struct E replaceable_if_eligible {}; // { dg-warning "identifier 'replaceable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +// { dg-error "variable 'E replaceable_if_eligible' has initializer but incomplete type" "" { target c++23_down } .-1 } +struct F trivially_relocatable_if_eligible replaceable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +// { dg-error "expected initializer before 'replaceable_if_eligible'" "" { target c++23_down } .-1 } +#endif +#if __cplusplus <= 202302L +struct G {}; +struct G trivially_relocatable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +struct H {}; +struct H replaceable_if_eligible {}; // { dg-warning "identifier 'replaceable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +struct I {}; +struct I trivially_relocatable_if_eligible replaceable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +#endif // { dg-error "expected initializer before 'replaceable_if_eligible'" "" { target c++23_down } .-1 } +struct J {}; +struct J __trivially_relocatable_if_eligible {}; // { dg-error "redefinition of 'struct J'" } +struct K {}; +struct K __replaceable_if_eligible {}; // { dg-error "redefinition of 'struct K'" } +struct L {}; +struct L __trivially_relocatable_if_eligible __replaceable_if_eligible {}; // { dg-error "redefinition of 'struct L'" } +struct M __trivially_relocatable_if_eligible __trivially_relocatable_if_eligible {}; // { dg-error "duplicate '__trivially_relocatable_if_eligible' specifier" } +struct N __replaceable_if_eligible __replaceable_if_eligible {}; // { dg-error "duplicate '__replaceable_if_eligible' specifier" } +struct O __trivially_relocatable_if_eligible __replaceable_if_eligible __replaceable_if_eligible __trivially_relocatable_if_eligible final final {}; +// { dg-error "duplicate '__replaceable_if_eligible' specifier" "" { target *-*-* } .-1 } +// { dg-error "duplicate '__trivially_relocatable_if_eligible' specifier" "" { target *-*-* } .-2 } +// { dg-error "duplicate 'final' specifier" "" { target *-*-* } .-3 } +#if __cpp_trivial_relocatability >= 202502L +struct P trivially_relocatable_if_eligible trivially_relocatable_if_eligible {}; // { dg-error "duplicate 'trivially_relocatable_if_eligible' specifier" "" { target c++26 } } +struct Q replaceable_if_eligible replaceable_if_eligible {}; // { dg-error "duplicate 'replaceable_if_eligible' specifier" "" { target c++26 } } +struct R trivially_relocatable_if_eligible replaceable_if_eligible replaceable_if_eligible trivially_relocatable_if_eligible final final {}; +// { dg-error "duplicate 'replaceable_if_eligible' specifier" "" { target c++26 } .-1 } +// { dg-error "duplicate 'trivially_relocatable_if_eligible' specifier" "" { target c++26 } .-2 } +// { dg-error "duplicate 'final' specifier" "" { target c++26 } .-3 } +struct S trivially_relocatable_if_eligible __trivially_relocatable_if_eligible {}; // { dg-error "duplicate '__trivially_relocatable_if_eligible' specifier" "" { target c++26 } } +struct T replaceable_if_eligible __replaceable_if_eligible {}; // { dg-error "duplicate '__replaceable_if_eligible' specifier" "" { target c++26 } } +struct U trivially_relocatable_if_eligible replaceable_if_eligible __replaceable_if_eligible __trivially_relocatable_if_eligible final __final {}; +// { dg-error "duplicate '__replaceable_if_eligible' specifier" "" { target c++26 } .-1 } +// { dg-error "duplicate '__trivially_relocatable_if_eligible' specifier" "" { target c++26 } .-2 } +// { dg-error "duplicate '__final' specifier" "" { target c++26 } .-3 } +struct V __trivially_relocatable_if_eligible trivially_relocatable_if_eligible {}; // { dg-error "duplicate 'trivially_relocatable_if_eligible' specifier" "" { target c++26 } } +struct W __replaceable_if_eligible replaceable_if_eligible {}; // { dg-error "duplicate 'replaceable_if_eligible' specifier" "" { target c++26 } } +struct X __trivially_relocatable_if_eligible __replaceable_if_eligible replaceable_if_eligible trivially_relocatable_if_eligible __final final {}; +// { dg-error "duplicate 'replaceable_if_eligible' specifier" "" { target c++26 } .-1 } +// { dg-error "duplicate 'trivially_relocatable_if_eligible' specifier" "" { target c++26 } .-2 } +// { dg-error "duplicate 'final' specifier" "" { target c++26 } .-3 } +#else +struct Y {}; +Y foo (); +struct Y trivially_relocatable_if_eligible = foo (); // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +struct Z {}; +Z bar (); +struct Z replaceable_if_eligible = bar (); // { dg-warning "identifier 'replaceable_if_eligible' is a conditional keyword in" "" { target c++23_down } } +#endif + +static_assert (__builtin_is_trivially_relocatable (A), ""); +static_assert (__builtin_is_replaceable (B), ""); +static_assert (__builtin_is_trivially_relocatable (C), ""); +static_assert (__builtin_is_replaceable (C), ""); +#if __cpp_trivial_relocatability >= 202502L +static_assert (__builtin_is_trivially_relocatable (D), ""); +static_assert (__builtin_is_replaceable (E), ""); +static_assert (__builtin_is_trivially_relocatable (F), ""); +static_assert (__builtin_is_replaceable (F), ""); +#endif diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable6.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable6.C new file mode 100644 index 0000000..ffcf12b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable6.C @@ -0,0 +1,30 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++98_only } } +// { dg-additional-options "-Wc++26-compat" } + +struct A __trivially_relocatable_if_eligible {}; +struct B __replaceable_if_eligible {}; +struct C __replaceable_if_eligible __final __trivially_relocatable_if_eligible {}; +struct D trivially_relocatable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" } +// { dg-error "variable 'D trivially_relocatable_if_eligible' has initializer but incomplete type" "" { target *-*-* } .-1 } +// { dg-error "extended initializer lists only available with" "" { target *-*-* } .-2 } +struct E replaceable_if_eligible {}; // { dg-warning "identifier 'replaceable_if_eligible' is a conditional keyword in" } +// { dg-error "variable 'E replaceable_if_eligible' has initializer but incomplete type" "" { target *-*-* } .-1 } +// { dg-error "extended initializer lists only available with" "" { target *-*-* } .-2 } +struct F trivially_relocatable_if_eligible replaceable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" } +// { dg-error "expected initializer before 'replaceable_if_eligible'" "" { target *-*-* } .-1 } +struct G {}; +struct G trivially_relocatable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" } +// { dg-error "extended initializer lists only available with" "" { target *-*-* } .-1 } +struct H {}; +struct H replaceable_if_eligible {}; // { dg-warning "identifier 'replaceable_if_eligible' is a conditional keyword in" } +// { dg-error "extended initializer lists only available with" "" { target *-*-* } .-1 } +struct I {}; +struct I trivially_relocatable_if_eligible replaceable_if_eligible {}; // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" } +// { dg-error "expected initializer before 'replaceable_if_eligible'" "" { target *-*-* } .-1 } +struct J {}; +J foo (); +struct J trivially_relocatable_if_eligible = foo (); // { dg-warning "identifier 'trivially_relocatable_if_eligible' is a conditional keyword in" } +struct K {}; +K bar (); +struct K replaceable_if_eligible = bar (); // { dg-warning "identifier 'replaceable_if_eligible' is a conditional keyword in" } diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable7.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable7.C new file mode 100644 index 0000000..608c245 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable7.C @@ -0,0 +1,33 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + // { dg-error "invalid use of incomplete type 'struct A'" "" { target *-*-* } .-1 } + +template <typename T> +inline constexpr bool is_nothrow_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_nothrow_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + // { dg-error "invalid use of incomplete type 'struct A'" "" { target *-*-* } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} // { dg-error "invalid use of incomplete type 'struct A'" "" { target *-*-* } .-1 } + +struct A; // { dg-message "forward declaration of 'struct A'" } + +auto a = std::is_trivially_relocatable_v <A>; // { dg-message "required from here" } +auto b = std::is_nothrow_relocatable_v <A>; // { dg-message "required from here" } +auto c = std::is_replaceable_v <A>; // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable8.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable8.C new file mode 100644 index 0000000..5f8390d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable8.C @@ -0,0 +1,190 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_nothrow_relocatable + : public integral_constant <bool, __builtin_is_nothrow_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_nothrow_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_nothrow_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +struct A { A (A &&) = default; A &operator= (A &&) = default; ~A () = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <A>, ""); +static_assert (std::is_nothrow_relocatable_v <A>, ""); +static_assert (std::is_replaceable_v <A>, ""); + +struct B { B (B &&); B &operator= (B &&) = default; ~B () = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <B>, ""); +static_assert (!std::is_nothrow_relocatable_v <B>, ""); +static_assert (!std::is_replaceable_v <B>, ""); + +struct C { C (C &&) = default; C &operator= (C &&); ~C () = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <C>, ""); +static_assert (std::is_nothrow_relocatable_v <C>, ""); +static_assert (!std::is_replaceable_v <C>, ""); + +struct D { D (D &&) = delete; D &operator= (D &&) = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <D>, ""); +static_assert (!std::is_nothrow_relocatable_v <D>, ""); +static_assert (!std::is_replaceable_v <D>, ""); + +struct E { E (E &&) = default; E &operator= (E &&) = delete; int a; }; + +static_assert (!std::is_trivially_relocatable_v <E>, ""); +static_assert (std::is_nothrow_relocatable_v <E>, ""); +static_assert (!std::is_replaceable_v <E>, ""); + +struct F { F (F &&) = default; F &operator= (F &&) = default; ~F () = delete; int a; }; + +static_assert (!std::is_trivially_relocatable_v <F>, ""); +static_assert (!std::is_nothrow_relocatable_v <F>, ""); +static_assert (!std::is_replaceable_v <F>, ""); + +struct G { G (const G &) = default; G &operator= (const G &) = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <G>, ""); +static_assert (std::is_nothrow_relocatable_v <G>, ""); +static_assert (std::is_replaceable_v <G>, ""); + +struct H { H (const H &); H &operator= (const H &) = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <H>, ""); +static_assert (!std::is_nothrow_relocatable_v <H>, ""); +static_assert (!std::is_replaceable_v <H>, ""); + +struct I { I (const I &) = default; I &operator= (const I &); ~I () = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <I>, ""); +static_assert (std::is_nothrow_relocatable_v <I>, ""); +static_assert (!std::is_replaceable_v <I>, ""); + +struct J { J (const J &) = delete; J &operator= (const J &) = default; int a; }; + +static_assert (!std::is_trivially_relocatable_v <J>, ""); +static_assert (!std::is_nothrow_relocatable_v <J>, ""); +static_assert (!std::is_replaceable_v <J>, ""); + +struct K { K (const K &) = default; K &operator= (const K &) = delete; int a; }; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (std::is_nothrow_relocatable_v <K>, ""); +static_assert (!std::is_replaceable_v <K>, ""); + +struct M; +struct L { L (L &&) = default; L (M &&); L &operator= (L &&) = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <L>, ""); +static_assert (std::is_nothrow_relocatable_v <L>, ""); +static_assert (std::is_replaceable_v <L>, ""); + +struct M : public L { using L::L; M (const M &); M &operator= (M &&) = default; int b; }; + +static_assert (!std::is_trivially_relocatable_v <M>, ""); +static_assert (!std::is_nothrow_relocatable_v <M>, ""); +static_assert (!std::is_replaceable_v <M>, ""); + +struct O; +struct N { N (N &&) = default; N &operator= (N &&) = default; N &operator= (O &&); int a; }; + +static_assert (std::is_trivially_relocatable_v <N>, ""); +static_assert (std::is_nothrow_relocatable_v <N>, ""); +static_assert (std::is_replaceable_v <N>, ""); + +struct O : public N { using N::operator=; O (O &&) = default; int b; }; + +static_assert (!std::is_trivially_relocatable_v <O>, ""); +static_assert (std::is_nothrow_relocatable_v <O>, ""); +static_assert (!std::is_replaceable_v <O>, ""); + +struct Q; +struct P { template <typename T> P (T &&) {} }; + +static_assert (std::is_trivially_relocatable_v <P>, ""); +static_assert (std::is_nothrow_relocatable_v <P>, ""); +static_assert (std::is_replaceable_v <P>, ""); + +struct Q : public P { using P::P; Q (const Q &); }; + +static_assert (!std::is_trivially_relocatable_v <Q>, ""); +static_assert (!std::is_nothrow_relocatable_v <Q>, ""); +static_assert (!std::is_replaceable_v <Q>, ""); + +struct S; +struct R { R (const R &) = default; R (const M &); R &operator= (R &&) = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <R>, ""); +static_assert (std::is_nothrow_relocatable_v <R>, ""); +static_assert (std::is_replaceable_v <R>, ""); + +struct S : public R { using R::R; S &operator= (S &&) = default; int b; }; + +static_assert (!std::is_trivially_relocatable_v <S>, ""); +static_assert (!std::is_nothrow_relocatable_v <S>, ""); +static_assert (!std::is_replaceable_v <S>, ""); + +struct T { T (T &&) = default; T &operator= (T &&) = default; ~T (); int a; }; + +static_assert (!std::is_trivially_relocatable_v <T>, ""); +static_assert (std::is_nothrow_relocatable_v <T>, ""); +static_assert (!std::is_replaceable_v <T>, ""); + +struct U { U (const U &) = default; U &operator= (const U &) = default; ~U (); int a; }; + +static_assert (!std::is_trivially_relocatable_v <U>, ""); +static_assert (std::is_nothrow_relocatable_v <U>, ""); +static_assert (!std::is_replaceable_v <U>, ""); + +struct V { public: V (); private: V (V &&) = default; V &operator= (V &&) = default; ~V () = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <V>, ""); +static_assert (std::is_nothrow_relocatable_v <V>, ""); +static_assert (std::is_replaceable_v <V>, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/trivially-relocatable9.C b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable9.C new file mode 100644 index 0000000..1c45b53 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/trivially-relocatable9.C @@ -0,0 +1,134 @@ +// P2786R13 - C++26 Trivial Relocatability +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++17 } } + +#if __cpp_trivial_relocatability < 202502L +#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible +#define replaceable_if_eligible __replaceable_if_eligible +#endif + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename> +struct is_trivially_relocatable; + +template <typename> +struct is_replaceable; + +template<typename T> +struct is_trivially_relocatable + : public integral_constant <bool, __builtin_is_trivially_relocatable (T)> +{ +}; + +template<typename T> +struct is_nothrow_relocatable + : public integral_constant <bool, __builtin_is_nothrow_relocatable (T)> +{ +}; + +template<typename T> +struct is_replaceable + : public integral_constant <bool, __builtin_is_replaceable (T)> +{ +}; + +template <typename T> +inline constexpr bool is_trivially_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_trivially_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_nothrow_relocatable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_nothrow_relocatable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } + +template <typename T> +inline constexpr bool is_replaceable_v // { dg-warning "inline variables are only available with" "" { target c++14_down } } + = __builtin_is_replaceable (T); // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +} + +struct A trivially_relocatable_if_eligible { A (A &&); A &operator= (A &&); ~A (); int a; }; + +static_assert (std::is_trivially_relocatable_v <A>, ""); +static_assert (std::is_nothrow_relocatable_v <A>, ""); + +struct B { B (B &&); B &operator= (B &&); ~B (); int a; }; + +static_assert (!std::is_trivially_relocatable_v <B>, ""); +static_assert (!std::is_nothrow_relocatable_v <B>, ""); + +struct C trivially_relocatable_if_eligible : public A { C (C &&); C &operator= (C &&); ~C (); int a; }; + +static_assert (std::is_trivially_relocatable_v <C>, ""); +static_assert (std::is_nothrow_relocatable_v <C>, ""); + +struct D trivially_relocatable_if_eligible : public B { D (D &&); D &operator= (D &&); ~D (); int a; }; + +static_assert (!std::is_trivially_relocatable_v <D>, ""); +static_assert (!std::is_nothrow_relocatable_v <D>, ""); + +struct E trivially_relocatable_if_eligible { E (E &&); E &operator= (E &&); ~E (); A a; }; + +static_assert (std::is_trivially_relocatable_v <E>, ""); +static_assert (std::is_nothrow_relocatable_v <E>, ""); + +struct F trivially_relocatable_if_eligible { F (F &&) noexcept; F &operator= (F &&); ~F (); B a; }; + +static_assert (!std::is_trivially_relocatable_v <F>, ""); +static_assert (std::is_nothrow_relocatable_v <F>, ""); + +struct G trivially_relocatable_if_eligible { G (G &&); G &operator= (G &&); ~G () = delete; int a; }; + +static_assert (!std::is_trivially_relocatable_v <G>, ""); +static_assert (!std::is_nothrow_relocatable_v <G>, ""); + +struct H trivially_relocatable_if_eligible : virtual A { H (H &&); H &operator= (H &&); ~H (); int a; }; + +static_assert (!std::is_trivially_relocatable_v <H>, ""); +static_assert (!std::is_nothrow_relocatable_v <H>, ""); + +struct I trivially_relocatable_if_eligible { I (I &&); I &operator= (I &&); ~I (); A &a; int &b; }; + +static_assert (std::is_trivially_relocatable_v <I>, ""); +static_assert (std::is_nothrow_relocatable_v <I>, ""); + +struct J trivially_relocatable_if_eligible { J (J &&); J &operator= (J &&); ~J (); B &a; int &b; }; + +static_assert (std::is_trivially_relocatable_v <J>, ""); +static_assert (std::is_nothrow_relocatable_v <J>, ""); + +struct K trivially_relocatable_if_eligible { K (K &&) noexcept; K &operator= (K &&); ~K (); union { A a; int b; char c; }; }; + +static_assert (!std::is_trivially_relocatable_v <K>, ""); +static_assert (std::is_nothrow_relocatable_v <K>, ""); + +struct L trivially_relocatable_if_eligible { L (L &&); L &operator= (L &&); ~L (); union { int a; B b; short c; }; }; + +static_assert (!std::is_trivially_relocatable_v <L>, ""); +static_assert (!std::is_nothrow_relocatable_v <L>, ""); + +struct M trivially_relocatable_if_eligible { M (M &&); M &operator= (M &&); ~M () = default; int a; }; + +static_assert (std::is_trivially_relocatable_v <M>, ""); +static_assert (std::is_nothrow_relocatable_v <M>, ""); + +struct N trivially_relocatable_if_eligible { N (N &&); N &operator= (N &&); ~N (); union { M a; int b; char c; }; }; + +static_assert (std::is_trivially_relocatable_v <N>, ""); +static_assert (std::is_nothrow_relocatable_v <N>, ""); + +struct O trivially_relocatable_if_eligible { O (O &&); O &operator= (O &&); ~O (); union { unsigned long long a; int b; char c; }; }; + +static_assert (std::is_trivially_relocatable_v <O>, ""); +static_assert (std::is_nothrow_relocatable_v <O>, ""); + +struct P { P (P &&) noexcept; P &operator= (P &&); ~P (); int a; }; + +static_assert (!std::is_trivially_relocatable_v <P>, ""); +static_assert (std::is_nothrow_relocatable_v <P>, ""); |