On 6/17/25 2:25 AM, Jakub Jelinek wrote:
Hi!
When writing the libstdc++ patch, I've noticed I've missed adding any
testsuite coverage for __builtin_is_nothrow_relocatable trait.
And got wrong the implementation as well, I thought type2 in that
case should be the rvalue reference type to type1, but it seems it
it has to be a TREE_VEC with single element of that rvalue reference type.
Fixed thusly (only changes since last patch are in the
(trait_expr_value) <case CPTK_IS_NOTHROW_RELOCATABLE>,
additional test coverage for __builtin_is_nothrow_relocatable and
some indentation fixes (8 spaces to tab)).
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2025-06-17 Jakub Jelinek <ja...@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_if_eligible,
replaceable_if_eligible, trivially_relocatable,
trivially_relocatable_computed, replaceable and replaceable_computed
bitfields. Change width of dummy from 2 to 28.
(CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE,
CLASSTYPE_REPLACEABLE_IF_ELIGIBLE, CLASSTYPE_TRIVIALLY_RELOCATABLE,
CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, CLASSTYPE_REPLACEABLE,
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_IF_ELIGIBLE
and/or CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if corresponding
conditional keywords were parsed.
* pt.cc (instantiate_class_template): Copy over also
CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE and
CLASSTYPE_REPLACEABLE_IF_ELIGIBLE 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.
--- gcc/c-family/c.opt.jj 2025-06-12 09:48:50.064307296 +0200
+++ gcc/c-family/c.opt 2025-06-13 14:50:24.533527899 +0200
@@ -493,6 +493,10 @@ Wc++20-compat
C++ ObjC++ Var(warn_cxx20_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
Init(0) CPP(cpp_warn_cxx20_compat) CppReason(CPP_W_CXX20_COMPAT)
Warn about C++ constructs whose meaning differs between ISO C++ 2017 and ISO
C++ 2020.
+Wc++26-compat
+C++ ObjC++ Var(warn_cxx26_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
Init(0)
+Warn about C++ constructs whose meaning differs between ISO C++ 2023 and ISO
C++ 2026.
+
Wc++11-extensions
C++ ObjC++ Var(warn_cxx11_extensions) Warning Init(1)
Warn about C++11 constructs in code compiled with an older standard.
--- gcc/c-family/c.opt.urls.jj 2025-06-12 09:48:50.122306526 +0200
+++ gcc/c-family/c.opt.urls 2025-06-13 14:50:24.718525502 +0200
@@ -187,6 +187,9 @@ UrlSuffix(gcc/Warning-Options.html#index
Wc++20-compat
UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b20-compat)
+Wc++26-compat
+UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b26-compat)
+
Wc++11-extensions
UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b11-extensions)
--- gcc/c-family/c-opts.cc.jj 2025-06-12 09:48:50.000308146 +0200
+++ gcc/c-family/c-opts.cc 2025-06-13 14:50:24.479528598 +0200
@@ -1165,6 +1165,9 @@ c_common_post_options (const char **pfil
warn_cxx20_compat = 0;
cpp_opts->cpp_warn_cxx20_compat = 0;
}
+ if (cxx_dialect >= cxx26)
+ /* Don't warn about C++26 compatibility changes in C++26 or later. */
+ warn_cxx26_compat = 0;
/* C++17 has stricter evaluation order requirements; let's use some of them
for earlier C++ as well, so chaining works as expected. */
--- gcc/c-family/c-cppbuiltin.cc.jj 2025-06-12 09:48:49.829310417 +0200
+++ gcc/c-family/c-cppbuiltin.cc 2025-06-13 14:50:24.496528378 +0200
@@ -1094,6 +1094,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_variadic_friend=202403L");
cpp_define (pfile, "__cpp_pack_indexing=202311L");
cpp_define (pfile, "__cpp_pp_embed=202502L");
+ cpp_define (pfile, "__cpp_trivial_relocatability=202502L");
}
if (flag_concepts && cxx_dialect > cxx14)
cpp_define (pfile, "__cpp_concepts=202002L");
--- gcc/cp/cp-tree.h.jj 2025-06-12 09:49:19.747913102 +0200
+++ gcc/cp/cp-tree.h 2025-06-13 14:50:24.450528973 +0200
@@ -2492,6 +2492,13 @@ struct GTY(()) lang_type {
bool erroneous : 1;
bool non_pod_aggregate : 1;
bool non_aggregate_pod : 1;
+ bool trivially_relocatable_if_eligible : 1;
+ bool replaceable_if_eligible : 1;
+
+ bool trivially_relocatable : 1;
+ bool trivially_relocatable_computed : 1;
+ bool replaceable : 1;
+ bool replaceable_computed : 1;
I wonder if we can get away with two bits per property? I don't think
there's a way to query whether the "if_eligible" appeared on the type,
only whether it is in fact e.g. replaceable.
So if replaceable is set and replaceable_computed is not, it means
_if_eligible was specified?
> /* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If
@@ -2500,7 +2507,7 @@ struct GTY(()) lang_type {
/* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or
remove a flag. */
- unsigned dummy : 2;
+ unsigned dummy : 28;
tree primary_base;
vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2836,6 +2843,34 @@ struct GTY(()) lang_type {
above (c++/120012). This could also be a hash_set. */
#define CLASSTYPE_NON_AGGREGATE_POD(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->non_aggregate_pod)
+
+/* True if this class is marked with trivially_relocatable_if_eligible
+ conditional keyword. */
+#define CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable_if_eligible)
+
+/* True if this class is marked with replaceable_if_eligible conditional
+ keyword. */
+#define CLASSTYPE_REPLACEABLE_IF_ELIGIBLE(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->replaceable_if_eligible)
+
+/* True if this class is trivially relocatable. */
+#define CLASSTYPE_TRIVIALLY_RELOCATABLE(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable)
+
+/* True if whether this class is trivially relocatable or not
+ has been computed already. */
+#define CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable_computed)
+
+/* True if this class is replaceable. */
+#define CLASSTYPE_REPLACEABLE(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->replaceable)
+
+/* True if whether this class is replaceable or not has been computed
+ already. */
+#define CLASSTYPE_REPLACEABLE_COMPUTED(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->replaceable_computed)
/* Additional macros for inheritance information. */
@@ -6463,7 +6498,9 @@ enum virt_specifier
{
VIRT_SPEC_UNSPECIFIED = 0x0,
VIRT_SPEC_FINAL = 0x1,
- VIRT_SPEC_OVERRIDE = 0x2
+ VIRT_SPEC_OVERRIDE = 0x2,
+ VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE = 0x4,
+ VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE = 0x8
};
/* A type-qualifier, or bitmask therefore, using the VIRT_SPEC
@@ -8231,6 +8268,8 @@ extern bool pod_type_p
(const_tree);
extern bool layout_pod_type_p (const_tree);
extern bool std_layout_type_p (const_tree);
extern bool trivial_type_p (const_tree);
+extern bool trivially_relocatable_type_p (tree);
+extern bool replaceable_type_p (tree);
extern bool trivially_copyable_p (const_tree);
extern bool type_has_unique_obj_representations (const_tree);
extern bool scalarish_type_p (const_tree);
--- gcc/cp/cp-trait.def.jj 2025-06-12 09:48:50.611300032 +0200
+++ gcc/cp/cp-trait.def 2025-06-13 14:50:24.410529492 +0200
@@ -87,12 +87,14 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE,
DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
DEFTRAIT_EXPR (IS_NOTHROW_DESTRUCTIBLE, "__is_nothrow_destructible", 1)
DEFTRAIT_EXPR (IS_NOTHROW_INVOCABLE, "__is_nothrow_invocable", -1)
+DEFTRAIT_EXPR (IS_NOTHROW_RELOCATABLE, "__builtin_is_nothrow_relocatable", 1)
DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF,
"__is_pointer_interconvertible_base_of", 2)
DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
+DEFTRAIT_EXPR (IS_REPLACEABLE, "__builtin_is_replaceable", 1)
DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
@@ -101,6 +103,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE,
DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
DEFTRAIT_EXPR (IS_TRIVIALLY_DESTRUCTIBLE, "__is_trivially_destructible", -1)
+DEFTRAIT_EXPR (IS_TRIVIALLY_RELOCATABLE, "__builtin_is_trivially_relocatable",
1)
DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
DEFTRAIT_EXPR (IS_VIRTUAL_BASE_OF, "__builtin_is_virtual_base_of", 2)
--- gcc/cp/parser.cc.jj 2025-06-13 14:50:09.256725765 +0200
+++ gcc/cp/parser.cc 2025-06-13 14:50:24.416529414 +0200
@@ -28012,6 +28012,8 @@ cp_parser_class_specifier (cp_parser* pa
class-property-specifier:
final
+ trivially_relocatable_if_eligible (C++26)
+ replaceable_if_eligible (C++26)
Returns a bitmask representing the class-property-specifiers. */
@@ -28044,6 +28046,38 @@ cp_parser_class_property_specifier_seq_o
}
else if (id_equal (token->u.value, "__final"))
virt_specifier = VIRT_SPEC_FINAL;
+ else if (id_equal (token->u.value, "trivially_relocatable_if_eligible"))
+ {
+ if (cxx_dialect < cxx26)
+ {
+ /* Warn about the C++26 conditional keyword (but don't parse
+ it). */
+ warning_at (token->location, OPT_Wc__26_compat,
+ "identifier %qE is a conditional keyword in C++26",
+ token->u.value);
+ break;
+ }
+ virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE;
+ }
+ else if (id_equal (token->u.value,
+ "__trivially_relocatable_if_eligible"))
+ virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE;
+ else if (id_equal (token->u.value, "replaceable_if_eligible"))
+ {
+ if (cxx_dialect < cxx26)
+ {
+ /* Warn about the C++26 conditional keyword (but don't parse
+ it). */
+ warning_at (token->location, OPT_Wc__26_compat,
+ "identifier %qE is a conditional keyword in C++26",
+ token->u.value);
+ break;
+ }
+ virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE;
+ }
+ else if (id_equal (token->u.value,
+ "__replaceable_if_eligible"))
+ virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE;
else
break;
@@ -28599,6 +28633,10 @@ cp_parser_class_head (cp_parser* parser,
DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
if (type && (virt_specifiers & VIRT_SPEC_FINAL))
CLASSTYPE_FINAL (type) = 1;
+ if (type && (virt_specifiers & VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE))
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE (type) = 1;
+ if (type && (virt_specifiers & VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE))
+ CLASSTYPE_REPLACEABLE_IF_ELIGIBLE (type) = 1;
out:
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
--- gcc/cp/pt.cc.jj 2025-06-12 09:48:51.130293140 +0200
+++ gcc/cp/pt.cc 2025-06-13 14:50:24.394529699 +0200
@@ -12700,7 +12700,13 @@ instantiate_class_template (tree type)
determine_visibility (TYPE_MAIN_DECL (type));
}
if (CLASS_TYPE_P (type))
- CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern);
+ {
+ CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern);
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE (type)
+ = CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE (pattern);
+ CLASSTYPE_REPLACEABLE_IF_ELIGIBLE (type)
+ = CLASSTYPE_REPLACEABLE_IF_ELIGIBLE (pattern);
+ }
pbinfo = TYPE_BINFO (pattern);
--- gcc/cp/semantics.cc.jj 2025-06-12 09:48:51.180292476 +0200
+++ gcc/cp/semantics.cc 2025-06-16 19:15:25.223070535 +0200
@@ -13359,6 +13359,18 @@ object_type_p (const_tree type)
&& !VOID_TYPE_P (type));
}
+/* [defns.referenceable] True iff TYPE is a referenceable type. */
+
+static bool
+referenceable_type_p (const_tree type)
+{
+ return (TYPE_REF_P (type)
+ || object_type_p (type)
+ || (FUNC_OR_METHOD_TYPE_P (type)
+ && (type_memfn_quals (type) == TYPE_UNQUALIFIED
+ && type_memfn_rqual (type) == REF_QUAL_NONE)));
The inner parens seem redundant.
+}
+
/* Actually evaluates the trait. */
static bool
@@ -13528,6 +13540,21 @@ trait_expr_value (cp_trait_kind kind, tr
case CPTK_IS_NOTHROW_INVOCABLE:
return expr_noexcept_p (build_invoke (type1, type2, tf_none), tf_none);
+ case CPTK_IS_NOTHROW_RELOCATABLE:
+ if (trivially_relocatable_type_p (type1))
+ return true;
+ else
+ {
+ type1 = strip_array_types (type1);
+ if (!referenceable_type_p (type1))
+ return false;
+ tree arg = make_tree_vec (1);
+ TREE_VEC_ELT (arg, 0)
+ = cp_build_reference_type (type1, /*rval=*/true);
+ return (is_nothrow_xible (INIT_EXPR, type1, arg)
+ && is_nothrow_xible (BIT_NOT_EXPR, type1, NULL_TREE));
+ }
+
case CPTK_IS_OBJECT:
return object_type_p (type1);
@@ -13546,6 +13573,9 @@ trait_expr_value (cp_trait_kind kind, tr
case CPTK_IS_REFERENCE:
return type_code1 == REFERENCE_TYPE;
+ case CPTK_IS_REPLACEABLE:
+ return replaceable_type_p (type1);
+
case CPTK_IS_SAME:
return same_type_p (type1, type2);
@@ -13570,6 +13600,9 @@ trait_expr_value (cp_trait_kind kind, tr
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
return is_trivially_xible (BIT_NOT_EXPR, type1, NULL_TREE);
+ case CPTK_IS_TRIVIALLY_RELOCATABLE:
+ return trivially_relocatable_type_p (type1);
+
case CPTK_IS_UNBOUNDED_ARRAY:
return array_of_unknown_bound_p (type1);
@@ -13698,18 +13731,6 @@ same_type_ref_bind_p (cp_trait_kind kind
(non_reference (to), non_reference (from))));
}
-/* [defns.referenceable] True iff TYPE is a referenceable type. */
-
-static bool
-referenceable_type_p (const_tree type)
-{
- return (TYPE_REF_P (type)
- || object_type_p (type)
- || (FUNC_OR_METHOD_TYPE_P (type)
- && (type_memfn_quals (type) == TYPE_UNQUALIFIED
- && type_memfn_rqual (type) == REF_QUAL_NONE)));
-}
-
/* Process a trait expression. */
tree
@@ -13752,8 +13773,11 @@ finish_trait_expr (location_t loc, cp_tr
case CPTK_IS_LITERAL_TYPE:
case CPTK_IS_POD:
case CPTK_IS_STD_LAYOUT:
+ case CPTK_IS_REPLACEABLE:
+ case CPTK_IS_NOTHROW_RELOCATABLE:
case CPTK_IS_TRIVIAL:
case CPTK_IS_TRIVIALLY_COPYABLE:
+ case CPTK_IS_TRIVIALLY_RELOCATABLE:
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
if (!check_trait_type (type1, /* kind = */ 2))
return error_mark_node;
--- gcc/cp/tree.cc.jj 2025-06-12 09:48:51.224291891 +0200
+++ gcc/cp/tree.cc 2025-06-16 12:46:48.217705455 +0200
@@ -4715,6 +4715,292 @@ trivial_type_p (const_tree t)
return scalarish_type_p (t);
}
+/* Returns 1 iff type T is a default-movable type, as defined in
+ [class.prop]. */
Missing blank line
+static bool
+default_movable_type_p (tree t)
+{
+ if (!CLASS_TYPE_P (t) || !COMPLETE_TYPE_P (t))
+ return false;
+ if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+ lazily_declare_fn (sfk_destructor, t);
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (user_provided_p (dtor) || DECL_DELETED_FN (dtor))
+ return false;
+
+ tree copy_ctor = NULL_TREE, move_ctor = NULL_TREE;
+ tree copy_assign = NULL_TREE, move_assign = NULL_TREE;
+ if (CLASSTYPE_LAZY_MOVE_CTOR (t))
+ move_ctor = lazily_declare_fn (sfk_move_constructor, t);
+ if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+ move_assign = lazily_declare_fn (sfk_move_assignment, t);
+ if (!move_ctor)
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_ctor = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_ctor = *iter;
+ break;
+ }
+ }
+ if (!move_assign)
+ for (ovl_iterator iter (get_class_binding_direct (t,
+ assign_op_identifier));
+ iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_assign = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_assign = *iter;
+ break;
+ }
+ }
+ if (!move_ctor)
+ {
+ if (CLASSTYPE_LAZY_COPY_CTOR (t))
+ copy_ctor = lazily_declare_fn (sfk_copy_constructor, t);
+ if (!copy_ctor)
+ return false;
+ if (user_provided_p (copy_ctor)
+ || DECL_DELETED_FN (copy_ctor)
+ || DECL_CONTEXT (copy_ctor) != t
+ || DECL_INHERITED_CTOR (copy_ctor))
+ return false;
+ }
+ else if (user_provided_p (move_ctor)
+ || DECL_DELETED_FN (move_ctor)
+ || DECL_CONTEXT (move_ctor) != t
+ || DECL_INHERITED_CTOR (move_ctor))
+ return false;
+ if (!move_assign)
+ {
+ if (CLASSTYPE_LAZY_COPY_ASSIGN (t))
+ copy_assign = lazily_declare_fn (sfk_copy_assignment, t);
+ if (!copy_assign)
+ return false;
+ if (user_provided_p (copy_assign)
+ || DECL_DELETED_FN (copy_assign)
+ || DECL_CONTEXT (copy_assign) != t)
+ return false;
+ }
+ else if (user_provided_p (move_assign)
+ || DECL_DELETED_FN (move_assign)
+ || DECL_CONTEXT (move_assign) != t)
+ return false;
+ return true;
+}
+
+/* Returns 1 iff type T is a union with no user declared special member
+ functions. */
+
+static bool
+union_with_no_declared_special_member_fns (tree t)
+{
+ if (TREE_CODE (t) != UNION_TYPE)
+ return false;
+
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL
+ && !DECL_ARTIFICIAL (*iter)
+ && (default_ctor_p (*iter) || copy_fn_p (*iter) || move_fn_p (*iter)))
+ return false;
+
+ for (ovl_iterator iter (get_class_binding_direct (t, assign_op_identifier));
+ iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL
+ && !DECL_ARTIFICIAL (*iter)
+ && (copy_fn_p (*iter) || move_fn_p (*iter)))
+ return false;
+
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (!DECL_ARTIFICIAL (dtor))
+ return false;
+
+ return true;
+}
+
+/* Returns 1 iff type T is a trivially relocatable type, as defined in
+ [basic.types.general] and [class.prop]. */
+
+bool
+trivially_relocatable_type_p (tree t)
+{
+ t = strip_array_types (t);
+
+ if (!CLASS_TYPE_P (t))
+ return scalarish_type_p (t);
+
+ t = TYPE_MAIN_VARIANT (t);
+ if (CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t))
+ return CLASSTYPE_TRIVIALLY_RELOCATABLE (t);
+ if (!COMPLETE_TYPE_P (t))
+ return false;
+
+ if (!CLASSTYPE_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE (t)
+ && !union_with_no_declared_special_member_fns (t)
+ && !default_movable_type_p (t))
+ {
+ nontriv:
+ CLASSTYPE_TRIVIALLY_RELOCATABLE (t) = 0;
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1;
+ return false;
+ }
+
+ if (CLASSTYPE_VBASECLASSES (t))
+ goto nontriv;
+
+ if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+ lazily_declare_fn (sfk_destructor, t);
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (DECL_DELETED_FN (dtor))
+ goto nontriv;
+
+ tree binfo, base_binfo;
+ unsigned int i;
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ if (!trivially_relocatable_type_p (basetype))
+ goto nontriv;
+ }
+
+ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && !DECL_ARTIFICIAL (field)
+ && !DECL_UNNAMED_BIT_FIELD (field))
+ {
+ tree type = TREE_TYPE (field);
+ if (type == error_mark_node)
+ goto nontriv;
+ if (!TYPE_REF_P (type) && !trivially_relocatable_type_p (type))
+ goto nontriv;
+ }
+
+ CLASSTYPE_TRIVIALLY_RELOCATABLE (t) = 1;
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1;
+ return true;
+}
+
+/* Returns 1 iff type T is a replaceable type, as defined in [basic.types]
+ and [class]. */
+
+bool
+replaceable_type_p (tree t)
+{
+ t = strip_array_types (t);
+
+ if (cv_qualified_p (t))
+ return false;
+
+ if (!CLASS_TYPE_P (t))
+ return scalarish_type_p (t);
+
+ t = TYPE_MAIN_VARIANT (t);
+ if (CLASSTYPE_REPLACEABLE_COMPUTED (t))
+ return CLASSTYPE_REPLACEABLE (t);
+ if (!COMPLETE_TYPE_P (t))
+ return false;
+
+ if (!CLASSTYPE_REPLACEABLE_IF_ELIGIBLE (t)
+ && !union_with_no_declared_special_member_fns (t)
+ && !default_movable_type_p (t))
+ {
+ nonrepl:
+ CLASSTYPE_REPLACEABLE (t) = 0;
+ CLASSTYPE_REPLACEABLE_COMPUTED (t) = 1;
+ return false;
+ }
+
+ if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+ lazily_declare_fn (sfk_destructor, t);
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (DECL_DELETED_FN (dtor))
+ goto nonrepl;
+
+ tree copy_ctor = NULL_TREE, move_ctor = NULL_TREE;
+ tree copy_assign = NULL_TREE, move_assign = NULL_TREE;
+ if (CLASSTYPE_LAZY_MOVE_CTOR (t))
+ move_ctor = lazily_declare_fn (sfk_move_constructor, t);
+ if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+ move_assign = lazily_declare_fn (sfk_move_assignment, t);
+ if (!move_ctor)
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_ctor = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_ctor = *iter;
+ break;
+ }
+ }
+ if (!move_assign)
+ for (ovl_iterator iter (get_class_binding_direct (t,
+ assign_op_identifier));
+ iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_assign = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_assign = *iter;
+ break;
+ }
+ }
+ if (!move_ctor)
+ {
+ if (CLASSTYPE_LAZY_COPY_CTOR (t))
+ copy_ctor = lazily_declare_fn (sfk_copy_constructor, t);
+ if (!copy_ctor || DECL_DELETED_FN (copy_ctor))
+ goto nonrepl;
+ }
+ else if (DECL_DELETED_FN (move_ctor))
+ goto nonrepl;
+ if (!move_assign)
+ {
+ if (CLASSTYPE_LAZY_COPY_ASSIGN (t))
+ copy_assign = lazily_declare_fn (sfk_copy_assignment, t);
+ if (!copy_assign || DECL_DELETED_FN (copy_assign))
+ goto nonrepl;
+ }
+ else if (DECL_DELETED_FN (move_assign))
+ goto nonrepl;
+
+ tree binfo, base_binfo;
+ unsigned int i;
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ if (!replaceable_type_p (basetype))
+ goto nonrepl;
+ }
+
+ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && !DECL_ARTIFICIAL (field)
+ && !DECL_UNNAMED_BIT_FIELD (field))
+ {
+ tree type = TREE_TYPE (field);
+ if (type == error_mark_node)
+ goto nonrepl;
+ if (!replaceable_type_p (type))
+ goto nonrepl;
+ }
+
+ CLASSTYPE_REPLACEABLE (t) = 1;
+ CLASSTYPE_REPLACEABLE_COMPUTED (t) = 1;
+ return true;
+}
+
/* Returns 1 iff type T is a POD type, as defined in [basic.types]. */
bool
--- gcc/cp/constraint.cc.jj 2025-06-12 09:48:50.611300032 +0200
+++ gcc/cp/constraint.cc 2025-06-13 14:50:24.425529297 +0200
@@ -3157,6 +3157,9 @@ diagnose_trait_expr (tree expr, tree arg
else
inform (loc, " %qT is not nothrow invocable by %qE", t1, t2);
break;
+ case CPTK_IS_NOTHROW_RELOCATABLE:
+ inform (loc, " %qT is not nothrow relocatable", t1);
+ break;
case CPTK_IS_OBJECT:
inform (loc, " %qT is not an object type", t1);
break;
@@ -3176,6 +3179,9 @@ diagnose_trait_expr (tree expr, tree arg
case CPTK_IS_REFERENCE:
inform (loc, " %qT is not a reference", t1);
break;
+ case CPTK_IS_REPLACEABLE:
+ inform (loc, " %qT is not replaceable", t1);
+ break;
case CPTK_IS_SAME:
inform (loc, " %qT is not the same as %qT", t1, t2);
break;
@@ -3203,6 +3209,9 @@ diagnose_trait_expr (tree expr, tree arg
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
inform (loc, " %qT is not trivially destructible", t1);
break;
+ case CPTK_IS_TRIVIALLY_RELOCATABLE:
+ inform (loc, " %qT is not trivially relocatable", t1);
+ break;
case CPTK_IS_UNBOUNDED_ARRAY:
inform (loc, " %qT is not an unbounded array", t1);
break;
--- gcc/doc/invoke.texi.jj 2025-06-12 09:48:51.308290776 +0200
+++ gcc/doc/invoke.texi 2025-06-13 14:50:24.972522213 +0200
@@ -353,7 +353,7 @@ Objective-C and Objective-C++ Dialects}.
-Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat
-Wc11-c23-compat -Wc23-c2y-compat
-Wc++-compat -Wc++11-compat -Wc++14-compat -Wc++17-compat
--Wc++20-compat
+-Wc++20-compat -Wc++26-compat
-Wno-c++11-extensions -Wno-c++14-extensions -Wno-c++17-extensions
-Wno-c++20-extensions -Wno-c++23-extensions
-Wcalloc-transposed-args
@@ -9625,6 +9625,12 @@ and ISO C++ 2017. This warning is enabl
Warn about C++ constructs whose meaning differs between ISO C++ 2017
and ISO C++ 2020. This warning is enabled by @option{-Wall}.
+@opindex Wc++26-compat
+@opindex Wno-c++26-compat
+@item -Wc++26-compat @r{(C++ and Objective-C++ only)}
+Warn about C++ constructs whose meaning differs between ISO C++ 2023
+and upcoming ISO C++ 2026. This warning is enabled by @option{-Wall}.
+
@opindex Wc++11-extensions
@opindex Wno-c++11-extensions
@item -Wno-c++11-extensions @r{(C++ and Objective-C++ only)}
--- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj 2025-06-16 22:08:21.453134624
+0200
+++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2025-06-16 22:09:51.920950882
+0200
@@ -634,3 +634,9 @@
#elif __cpp_pp_embed != 202502
# error "__cpp_pp_embed != 202502"
#endif
+
+#ifndef __cpp_trivial_relocatability
+# error "__cpp_trivial_relocatability"
+#elif __cpp_trivial_relocatability != 202502
+# error "__cpp_trivial_relocatability != 202502"
+#endif
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable1.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable1.C 2025-06-16
22:09:51.920950882 +0200
@@ -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.
Agreed. The example in the paper even calls this class "Immobile".
+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.
This makes sense to me.
+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.
Agreed.
+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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable2.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable2.C 2025-06-16
22:09:51.920950882 +0200
@@ -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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable3.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable3.C 2025-06-16
22:09:51.920950882 +0200
@@ -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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable4.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable4.C 2025-06-16
22:09:51.920950882 +0200
@@ -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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable5.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable5.C 2025-06-16
22:09:51.920950882 +0200
@@ -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
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable6.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable6.C 2025-06-16
22:09:51.920950882 +0200
@@ -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" }
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable7.C.jj 2025-06-16
22:09:51.920950882 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable7.C 2025-06-17
08:04:56.544168746 +0200
@@ -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" }
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable8.C.jj 2025-06-16
22:09:51.939950633 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable8.C 2025-06-17
08:10:05.101063421 +0200
@@ -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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable9.C.jj 2025-06-16
22:09:51.940950620 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable9.C 2025-06-17
08:18:26.788388486 +0200
@@ -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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable10.C.jj 2025-06-16
22:09:51.940950620 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable10.C 2025-06-16
22:09:51.940950620 +0200
@@ -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>, "");
--- gcc/testsuite/g++.dg/cpp26/trivially-relocatable11.C.jj 2025-06-16
22:09:51.940950620 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivially-relocatable11.C 2025-06-16
22:09:51.940950620 +0200
@@ -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>, "");
Jakub