diff --git a/source/basic.tex b/source/basic.tex index 152a9eff7f..88ff114cc7 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -5030,6 +5030,14 @@ Scalar types, trivially copyable class types\iref{class.prop}, arrays of such types, and cv-qualified versions of these types are collectively called \defnadjx{trivially copyable}{types}{type}. +\label{term.trivially.relocatable.type}% +Scalar types, trivially relocatable class types\iref{class.prop}, +arrays of such types, and cv-qualified versions of these +types are collectively called \defnadjx{trivially relocatable}{types}{type}. +\label{term.replaceable.type}% +Cv-unqualified scalar types, replaceable class types\iref{class.prop}, and +arrays of such types are collectively called +\defnadjx{replaceable}{types}{type}. \label{term.standard.layout.type}% Scalar types, standard-layout class types\iref{class.prop}, arrays of such types, and diff --git a/source/classes.tex b/source/classes.tex index a92d46955d..fec5f06b0d 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -36,7 +36,7 @@ \begin{bnf} \nontermdef{class-head}\br - class-key \opt{attribute-specifier-seq} class-head-name \opt{class-virt-specifier} \opt{base-clause}\br + class-key \opt{attribute-specifier-seq} class-head-name \opt{class-property-specifier-seq} \opt{base-clause}\br class-key \opt{attribute-specifier-seq} \opt{base-clause} \end{bnf} @@ -46,8 +46,15 @@ \end{bnf} \begin{bnf} -\nontermdef{class-virt-specifier}\br - \keyword{final} +\nontermdef{class-property-specifier-seq}\br + class-property-specifier \opt{class-property-specifier-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{class-property-specifier}\br + \keyword{final}\br + \keyword{trivially_relocatable_if_eligible}\br + \keyword{replaceable_if_eligible} \end{bnf} \begin{bnf} @@ -120,12 +127,13 @@ \end{note} \pnum -If a class is marked with the \grammarterm{class-virt-specifier} \tcode{final} and it appears -as a \grammarterm{class-or-decltype} in a \grammarterm{base-clause}\iref{class.derived}, -the program is ill-formed. Whenever a -\grammarterm{class-key} is followed by a \grammarterm{class-head-name}, the -\grammarterm{identifier} \tcode{final}, and a colon or left brace, \tcode{final} is -interpreted as a \grammarterm{class-virt-specifier}. +Each \grammarterm{class-property-specifier} shall appear at most once +withina single \grammarterm{class-property-specifier-seq}. +Whenever a \grammarterm{class-key} is followed +by a \grammarterm{class-head-name}, +the identifier \tcode{final}, \tcode{trivially_relocatable_if_eligible}, +or \tcode{replaceable_if_eligible}, and a colon or left brace, +the identifier is interpreted as a \grammarterm{class-property-specifier}. \begin{example} \begin{codeblock} struct A; @@ -134,12 +142,19 @@ struct X { struct C { constexpr operator int() { return 5; } }; - struct B final : C{}; // OK, definition of nested class \tcode{B}, - // not declaration of a bit-field member \tcode{final} + struct B trivially_relocatable_if_eligible : C{}; + // OK, definition of nested class \tcode{B}, + // not declaration of a bit-field member + // \tcode{trivially_relocatable_if_eligible} }; \end{codeblock} \end{example} +\pnum +If a class is marked with the \grammarterm{class-property-specifier} +\tcode{final} and that class appears as a \grammarterm{class-or-decltype} +in a \grammarterm{base-clause}\iref{class.derived}, the program is ill-formed. + \pnum \begin{note} Complete objects of class type have nonzero size. @@ -172,6 +187,87 @@ \item that has a trivial, non-deleted destructor\iref{class.dtor}. \end{itemize} +\pnum +A class \tcode{C} is \defn{default-movable} if + +\begin{itemize} +\item overload resolution for direct-initializing an object of type \tcode{C} +from an xvalue of type \tcode{C} selects a constructor that is a direct member +of \tcode{C} and is neither user-provided nor deleted, + +\item overload resolution for assigning to an lvalue of type \tcode{C} from an +xvalue of type \tcode{C} selects an assignment operator function that is a +direct member of \tcode{C} and is neither user-provided nor deleted, and + +\item \tcode{C} has a destructor that is neither user-provided nor deleted. +\end{itemize} + +\pnum +A class is \defn{eligible for trivial relocation} unless it +\begin{itemize} +\item has any virtual base classes, +\item has a base class that is not a trivially relocatable class, +\item has a non-static data member of an object type that is not of a +trivially relocatable type, or + +\item has a deleted destructor, +\end{itemize} +except that it is \impldef{whether an otherwise-eligible union having one or +more subobjects of polymorphic class type is eligible for trivial relocation} +whether an otherwise-eligible union having one or more subobjects of +polymorphic class type is eligible for trivial relocation. + +\pnum +A class \tcode{C} is a \defnadj{trivially relocatable}{class} +if it is eligible for trivial relocation and +\begin{itemize} +\item has the \tcode{trivially_relocatable_if_eligible} \grammarterm{class-property-specifier}, +\item is a union with no user-declared special member functions, or +\item is default-movable. +\end{itemize} + +\pnum +\begin{note} +A class with const-qualified or reference non-static data members can be +trivially relocatable. +\end{note} + +\pnum +A class \tcode{C} is \defn{eligible for replacement} unless +\begin{itemize} +\item it has a base class that is not a replaceable class, +\item it has a non-static data member that is not of a replaceable type, +\item overload resolution fails or selects a deleted constructor when +direct-initializing an object of type \tcode{C} from an xvalue of type +\tcode{C}\iref{dcl.init.general}, + +\item overload resolution fails or selects a deleted assignment operator +function when assigning to an lvalue of type \tcode{C} from an xvalue of type +\tcode{C} \iref{expr.assign,over.assign}), or + +\item it has a deleted destructor. +\end{itemize} + +\pnum +A class \tcode{C} is a \defnadj{replaceable}{class} if it is +eligible for replacement and +\begin{itemize} +\item has the \tcode{replaceable_if_eligible} \grammarterm{class-property-specifier}, +\item is a union with no user-declared special member functions, or +\item is default-movable. +\end{itemize} + +\pnum +\begin{note} +Accessibility of the special member functions is not considered when +establishing trivial relocatability or replaceability. +\end{note} + +\pnum +\begin{note} +Not all trivially copyable classes are trivially relocatable or replaceable. +\end{note} + \pnum A class \tcode{S} is a \defnadj{standard-layout}{class} if it: \begin{itemize} diff --git a/source/compatibility.tex b/source/compatibility.tex index cbfd3eadd0..181b6744f0 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -91,6 +91,22 @@ \rSec2[diff.cpp23.dcl.dcl]{\ref{dcl}: declarations} +\diffref{dcl.decl.general} +\change +Introduction of \tcode{trivially_relocatable_if_eligible} and +\tcode{replaceable_if_eligible} as identifiers with special meaning\iref{lex.name}. +\rationale +Support declaration of trivially relocatable and replaceable types\iref{class.prop}. +\effect +Valid \CppXXIII{} code can become ill-formed. +\begin{example} +\begin{codeblock} +struct C {}; +struct C replaceable_if_eligible {}; // was well-formed (new variable \tcode{replaceable_if_eligible}) + // now ill-formed (redefines \tcode{C}) +\end{codeblock} +\end{example} + \diffref{dcl.init.list} \change Pointer comparisons between \tcode{initializer_list} objects' backing arrays @@ -212,6 +228,17 @@ Valid \CppXXIII{} code that \tcode{\#include}{s} headers with these names may be invalid in this revision of \Cpp{}. +\diffref{res.on.macro.definitions} +\change +Additional restrictions on macro names. +\rationale +Avoid hard to diagnose or non-portable constructs. +\effect +Names of special identifiers may not be used as macro names. +Valid \CppXXIII{} code that defines \tcode{replaceable_if_eligible} or +\tcode{trivially_relocatable_if_eligible} as macros is invalid +in this revision of \Cpp{}. + \rSec2[diff.cpp23.strings]{\ref{strings}: strings library} \diffref{string.conversions} diff --git a/source/expressions.tex b/source/expressions.tex index faeec73322..5867bea5d1 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -2157,9 +2157,9 @@ other than by changing: \begin{itemize} \item the size and/or alignment of the closure type, - -\item whether the closure type is trivially copyable\iref{class.prop}, or - +\item whether the closure type is trivially copyable\iref{class.prop}, +\item whether the closure type is trivially relocatable\iref{class.prop}, +\item whether the closure type is replaceable\iref{class.prop}, or \item whether the closure type is a standard-layout class\iref{class.prop}. \end{itemize} diff --git a/source/lex.tex b/source/lex.tex index 9642c4badc..1841a202f7 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -907,6 +907,8 @@ \indextext{\idxcode{final}}% \indextext{\idxcode{module}}% \indextext{\idxcode{override}}% +\indextext{\idxcode{replaceable_if_eligible}}% +\indextext{\idxcode{trivially_relocatable_if_eligible}}% The identifiers in \tref{lex.name.special} have a special meaning when appearing in a certain context. When referred to in the grammar, these identifiers are used explicitly rather than using the \grammarterm{identifier} grammar production. @@ -915,18 +917,15 @@ token as a regular \grammarterm{identifier}. \begin{multicolfloattable}{Identifiers with special meaning}{lex.name.special} -{llllll} -\keyword{final} \\ -\columnbreak -\keyword{import} \\ -\columnbreak -\keyword{module} \\ -\columnbreak -\keyword{override} \\ -\columnbreak -\keyword{post} \\ -\columnbreak -\keyword{pre} \\ +{llll} +\keyword{final} \\ +\keyword{override} \\\columnbreak +\keyword{import} \\ +\keyword{module} \\\columnbreak +\keyword{post} \\ +\keyword{pre} \\\columnbreak +\keyword{replaceable_if_eligible} \\ +\keyword{trivially_relocatable_if_eligible} \\ \end{multicolfloattable} \pnum diff --git a/source/lib-intro.tex b/source/lib-intro.tex index d0270ea603..8d21e19b18 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -3785,6 +3785,28 @@ side effects. \end{note} +\rSec3[library.class.props]{Properties of library classes} + +\pnum +Unless explicitly stated otherwise, it is unspecified whether any class +described in \ref{\firstlibchapter} through \ref{\lastlibchapter} and +\ref{depr} is a trivially copyable class, a standard-layout class, or an +implicit-lifetime class\iref{class.prop}. + +\pnum +Unless explicitly stated otherwise, it is unspecified whether any class for +which trivial relocation (i.e., the effects of +\tcode{trivially_relocate}\iref{obj.lifetime}) would be semantically equivalent +to move-construction of the destination object followed by destruction of the +source object is a trivially relocatable class\iref{class.prop}. + +\pnum +Unless explicitly stated otherwise, it is unspecified whether a class \tcode{C} +is a replaceable class\iref{class.prop} if assigning an xvalue \tcode{a} of +type \tcode{C} to an object \tcode{b} of type \tcode{C} is semantically +equivalent to destroying \tcode{b} and then constructing from \tcode{a} in +\tcode{b}'s place. + \rSec3[protection.within.classes]{Protection within classes} \pnum diff --git a/source/memory.tex b/source/memory.tex index 70ebe44565..e943cfe6f7 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -104,6 +104,10 @@ template const volatile T* start_lifetime_as_array(const volatile void* p, // freestanding size_t n) noexcept; + template + T* trivially_relocate(T* first, T* last, T* result); // freestanding + template + constexpr T* relocate(T* first, T* last, T* result); // freestanding // \ref{allocator.tag}, allocator argument tag struct allocator_arg_t { explicit allocator_arg_t() = default; }; // freestanding @@ -989,6 +993,128 @@ a pointer that compares equal to \tcode{p}\iref{expr.eq}. \end{itemdescr} +\indexlibraryglobal{trivially_relocate}% +\begin{itemdecl} +template + T* trivially_relocate(T* first, T* last, T* result); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_trivially_relocatable_v \&\& !is_const_v} is \tcode{true}. +\tcode{T} is not an array of unknown bound. + +\pnum +\expects +\begin{itemize} +\item + \range{first}{last} is a valid range. +\item + \range{result}{result + (last - first)} denotes a region of storage that + is a subset of the region reachable through \tcode{result}\iref{basic.compound} + and suitably aligned for the type \tcode{T}. +\item + No element in the range \range{first}{last} is a potentially-overlapping subobject. +\end{itemize} + +\pnum +\ensures +No effect if \tcode{result == first} is \tcode{true}. +Otherwise, the range denoted by \range{result}{result + (last - first)} +contains objects (including subobjects) whose lifetime has begun and whose +object representations are the original object representations of the +corresponding objects in the source range \range{first}{last} except +for any parts of the object representations used by the implementation to +represent type information\iref{intro.object}. If any of the objects has +union type, its active member is the same as that of the corresponding object +in the source range. If any of the aforementioned objects has a non-static +data member of reference type, that reference refers to the same entity as +does the corresponding reference in the source range. The lifetimes of the +original objects in the source range have ended. + +\pnum +\returns +\tcode{result + (last - first)}. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Linear in the length of the source range. + +\pnum +\remarks +The destination region of storage is considered reused\iref{basic.life}. +No constructors or destructors are invoked. + +\begin{note} +Overlapping ranges are supported. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{relocate}% +\begin{itemdecl} +template + constexpr T* relocate(T* first, T* last, T* result); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_nothrow_relocatable_v \&\& !is_const_v} is \tcode{true}. +\tcode{T} is not an array of unknown bound. + +\pnum +\expects +\begin{itemize} +\item + \range{first}{last} is a valid range. +\item + \range{result}{result + (last - first)} denotes a region of storage that is + a subset of the region reachable through \tcode{result}\iref{basic.compound} + and suitably aligned for the type \tcode{T}. +\item + No element in the range \range{first}{last} is a potentially-overlapping + subobject. +\end{itemize} + +\pnum +\effects +\begin{itemize} +\item + If \tcode{result == first} is \tcode{true}, no effect; +\item + otherwise, if not called during constant evaluation and + \tcode{is_trivially_relocatable_v} is \tcode{true}, then has + effects equivalent to: \tcode{trivially_relocate(first, last, result);} +\item + otherwise, for each integer \tcode{i} in \range{0}{last - first}, + \begin{itemize} + \item + if \tcode{T} is an array type, equivalent to: + \tcode{relocate(begin(first[i]), end(first[i]), *start_lifetime_as(result + i));} + \item + otherwise, equivalent to: + \tcode{construct_at(result + i, std::move(first[i])); destroy_at(first + i);} + \end{itemize} +\end{itemize} + +\pnum +\returns +\tcode{result + (last - first)}. + +\pnum +\throws +Nothing. + +\begin{note} +Overlapping ranges are supported. +\end{note} +\end{itemdescr} + \rSec2[allocator.tag]{Allocator argument tag} \indexlibraryglobal{allocator_arg_t}% diff --git a/source/meta.tex b/source/meta.tex index 0b9139aa47..61fa4ca259 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -193,6 +193,8 @@ template struct is_const; template struct is_volatile; template struct is_trivially_copyable; + template struct is_trivially_relocatable; + template struct is_replaceable; template struct is_standard_layout; template struct is_empty; template struct is_polymorphic; @@ -243,6 +245,7 @@ template struct is_nothrow_swappable; template struct is_nothrow_destructible; + template struct is_nothrow_relocatable; template struct is_implicit_lifetime; @@ -431,6 +434,8 @@ constexpr bool @\libglobal{is_volatile_v}@ = is_volatile::value; template constexpr bool @\libglobal{is_trivially_copyable_v}@ = is_trivially_copyable::value; + template + constexpr bool @\libglobal{is_trivially_relocatable_v}@ = is_trivially_relocatable::value; template constexpr bool @\libglobal{is_standard_layout_v}@ = is_standard_layout::value; template @@ -519,8 +524,12 @@ constexpr bool @\libglobal{is_nothrow_swappable_v}@ = is_nothrow_swappable::value; template constexpr bool @\libglobal{is_nothrow_destructible_v}@ = is_nothrow_destructible::value; + template + constexpr bool @\libglobal{is_nothrow_relocatable_v}@ = is_nothrow_relocatable::value; template constexpr bool @\libglobal{is_implicit_lifetime_v}@ = is_implicit_lifetime::value; + template + constexpr bool @\libglobal{is_replaceable_v}@ = is_replaceable::value; template constexpr bool @\libglobal{has_virtual_destructor_v}@ = has_virtual_destructor::value; template @@ -836,6 +845,20 @@ \tcode{remove_all_extents_t} shall be a complete type or \cv{}~\keyword{void}. \\ \rowsep +\indexlibraryglobal{is_trivially_relocatable}% +\tcode{template}\br + \tcode{struct is_trivially_relocatable;} & + \tcode{T} is a trivially relocatable type\iref{basic.types.general} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}, \\ \rowsep + +\indexlibraryglobal{is_replaceable}% +\tcode{template}\br + \tcode{struct is_replaceable;} & + \tcode{T} is a replaceable type\iref{basic.types.general} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}, \\ \rowsep + \indexlibraryglobal{is_standard_layout}% \tcode{template}\br \tcode{struct is_standard_layout;} & @@ -867,7 +890,7 @@ \indexlibraryglobal{is_final}% \tcode{template}\br \tcode{struct is_final;} & - \tcode{T} is a class type marked with the \grammarterm{class-virt-specifier} + \tcode{T} is a class type marked with the \grammarterm{class-property-specifier} \tcode{final}\iref{class.pre}. \begin{tailnote} A union is a class type that @@ -1198,6 +1221,16 @@ \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep +\indexlibraryglobal{is_nothrow_relocatable}% +\tcode{template}\br + \tcode{struct is_nothrow_relocatable;} & + \tcode{is_trivially_relocatable_v ||} + \tcode{(is_nothrow_move_constructible_v<} + \tcode{remove_all_extents_t> \&\& is_nothrow_destructible_v<} + \tcode{remove_all_extents_t>)} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}, \\ \rowsep + \indexlibraryglobal{is_implicit_lifetime}% \tcode{template}\br \tcode{struct is_implicit_lifetime;} & diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 53829ff929..4bf6f4f54d 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -1909,6 +1909,7 @@ \defnxname{cpp_template_parameters} & \tcode{202502L} \\ \rowsep \defnxname{cpp_template_template_args} & \tcode{201611L} \\ \rowsep \defnxname{cpp_threadsafe_static_init} & \tcode{200806L} \\ \rowsep +\defnxname{cpp_trivial_relocatability} & \tcode{202502L} \\ \rowsep \defnxname{cpp_trivial_union} & \tcode{202502L} \\ \rowsep \defnxname{cpp_unicode_characters} & \tcode{200704L} \\ \rowsep \defnxname{cpp_unicode_literals} & \tcode{200710L} \\ \rowsep diff --git a/source/support.tex b/source/support.tex index d11a1c0d45..622b70c9f5 100644 --- a/source/support.tex +++ b/source/support.tex @@ -815,6 +815,8 @@ #define @\defnlibxname{cpp_lib_transformation_trait_aliases}@ 201304L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_transparent_operators}@ 201510L // freestanding, also in \libheader{memory}, \libheader{functional} +#define @\defnlibxname{cpp_lib_trivially_relocatable}@ 202502L + // freestanding, also in \libheader{memory}, \libheader{type_traits} #define @\defnlibxname{cpp_lib_tuple_element_t}@ 201402L // freestanding, also in \libheader{tuple} #define @\defnlibxname{cpp_lib_tuple_like}@ 202311L // also in \libheader{utility}, \libheader{tuple}, \libheader{map}, \libheader{unordered_map}