diff --git a/source/algorithms.tex b/source/algorithms.tex index 6f0001c5ca..0c5d2b5cb6 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -2316,16 +2316,6 @@ template<@\libconcept{input_or_output_iterator}@ O, @\libconcept{copy_constructible}@ F> requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> constexpr O generate_n(O first, iter_difference_t n, F gen); - template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ S, - @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O generate(Ep&& exec, O first, S last, F gen); // freestanding-deleted - template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@, invoke_result_t> - borrowed_iterator_t generate(Ep&& exec, R&& r, F gen); // freestanding-deleted - template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O generate_n(Ep&& exec, O first, iter_difference_t n, F gen); // freestanding-deleted } // \ref{alg.remove}, remove @@ -2857,12 +2847,12 @@ class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@ I stable_sort(Ep&& exec, I first, S last, Comp comp = {}, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@, Comp, Proj> borrowed_iterator_t - stable_sort(Ep&& exec, R&& r, Comp comp = {}, Proj proj = {}); // freestanding-deleted + stable_sort(Ep&& exec, R&& r, Comp comp = {}, Proj proj = {}); // hosted } template @@ -3261,12 +3251,12 @@ requires @\libconcept{permutable}@ subrange stable_partition(Ep&& exec, I first, S last, Pred pred, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{permutable}@> borrowed_subrange_t - stable_partition(Ep&& exec, R&& r, Pred pred, Proj proj = {}); // freestanding-deleted + stable_partition(Ep&& exec, R&& r, Pred pred, Proj proj = {}); // hosted } template requires @\libconcept{sortable}@ I inplace_merge(Ep&& exec, I first, I middle, S last, Comp comp = {}, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@, Comp, Proj> borrowed_iterator_t inplace_merge(Ep&& exec, R&& r, iterator_t middle, Comp comp = {}, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted } // \ref{alg.set.operations}, set operations @@ -7005,9 +6995,9 @@ ranges::transform(Ep&& exec, I first1, S last1, O result, OutS result_last, F op, Proj proj = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, @\exposconcept{sized-random-access-range}@ OutR, - @\libconcept{copy_constructible}@ F, class Proj = identity> + @\libconcept{copy_constructible}@ F, class Proj = identity> requires @\libconcept{indirectly_writable}@, - indirect_result_t, Proj>>> + indirect_result_t, Proj>>> ranges::unary_transform_result, borrowed_iterator_t> ranges::transform(Ep&& exec, R&& r, OutR&& result_r, F op, Proj proj = {}); @@ -7032,17 +7022,17 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, @\libconcept{copy_constructible}@ F, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, - projected>> + projected>> ranges::binary_transform_result ranges::transform(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R1, @\exposconcept{sized-random-access-range}@ R2, @\exposconcept{sized-random-access-range}@ OutR, @\libconcept{copy_constructible}@ F, - class Proj1 = identity, class Proj2 = identity> + class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, - indirect_result_t, Proj1>, - projected, Proj2>>> + indirect_result_t, Proj1>, + projected, Proj2>>> ranges::binary_transform_result, borrowed_iterator_t, borrowed_iterator_t> ranges::transform(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, @@ -7178,8 +7168,8 @@ template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Proj = identity, class T1 = projected_value_t, Proj>, class T2 = range_value_t> requires @\libconcept{indirectly_writable}@, const T2&> && - @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> + @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> borrowed_iterator_t ranges::replace(Ep&& exec, R&& r, const T1& old_value, const T2& new_value, Proj proj = {}); @@ -7299,7 +7289,7 @@ class T2 = range_value_t> requires @\libconcept{indirectly_copyable}@, iterator_t> && @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> && + projected, Proj>, const T1*> && @\libconcept{indirectly_writable}@, const T2&> ranges::replace_copy_result, borrowed_iterator_t> ranges::replace_copy(Ep&& exec, R&& r, OutR&& result_r, const T1& old_value, @@ -7492,17 +7482,6 @@ template<@\libconcept{input_or_output_iterator}@ O, @\libconcept{copy_constructible}@ F> requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> constexpr O ranges::generate_n(O first, iter_difference_t n, F gen); - -template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ S, - @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O ranges::generate(Ep&& exec, O first, S last, F gen); -template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@, invoke_result_t> - borrowed_iterator_t ranges::generate(Ep&& exec, R&& r, F gen); -template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O ranges::generate_n(Ep&& exec, O first, iter_difference_t n, F gen); \end{itemdecl} \begin{itemdescr} @@ -7577,7 +7556,7 @@ class T = projected_value_t, Proj>> requires @\libconcept{permutable}@> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + projected, Proj>, const T*> borrowed_subrange_t ranges::remove(Ep&& exec, R&& r, const T& value, Proj proj = {}); @@ -7604,7 +7583,7 @@ \begin{itemdescr} \pnum -Let $E$ be +Let $E(\tcode{i})$ be \begin{itemize} \item \tcode{bool(*i == value)} for \tcode{remove}; \item \tcode{bool(pred(*i))} for \tcode{remove_if}; @@ -7621,7 +7600,7 @@ \pnum \effects Eliminates all the elements referred to by iterator \tcode{i} -in the range \range{first}{last} for which $E$ holds. +in the range \range{first}{last} for which $E(\tcode{i})$ holds. \pnum \returns @@ -7701,7 +7680,7 @@ class Proj = identity, class T = projected_value_t, Proj>> requires @\libconcept{indirectly_copyable}@, iterator_t> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + projected, Proj>, const T*> ranges::remove_copy_result, borrowed_iterator_t> ranges::remove_copy(Ep&& exec, R&& r, OutR&& result_r, const T& value, Proj proj = {}); @@ -9076,7 +9055,7 @@ @\libconcept{random_access_iterator}@ I2, @\libconcept{sized_sentinel_for}@ S2, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_copyable}@ && @\libconcept{sortable}@ && - @\libconcept{indirect_strict_weak_order}@, projected> + @\libconcept{indirect_strict_weak_order}@, projected> ranges::partial_sort_copy_result ranges::partial_sort_copy(Ep&& exec, I1 first, S1 last, I2 result_first, S2 result_last, Comp comp = {}, Proj1 proj1 = {}, @@ -9281,7 +9260,7 @@ class Proj = identity, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> I ranges::is_sorted_until(Ep&& exec, I first, S last, Comp comp = {}, - Proj proj = {}); + Proj proj = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Proj = identity, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> borrowed_iterator_t @@ -9892,7 +9871,7 @@ class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{indirectly_copyable}@, iterator_t> && - @\libconcept{indirectly_copyable}@, iterator_t> + @\libconcept{indirectly_copyable}@, iterator_t> ranges::partition_copy_result, borrowed_iterator_t, borrowed_iterator_t> ranges::partition_copy(Ep&& exec, R&& r, OutR1&& out_true_r, OutR2&& out_false_r, @@ -10340,7 +10319,7 @@ template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R1, @\exposconcept{sized-random-access-range}@ R2, class Proj1 = identity, class Proj2 = identity, @\libconcept{indirect_strict_weak_order}@, Proj1>, - projected, Proj2>> Comp = ranges::less> + projected, Proj2>> Comp = ranges::less> bool ranges::includes(Ep&& exec, R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -13510,7 +13489,7 @@ \remarks A function call expression that violates the precondition in the \Fundescx{Preconditions} element -is not a core constant expression\iref{expr.const}. +is not a core constant expression\iref{expr.const.core}. \end{itemdescr} \rSec3[numeric.sat.cast]{Casting} diff --git a/source/back.tex b/source/back.tex index da31760918..03939906da 100644 --- a/source/back.tex +++ b/source/back.tex @@ -7,10 +7,6 @@ \bibitem{iso4217} ISO 4217:2015, \doccite{Codes for the representation of currencies} -\bibitem{iso10967-1} - ISO/IEC 10967-1:2012, - \doccite{Information technology --- Language independent arithmetic --- - Part 1: Integer and floating point arithmetic} \bibitem{iso14882:2023} ISO/IEC 14882:2023, \doccite{Programming Languages --- \Cpp{}} diff --git a/source/basic.tex b/source/basic.tex index 266580c8bc..3ec230de1e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -32,10 +32,26 @@ \end{note} \pnum -A \defn{name} is an \grammarterm{identifier}\iref{lex.name}, -\grammarterm{conversion-function-id}\iref{class.conv.fct}, -\grammarterm{operator-function-id}\iref{over.oper}, or -\grammarterm{literal-operator-id}\iref{over.literal}. +A \defn{name} is +\begin{itemize} +\item an \grammarterm{identifier} token\iref{lex.token, lex.name} other than + \begin{itemize} + \item + the \grammarterm{identifier} of a + \grammarterm{label}\iref{stmt.label} or + \grammarterm{literal-operator-id}\iref{over.literal}, + \item + the \grammarterm{identifier} following a \keyword{goto} in a + \grammarterm{jump-statement}\iref{stmt.jump.general}, + \item + any \grammarterm{identifier} in a + \grammarterm{module-name}\iref{module.unit} or + \grammarterm{attribute-token}\iref{dcl.attr.grammar}, or + \end{itemize} +\item a \grammarterm{conversion-function-id}\iref{class.conv.fct}, +\item an \grammarterm{operator-function-id}\iref{over.oper}, or +\item a \grammarterm{literal-operator-id}\iref{over.literal}. +\end{itemize} \pnum Two names are \defnx{the same}{name!same} if @@ -115,13 +131,15 @@ \pnum A \defn{variable} is introduced by the -declaration of +declaration $D$ of \begin{itemize} \item a reference other than a non-static data member or \item -an object. +an object, \end{itemize} +where $D$ is not the \grammarterm{parameter-declaration} of +a \grammarterm{template-parameter}. \pnum An \defn{entity} is a @@ -274,7 +292,7 @@ \item it is an explicit instantiation declaration\iref{temp.explicit}, or \item it is -an explicit specialization\iref{temp.expl.spec} whose +an \grammarterm{explicit-specialization}\iref{temp.expl.spec} whose \grammarterm{declaration} is not a definition. \end{itemize} A declaration is said to be a \defn{definition} of each entity that it defines. @@ -492,13 +510,13 @@ \grammarterm{splice-expression}\iref{expr.prim.splice} that designates it. A variable \tcode{x} that is named by a -potentially-evaluated expression $N$ +potentially evaluated expression $N$ that appears at a point $P$ is \defnx{odr-used}{odr-use} by $N$ unless \begin{itemize} \item \tcode{x} is a reference -that is usable in constant expressions at $P$\iref{expr.const}, or +that is usable in constant expressions at $P$\iref{expr.const.init}, or \item $N$ is an element of the set of potential results of an expression $E$, where \begin{itemize} @@ -552,10 +570,10 @@ a \grammarterm{splice-expression} that designates that structured binding. A structured binding is odr-used -if it is named by a potentially-evaluated expression. +if it is named by a potentially evaluated expression. \pnum -\tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially-evaluated expression +\tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially evaluated expression (including as the result of any implicit transformation to a class member access expression\iref{expr.prim.id.general}). @@ -563,7 +581,7 @@ A virtual member function is odr-used if it is not pure. A function is odr-used if it is named by -a potentially-evaluated expression or conversion. +a potentially evaluated expression or conversion. A non-placement allocation or deallocation function for a class is odr-used by the definition of a constructor of that class. A non-placement deallocation function for a class is odr-used by the @@ -656,7 +674,7 @@ \pnum Every program shall contain at least one definition of every function or variable that is odr-used in that program -outside of a discarded statement\iref{stmt.if}; no diagnostic required. +outside of a discarded statement\iref{stmt.if}; no diagnostic required\ifndrdef{basic.def.odr.exact.one.def}. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see~\ref{class.default.ctor}, \ref{class.copy.ctor}, @@ -739,7 +757,7 @@ \pnum If a definable item \tcode{D} is defined in a translation unit -by an injected declaration $X$\iref{expr.const} and +by an injected declaration $X$\iref{expr.const.reflect} and another translation unit contains a definition of \tcode{D}, that definition shall be an injected declaration having the same characteristic sequence as $X$; @@ -781,7 +799,7 @@ a non-volatile const object with internal or no linkage if the object \begin{itemize} \item has the same literal type in all definitions of \tcode{D}, -\item is initialized with a constant expression\iref{expr.const}, +\item is initialized with a constant expression\iref{expr.const.const}, \item is not odr-used in any definition of \tcode{D}, and \item has the same value in all definitions of \tcode{D}, \end{itemize} @@ -939,7 +957,7 @@ reachable unnamed enumeration definition in the same scope that have the same first enumerator name and do not have typedef names for linkage purposes\iref{dcl.enum}, -those unnamed enumeration types shall be the same; no diagnostic required. +those unnamed enumeration types shall be the same; no diagnostic required\ifndrdef{basic.def.odr.unnamed.enum.same.type}. \indextext{one-definition rule|)} \rSec1[basic.scope]{Scope}% @@ -999,7 +1017,7 @@ Corresponding declarations with appropriate linkage declare the same entity\iref{basic.link}. \item -The declaration in a \grammarterm{template-declaration} +The \grammarterm{declaration} of a \grammarterm{template-declaration} inhabits the same scope as the \grammarterm{template-declaration}. \item Friend declarations and @@ -1660,6 +1678,11 @@ used in further processing. \pnum +There is a \defnadj{program}{point} +before the first token of the translation unit, +at least one between every pair of adjacent tokens, and +at least one after the last token of the translation unit. + A program point $P$ is said to follow any declaration in the same translation unit whose locus\iref{basic.scope.pdecl} is before $P$. @@ -1815,7 +1838,7 @@ If it is an invalid set, the program is ill-formed. If it differs from the result of a search in $T$ for $M$ in a complete-class context\iref{class.mem} of $T$, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{class.member.lookup.name.refers.diff.decl}. \begin{example} \begin{codeblock} struct A { int x; }; // S(x,A) = \{ \{ \tcode{A::x} \}, \{ \tcode{A} \} \} @@ -2065,7 +2088,8 @@ \pnum In a friend declaration \grammarterm{declarator} whose \grammarterm{declarator-id} is a \grammarterm{qualified-id} -whose lookup context\iref{basic.lookup.qual} is a class or namespace $S$, +whose \grammarterm{nested-name-specifier} +designates a class or namespace $S$\iref{expr.prim.id.qual}, lookup for an unqualified name that appears after the \grammarterm{declarator-id} performs a search in the scope associated with $S$. @@ -2557,13 +2581,13 @@ \end{footnote} \begin{itemize} \item -if the search finds the injected-class-name of \tcode{C}\iref{class.pre}, or +if the search finds the injected-class-name of $C$\iref{class.pre}, or \item if $N$ is dependent and is the terminal name of a \grammarterm{using-declarator}\iref{namespace.udecl} that names a constructor, \end{itemize} -$N$ is instead considered to name the constructor of class \tcode{C}. +$N$ is instead considered to name the constructor of class $C$. Such a constructor name shall be used only in the \grammarterm{declarator-id} of a (friend) declaration of a constructor or in a \grammarterm{using-declaration}. @@ -2834,7 +2858,7 @@ \pnum The \grammarterm{constant-expression} of a \grammarterm{splice-specifier} shall be a converted constant expression of -type \tcode{std::meta::info}\iref{expr.const}. +type \tcode{std::meta::info}\iref{expr.const.const}. A \grammarterm{splice-specifier} whose converted \grammarterm{constant-expression} represents a construct $X$ is said to \defn{designate} either @@ -3055,9 +3079,7 @@ \item they both declare type aliases or namespace aliases that have the same underlying entity, or \item -they both declare names with module linkage and are attached to the same module, or -\item -they both declare names with external linkage. +they both declare names with module or external linkage and are attached to the same module. \end{itemize} \begin{note} There are other circumstances in which declarations declare @@ -3074,9 +3096,11 @@ \end{note} \pnum -If two declarations of an entity are -attached to different modules, the program is ill-formed; -no diagnostic is required if neither is reachable from the other. +\begin{note} +If two declarations correspond but are +attached to different modules, the program is ill-formed +if one precedes the other\iref{basic.scope.scope}. +\end{note} \begin{example} \begin{codeblocktu}{\tcode{"decls.h"}} int f(); // \#1, attached to the global module @@ -3088,15 +3112,15 @@ #include "decls.h" export module M; export using ::f; // OK, does not declare an entity, exports \#1 -int g(); // error: matches \#2, but attached to \tcode{M} +int g(); // error: corresponds to \#2, but attached to \tcode{M} export int h(); // \#3 export int k(); // \#4 \end{codeblocktu} \begin{codeblocktu}{Other translation unit} import M; -static int h(); // error: matches \#3 -int k(); // error: matches \#4 +static int h(); // error: conflicts with \#3 +int k(); // error: conflicts with \#4 \end{codeblocktu} \end{example} As a consequence of these rules, @@ -3142,7 +3166,8 @@ declarations for an array object can specify array types that differ by the presence or absence of a major array bound\iref{dcl.array}. -No diagnostic is required if neither declaration is reachable from the other. +No diagnostic is required +if neither declaration is reachable from the other\ifndrdef{basic.link.consistent.types}. \begin{example} \begin{codeblock} int f(int x, int x); // error: different entities for \tcode{x} @@ -3171,7 +3196,7 @@ a \grammarterm{reflect-expression} or a \grammarterm{splice-specifier} that, respectively, represents or designates $E$, \item -$D$ is an injected declaration\iref{expr.const} +$D$ is an injected declaration\iref{expr.const.reflect} whose characteristic sequence contains a reflection that represents a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$)\iref{class.mem.general} @@ -3622,8 +3647,7 @@ \item the backing array of an initializer list\iref{dcl.init.ref}, or \item - the object introduced by a call to \tcode{std::meta::reflect_constant_array} - or \tcode{std::meta::reflect_constant_string}\iref{meta.define.static}, or + a template parameter object of array type\iref{meta.define.static}, or \item a subobject thereof. \end{itemize} @@ -3639,18 +3663,18 @@ may have the same address if \begin{itemize} \item one is nested within the other, -\item at least one is a subobject of zero size and they are not of similar types\iref{conv.qual}, +\item +they are both nested within some complete object $o$, +exactly one is a subobject of $o$, and the subobject is of zero size, +\item +they are both subobjects of the same complete object, +at least one is a subobject of zero size, and +they are not of similar types\iref{conv.qual}, or \item they are both potentially non-unique objects; \end{itemize} otherwise, they have distinct addresses and occupy disjoint bytes of storage. -\begin{footnote} -Under the ``as-if'' rule an -implementation is allowed to store two objects at the same machine address or -not store an object at all if the program cannot observe the -difference\iref{intro.execution}. -\end{footnote} \begin{example} \begin{codeblock} static const char test1 = 'x'; @@ -3670,6 +3694,16 @@ the address of an unspecified byte of storage occupied by the complete object of that subobject. +\pnum +A \defnadj{union elemental}{subobject} +\indextext{union!elemental subobject|see{subobject, union elemental}} +is a direct member of a union or +an element of an array that is a union elemental subobject. +An \defnx{inactive union elemental subobject}{subobject!union elemental!inactive} +\indextext{inactive union elemental subobject|see{subobject, union elemental, inactive}} +\indextext{union!inactive elemental subobject|see{subobject, union elemental, inactive}} +is a union elemental subobject that is not within its lifetime. + \pnum The \defnx{constituent values}{constituent value} of an object $o$ are \begin{itemize} @@ -3677,7 +3711,7 @@ if $o$ has scalar type, the value of $o$; \item otherwise, the constituent values of any direct subobjects of $o$ -other than inactive union members. +other than inactive union elemental subobjects. \end{itemize} The \defnx{constituent references}{constituent reference} of an object $o$ are \begin{itemize} @@ -3685,8 +3719,46 @@ any direct members of $o$ that have reference type, and \item the constituent references of any direct subobjects of $o$ -other than inactive union members. +other than inactive union elemental subobjects. \end{itemize} +\begin{example} +\begin{codeblock} +struct A { + struct X { + int i; + int j; + }; + + struct Y { + X x1; + X x2; + }; + + union { + int i; + int arr[4]; + Y y; + }; +}; + +constexpr A v1; // OK, no constituent values +constexpr A v2{.i=1}; // OK, the constituent values are \tcode{\{v2.i\}} +constexpr A v3 = []{ + A a; + std::start_lifetime(a.arr); // OK, arr is now the active element of the union + new (&a.arr[1]) int(1); + a.arr[2] = 2; + return a; +}(); // OK, the constituent values are \tcode{\{v3.arr[1], v3.arr[2]\}} +constexpr A v4 = []{ + A a; + a.y.x1.i = 1; + a.y.x2.j = 2; + return a; +}(); // error: the constituent values include \tcode{v4.y.x1.j} and \tcode{v4.y.x2.i} + // which have erroneous value +\end{codeblock} +\end{example} \pnum Some operations are described as @@ -3697,7 +3769,7 @@ zero or more objects of implicit-lifetime types\iref{term.implicit.lifetime.type} in its specified region of storage if doing so would result in the program having defined behavior. -If no such set of objects would give the program defined behavior, +If no such set of objects would give the program defined behavior\ubdef{intro.object.implicit.create}, the behavior of the program is undefined. If multiple such sets of objects would give the program defined behavior, it is unspecified which such set of objects is created. @@ -3715,7 +3787,7 @@ and produce a pointer value that points to that object, if that value would result in the program having defined behavior. If no such pointer value would give the program defined behavior, -the behavior of the program is undefined. +the behavior of the program is undefined\ubdef{intro.object.implicit.pointer}. If multiple such pointer values would give the program defined behavior, it is unspecified which such pointer value is produced. @@ -3766,10 +3838,10 @@ integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested -using the alignment specifier\iref{dcl.align}. +using the \grammarterm{alignment-specifier}\iref{dcl.align}. Attempting to create an object\iref{intro.object} in storage that does not meet the alignment requirements of the object's type -is undefined behavior. +is undefined behavior\ubdef{basic.align.object.alignment}. \pnum A \defnadj{fundamental}{alignment} is represented by an alignment @@ -3826,8 +3898,8 @@ the narrow character types\iref{basic.fundamental} shall have the weakest alignment requirement. \begin{note} -This enables the ordinary character types to be used as the -underlying type for an aligned memory area\iref{dcl.align}. +The type \tcode{\keyword{unsigned} \keyword{char}} can be used as +the element type of an array providing aligned storage\iref{dcl.align}. \end{note} \pnum @@ -3958,19 +4030,20 @@ if the pointer were of type \tcode{\keyword{void}*} is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The -program has undefined behavior if +program has undefined behavior if: \begin{itemize} \item - the pointer is used as the operand of a \grammarterm{delete-expression}, + the pointer is used as the operand of a \grammarterm{delete-expression}\ubdef{lifetime.outside.pointer.delete}, \item the pointer is used to access a non-static data member or call a - non-static member function of the object, or + non-static member function of the object\ubdef{lifetime.outside.pointer.member}, or \item the pointer is converted\iref{conv.ptr,expr.static.cast} to a pointer - to a virtual base class or to a base class thereof, or + to a virtual base class\ubdef{lifetime.outside.pointer.virtual} or + to a base class thereof, or \item the pointer is used as the operand of a - \keyword{dynamic_cast}\iref{expr.dynamic.cast}. + \keyword{dynamic_cast}\iref{expr.dynamic.cast}\ubdef{lifetime.outside.pointer.dynamic.cast}. \end{itemize} \begin{example} \begin{codeblock} @@ -4013,14 +4086,14 @@ a glvalue refers to allocated storage\iref{basic.stc.dynamic.allocation}, and using the properties of the glvalue that do not depend on its value is -well-defined. The program has undefined behavior if +well-defined. The program has undefined behavior if: \begin{itemize} -\item the glvalue is used to access the object, or -\item the glvalue is used to call a non-static member function of the object, or -\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}, or +\item the glvalue is used to access the object\ubdef{lifetime.outside.glvalue.access}, or +\item the glvalue is used to call a non-static member function of the object\ubdef{lifetime.outside.glvalue.member}, or +\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}\ubdef{lifetime.outside.glvalue.virtual}, or \item the glvalue is used as the operand of a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or as the operand of -\keyword{typeid}. +\keyword{typeid}\ubdef{lifetime.outside.glvalue.dynamic.cast}. \end{itemize} \begin{note} @@ -4105,7 +4178,7 @@ \end{footnote} and another object of the original type does not occupy that same storage location when the implicit destructor call takes -place, the behavior of the program is undefined. This is true +place, the behavior of the program is undefined\ubdef{original.type.implicit.destructor}. This is true even if the block is exited with an exception. \begin{example} \begin{codeblock} @@ -4125,7 +4198,7 @@ Creating a new object within the storage that a const, complete object with static, thread, or automatic storage duration occupies, or within the storage that such a const object used to occupy before -its lifetime ended, results in undefined behavior. +its lifetime ended, results in undefined behavior\ubdef{creating.within.const.complete.obj}. \begin{example} \begin{codeblock} struct B { @@ -4186,7 +4259,7 @@ then the value produced by that operator is erroneous. Except in the following cases, if an indeterminate value is produced by an evaluation, -the behavior is undefined, and +the behavior is undefined\ubdef{basic.indet.value}, and if an erroneous value is produced by an evaluation, the behavior is erroneous and the result of the evaluation is that erroneous value: @@ -4473,7 +4546,7 @@ does not satisfy the semantic constraints specified in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}, -the behavior is undefined. +the behavior is undefined\ubdef{basic.stc.alloc.dealloc.constraint}. \indextext{storage duration!dynamic|)} @@ -4483,7 +4556,7 @@ \indextext{function!allocation}% An allocation function that is not a class member function shall belong to the global scope and not have a name with internal linkage. -The return type shall be \tcode{\keyword{void}*}. The first +The return type shall be ``pointer to \keyword{void}''. The first parameter shall have type \tcode{std::size_t}\iref{support.types}. The first parameter shall not have an associated default argument\iref{dcl.fct.default}. The value of the first parameter @@ -4513,7 +4586,7 @@ \tcode{p0} represents the address of a block of storage disjoint from the storage for any other object accessible to the caller. The effect of indirecting through a pointer -returned from a request for zero size is undefined. +returned from a request for zero size is undefined\ubdef{basic.stc.alloc.zero.dereference}. \begin{footnote} The intent is to have \tcode{\keyword{operator} \keyword{new}()} implementable by @@ -4604,9 +4677,9 @@ Each deallocation function shall return \keyword{void}. If the function is a destroying operator delete declared in class type \tcode{C}, -the type of its first parameter shall be \tcode{C*}; +the type of its first parameter shall be ``pointer to \tcode{C}''; otherwise, the type of its first -parameter shall be \tcode{\keyword{void}*}. A deallocation function may have more +parameter shall be ``pointer to \keyword{void}''. A deallocation function may have more than one parameter. \indextext{deallocation function!usual}% A \defn{usual deallocation function} is a deallocation function @@ -4636,7 +4709,7 @@ signature. \pnum -If a deallocation function terminates by throwing an exception, the behavior is undefined. +If a deallocation function terminates by throwing an exception, the behavior is undefined\ubdef{basic.stc.alloc.dealloc.throw}. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. @@ -4743,7 +4816,7 @@ \pnum When an object of type \tcode{X} -is passed to or returned from a potentially-evaluated function call, +is passed to or returned from a potentially evaluated function call, if \tcode{X} is \begin{itemize} \item @@ -4891,7 +4964,7 @@ covered above. \begin{example} \begin{codeblock} -const int& x = (const int&)1; // temporary for value 1 has same lifetime as x +const int& x = (const int&)1; // temporary for value \tcode{1} has same lifetime as \tcode{x} \end{codeblock} \end{example} \end{note} @@ -4953,7 +5026,7 @@ \pnum The sixth context is when a temporary object is created in the \grammarterm{expansion-initializer} -of a destructuring expansion statement. +of an iterating or destructuring expansion statement. If such a temporary object would otherwise be destroyed at the end of that \grammarterm{expansion-initializer}, the object persists for the lifetime of the reference @@ -5351,7 +5424,7 @@ during the evaluation of a core constant expression. \end{itemize} Every function of consteval-only type shall be -an immediate function\iref{expr.const}. +an immediate function\iref{expr.const.imm}. \rSec2[basic.fundamental]{Fundamental types} @@ -5635,13 +5708,12 @@ \indextext{type!\idxcode{void}}% A type \cv{}~\keyword{void} is an incomplete type that cannot be completed; such a type has -an empty set of values. It is used as the return -type for functions that do not return a value. +an empty set of values. \begin{note} An expression of type \cv{}~\keyword{void} can be used as \begin{itemize} -\item an expression statement\iref{stmt.expr}, -\item the expression in a \keyword{return} statement\iref{stmt.return} +\item the \grammarterm{expression} of an expression statement\iref{stmt.expr}, +\item the operand of a \keyword{return} statement\iref{stmt.return} for a function with the return type \cv{}~\keyword{void}, \item an operand of a comma expression\iref{expr.comma}, \item the operand of a parenthesized expression\iref{expr.prim.paren}, @@ -5660,7 +5732,12 @@ A prvalue of type \tcode{std::nullptr_t} is a null pointer constant\iref{conv.ptr}. Such values participate in the pointer and the pointer-to-member conversions\iref{conv.ptr,conv.mem}. -\tcode{\keyword{sizeof}(std::nullptr_t)} shall be equal to \tcode{\keyword{sizeof}(\keyword{void}*)}. +The size\iref{expr.sizeof} and alignment requirement\iref{basic.align} of +the type \tcode{std::nullptr_t} are those of +the type ``pointer to \keyword{void}''. +\begin{note} +The value representation can comprise no bits\iref{conv.lval}. +\end{note} \pnum A value of type \tcode{std::meta::info} is called a \defn{reflection}. @@ -5771,7 +5848,7 @@ If the implementation supports an extended floating-point type\iref{basic.fundamental} whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary16, -then the \grammarterm{typedef-name} \tcode{std::float16_t} +then the type alias \tcode{std::float16_t} is declared in the header \libheaderref{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT16_T} is defined\iref{cpp.predefined}, and the floating-point literal suffixes \tcode{f16} and \tcode{F16} @@ -5781,7 +5858,7 @@ If the implementation supports an extended floating-point type whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary32, -then the \grammarterm{typedef-name} \tcode{std::float32_t} +then the type alias \tcode{std::float32_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT32_T} is defined, and the floating-point literal suffixes \tcode{f32} and \tcode{F32} are supported. @@ -5790,7 +5867,7 @@ If the implementation supports an extended floating-point type whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary64, -then the \grammarterm{typedef-name} \tcode{std::float64_t} +then the type alias \tcode{std::float64_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT64_T} is defined, and the floating-point literal suffixes \tcode{f64} and \tcode{F64} are supported. @@ -5799,7 +5876,7 @@ If the implementation supports an extended floating-point type whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary128, -then the \grammarterm{typedef-name} \tcode{std::float128_t} +then the type alias \tcode{std::float128_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT128_T} is defined, and the floating-point literal suffixes \tcode{f128} and \tcode{F128} are supported. @@ -5812,7 +5889,7 @@ precision in bits ($p$) of 8, maximum exponent ($emax$) of 127, and exponent field width in bits ($w$) of 8, then -the \grammarterm{typedef-name} \tcode{std::bfloat16_t} +the type alias \tcode{std::bfloat16_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_BFLOAT16_T} is defined, and the floating-point literal suffixes \tcode{bf16} and \tcode{BF16} are supported. @@ -5979,6 +6056,28 @@ alignment requirement. \end{note} +\pnum +A pointer value +pointing to a potentially non-unique object $O$\iref{intro.object} is +\indextext{value!associated with an evaluation}% +\defn{associated with} the evaluation of +\begin{itemize} +\item +the string-literal\iref{lex.string} that resulted in the string literal object, +\item +the initializer list\iref{dcl.init.list} that resulted in the backing array, +or +\item +the initialization of +the template parameter object\iref{temp.arg.nontype, meta.define.static} +\end{itemize} +that is $O$ or of which $O$ is a subobject. +\begin{note} +A pointer value obtained by pointer arithmetic\iref{expr.add} +from a pointer value associated with an evaluation $E$ +is also associated with $E$. +\end{note} + \pnum A pointer value $P$ is \indextext{value!valid in the context of an evaluation}% @@ -5990,7 +6089,7 @@ $P$ is not valid in the context of $E$, then the behavior is undefined if $E$ is an indirection\iref{expr.unary.op} or -an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation}, +an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation}\ubdef{basic.compound.invalid.pointer}, and \impldef{invalid pointer value in the context of an evaluation} otherwise. \begin{footnote} Some implementations might define that @@ -6252,7 +6351,7 @@ \tcode{\keyword{long} \keyword{double}}, \keyword{double}, and \tcode{std::float64_t} -have the same set of values (see \IsoC H.4.3). +have the same set of values (see \IsoC{} H.4.3). \end{tailnote} \end{itemize} \begin{note} @@ -6368,9 +6467,9 @@ \item an unevaluated operand\iref{expr.context}, \item -a \grammarterm{constant-expression}\iref{expr.const}, +a \grammarterm{constant-expression}\iref{expr.const.core}, \item -an immediate invocation\iref{expr.const}, +an immediate invocation\iref{expr.const.imm}, \item an \grammarterm{init-declarator}\iref{dcl.decl} (including such introduced by a structured binding\iref{dcl.struct.bind}) or @@ -6437,7 +6536,7 @@ \indextext{value computation|(}% Reading an object designated by a \keyword{volatile} glvalue\iref{basic.lval}, modifying an object, -producing an injected declaration\iref{expr.const}, +producing an injected declaration\iref{expr.const.reflect}, calling a library I/O function, or calling a function that does any of those operations are all \defn{side effects}, @@ -6510,7 +6609,7 @@ The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. -The behavior is undefined if +The behavior is undefined\iref{intro.multithread}\ubdef{intro.execution.unsequenced.modification} if \begin{itemize} \item \indextext{side effects}% @@ -6617,7 +6716,7 @@ \pnum During the evaluation of an expression -as a core constant expression\iref{expr.const}, +as a core constant expression\iref{expr.const.core}, evaluations of operands of individual operators and of subexpressions of individual expressions that are otherwise either unsequenced or indeterminately sequenced @@ -6806,7 +6905,7 @@ \item $A$ happens before $B$ and \item there is no other \indextext{side effects}% -side effect $X$ to $M$ such that $A$ +side effect $X$ on $M$ such that $A$ happens before $X$ and $X$ happens before $B$. \end{itemize} @@ -6918,7 +7017,7 @@ and neither happens before the other, except for the special case for signal handlers described below. Any such data race results in undefined -behavior. +behavior\ubdef{intro.races.data}. \begin{note} It can be shown that programs that correctly use mutexes and \tcode{memory_order::seq_cst} operations to prevent all data races and use no @@ -6977,8 +7076,8 @@ \rSec3[intro.progress]{Forward progress} \pnum -The implementation may assume that any thread will eventually do one of the -following: +The implementation may assume\ubdef{intro.progress.stops} that any thread +will eventually do one of the following: \begin{itemize} \item terminate, \item invoke the function \tcode{std::this_thread::yield}\iref{thread.thread.this}, @@ -7282,7 +7381,7 @@ objects with automatic storage duration\iref{class.dtor}. If \tcode{std::exit} is invoked during the destruction of an object with static or thread storage duration, the program has undefined -behavior. +behavior\ubdef{basic.start.main.exit.during.destruction}. \pnum \indextext{termination!program}% @@ -7311,7 +7410,7 @@ \indextext{initialization!constant}% \defnx{Constant initialization}{constant initialization} is performed if a variable with static or thread storage duration -is constant-initialized\iref{expr.const}. +is constant-initialized\iref{expr.const.init}. \indextext{initialization!zero-initialization}% If constant initialization is not performed, a variable with static storage duration\iref{basic.stc.static} or thread storage @@ -7349,16 +7448,18 @@ object \tcode{obj2} potentially requiring dynamic initialization and defined later in the same translation unit, it is unspecified whether the value of \tcode{obj2} used will be the value of the fully initialized \tcode{obj2} (because \tcode{obj2} was statically -initialized) or will be the value of \tcode{obj2} merely zero-initialized. For example, +initialized) or will be the value of \tcode{obj2} merely zero-initialized. For example: \begin{codeblock} inline double fd() { return 1.0; } extern double d1; -double d2 = d1; // unspecified: - // either statically initialized to \tcode{0.0} or - // dynamically initialized to \tcode{0.0} if \tcode{d1} is - // dynamically initialized, or \tcode{1.0} otherwise -double d1 = fd(); // either initialized statically or dynamically to \tcode{1.0} +double d2 = d1; +double d1 = fd(); \end{codeblock} +Both \tcode{d1} and \tcode {d2} can be initialized +either statically or dynamically. +If \tcode{d1} is initialized statically and \tcode{d2} dynamically, +both variables are initialized to \tcode{1.0}; +in all other cases, \tcode{d2} is initialized to \tcode{0.0}. \end{note} \rSec3[basic.start.dynamic]{Dynamic initialization of non-block variables} @@ -7562,7 +7663,7 @@ \pnum The destruction of a complete object with thread storage duration within a given thread -and having constant destruction\iref{expr.const} +and having constant destruction\iref{expr.const.defns} is sequenced after the destruction of any other complete object with thread storage duration within the thread. The destruction of a complete object with static storage duration @@ -7617,7 +7718,7 @@ \pnum If a function contains a block variable of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or -thread storage duration, the program has undefined behavior if the flow of control +thread storage duration, the program has undefined behavior\ubdef{basic.start.term.use.after.destruction} if the flow of control passes through the definition of the previously destroyed block variable. \begin{note} Likewise, the behavior is undefined @@ -7645,7 +7746,7 @@ handlers\iref{support.runtime} that does not happen before\iref{intro.multithread} completion of destruction of objects with static storage duration and execution of \tcode{std::atexit} registered functions\iref{support.start.term}, the program has -undefined behavior. +undefined behavior\ubdef{basic.start.term.signal.handler}. \begin{note} If there is a use of an object with static storage duration that does not happen before the object's destruction, the program has undefined @@ -7694,7 +7795,7 @@ An invocation of the macro \tcode{va_start}\iref{cstdarg.syn} shall not be a subexpression of the predicate of a contract assertion, -no diagnostic required. +no diagnostic required\ifndrdef{basic.contract.vastart.contract.predicate}. \pnum \begin{note} @@ -7801,7 +7902,7 @@ \item the evaluation of the predicate is performed in a context that is -manifestly constant-evaluated\iref{expr.const} +manifestly constant-evaluated\iref{expr.const.defns} and the predicate is not a core constant expression. \end{itemize} @@ -7822,7 +7923,7 @@ \pnum \indexdefn{contract evaluation semantics!terminating}% If a contract violation occurs -in a context that is manifestly constant-evaluated\iref{expr.const}, +in a context that is manifestly constant-evaluated\iref{expr.const.defns}, and the evaluation semantic is a terminating semantic, the program is ill-formed. @@ -8100,6 +8201,6 @@ If the contract-violation handler is not replaceable, a declaration of a replacement function for the contract-violation handler -is ill-formed, no diagnostic required. +is ill-formed, no diagnostic required.\ifndrdef{basic.contract.handler.replacing.nonreplaceable} \indextext{contract assertion|)} diff --git a/source/classes.tex b/source/classes.tex index c6bb8eb3f1..bc9a4d0b20 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -580,6 +580,10 @@ shall either declare at least one member name of the class or declare at least one unnamed bit-field. +A \defnx{user-declared}{entity!user-declared} +\indextext{user-declared entity|see{entity, user-declared}} +entity is a direct member or a friend that, in either case, +is declared by a \grammarterm{member-declaration}. \pnum A \defn{data member} is either a non-function member introduced by a @@ -717,7 +721,7 @@ shall not directly or indirectly cause the implicit definition of a defaulted default constructor for the enclosing class or the exception specification of that constructor. -An immediate invocation\iref{expr.const} that +An immediate invocation\iref{expr.const.imm} that is a potentially-evaluated subexpression\iref{intro.execution} of a default member initializer is neither evaluated nor checked for whether it @@ -1273,8 +1277,9 @@ has a default argument (including the case of a constructor with no parameters). \indextext{implicitly-declared default constructor}% -If there is no user-declared constructor or constructor template for class -\tcode{X}, +If a class does not have +a user-declared constructor or constructor template, +and the class is not an anonymous union, a non-explicit constructor having no parameters is implicitly declared as defaulted\iref{dcl.fct.def}. An implicitly-declared default constructor is an @@ -1332,18 +1337,7 @@ \defnx{non-trivial}{constructor!default!non-trivial}. \pnum -If a default constructor of a union-like class \tcode{X} is trivial, -then for each union \tcode{U} -that is either \tcode{X} or an anonymous union member of \tcode{X}, -if the first variant member, if any, of \tcode{U} -has implicit-lifetime type\iref{basic.types.general}, -the default constructor of \tcode{X} begins the lifetime of that member -if it is not the active member of its union. -\begin{note} -It is already the active member if \tcode{U} was value-initialized. -\end{note} -Otherwise, -an implicitly-defined\iref{dcl.fct.def.default} default constructor performs the set of +An implicitly-defined\iref{dcl.fct.def.default} default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no \grammarterm{ctor-initializer}\iref{class.base.init} and an empty @@ -1503,7 +1497,8 @@ \end{example} \pnum -If the class definition does not explicitly declare a copy constructor, +If the class does not have a user-declared copy constructor +and the class is not an anonymous union, a non-explicit one is declared \defnx{implicitly}{constructor!copy!implicitly declared}. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy @@ -1543,10 +1538,13 @@ \pnum \indextext{constructor!move!implicitly declared}% -If the definition of a class \tcode{X} does not explicitly declare -a move constructor, a non-explicit one will be +If a class \tcode{X} does not have +a user-declared move constructor, a non-explicit one will be implicitly declared as defaulted if and only if \begin{itemize} +\item +\tcode{X} is not an anonymous union, + \item \tcode{X} does not have a user-declared copy constructor, @@ -1601,6 +1599,17 @@ an rvalue which can use the copy constructor instead. \end{note} +\pnum +\begin{note} +A using-declaration in a derived class \tcode{C} that +names a constructor from a base class +never suppresses the implicit declaration of +a copy/move constructor of \tcode{C}, +even if the base class constructor would be +a copy or move constructor +if declared as a member of \tcode{C}. +\end{note} + \pnum \indextext{constructor!copy!trivial}% \indextext{constructor!move!trivial}% @@ -1742,9 +1751,10 @@ \end{note} \pnum -If the class definition does not explicitly declare a copy assignment operator, +If the class does not have a user-declared copy assignment operator +and the class is not an anonymous union, one is declared \defnx{implicitly}{assignment operator!copy!implicitly declared}. -If the class definition declares a move +If the class has a user-declared move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defaulted\iref{dcl.fct.def}. @@ -1796,6 +1806,9 @@ move assignment operator, one will be implicitly declared as defaulted if and only if \begin{itemize} +\item +\tcode{X} is not an anonymous union, + \item \tcode{X} does not have a user-declared copy constructor, @@ -2030,7 +2043,8 @@ \indextext{generated destructor|see{destructor, default}}% \indextext{destructor!default}% If a class has no user-declared -prospective destructor, +prospective destructor +and the class is not an anonymous union, a prospective destructor is implicitly declared as defaulted\iref{dcl.fct.def}. An implicitly-declared prospective destructor is an @@ -2043,7 +2057,8 @@ \end{codeblock} \pnum -At the end of the definition of a class, +At the end of the definition of a class +other than an anonymous union, overload resolution is performed among the prospective destructors declared in that class with an empty argument list @@ -2316,7 +2331,7 @@ \pnum Once a destructor is invoked for an object, the object's lifetime ends; -the behavior is undefined if the destructor is invoked +the behavior is undefined\ubdef{class.dtor.no.longer.exists} if the destructor is invoked for an object whose lifetime has ended\iref{basic.life}. \begin{example} If the destructor for an object with automatic storage duration is explicitly invoked, @@ -2750,7 +2765,7 @@ its declaration in the class definition can specify a \grammarterm{brace-or-equal-initializer} in which every \grammarterm{initializer-clause} that is an \grammarterm{assignment-expression} -is a constant expression\iref{expr.const}. +is a constant expression\iref{expr.const.const}. The member shall still be defined in a namespace scope if it is odr-used\iref{term.odr.use} in the program and the namespace scope definition shall not contain an \grammarterm{initializer}. @@ -3266,13 +3281,16 @@ an \defnx{anonymous union member}{member!anonymous union} if it is a non-static data member or an \defnx{anonymous union variable}{variable!anonymous union} otherwise. +Each object of such an unnamed type shall be such an unnamed object. \indextext{access control!anonymous \tcode{union}}% \indextext{restriction!anonymous \tcode{union}}% Each \grammarterm{member-declaration} in the \grammarterm{member-specification} of an anonymous union shall define one or more public non-static data members, be an \grammarterm{empty-declaration}, or be a \grammarterm{static_assert-declaration}. -Nested types, anonymous unions, and functions +Nested types +(including closure types\iref{expr.prim.lambda.closure} and anonymous unions) +and functions shall not be declared within an anonymous union. The names of the members of an anonymous union are bound in the scope inhabited by the union declaration. @@ -3984,7 +4002,7 @@ \indextext{definition!virtual function}% A virtual function declared in a class shall be defined, or declared pure\iref{class.abstract} in that class, or both; no diagnostic is -required\iref{basic.def.odr}. +required\iref{basic.def.odr}\ifndrdef{class.virtual.pure.or.defined}. \indextext{friend!\tcode{virtual} and}% \pnum @@ -4099,11 +4117,11 @@ \indextext{function!virtual|)} \pnum -A class with a \keyword{consteval} virtual function that overrides -a virtual function that is not \keyword{consteval} +A class with an immediate virtual function that overrides +a non-immediate virtual function shall have consteval-only type\iref{basic.types.general}. -A \keyword{consteval} virtual function shall not be overridden by -a virtual function that is not \keyword{consteval}. +An immediate virtual function shall not be overridden by +a non-immediate virtual function. \rSec2[class.abstract]{Abstract classes}% @@ -4218,7 +4236,7 @@ \indextext{virtual function call!undefined pure}% the effect of making a virtual call\iref{class.virtual} to a pure virtual function directly or indirectly for the object being created (or -destroyed) from such a constructor (or destructor) is undefined.% +destroyed) from such a constructor (or destructor) is undefined\ubdef{class.abstract.pure.virtual}.% \indextext{derived class|)} \rSec1[class.access]{Member access control}% @@ -5359,9 +5377,9 @@ Here, \tcode{x.i} -is initialized with 99, +is initialized with \tcode{99}, \tcode{x.f} -is initialized with 88.8, and +is initialized with \tcode{88.8}, and \tcode{complex::complex(double)} is called for the initialization of \tcode{x.c}. @@ -5503,7 +5521,7 @@ The target constructor is selected by overload resolution. Once the target constructor returns, the body of the delegating constructor is executed. If a constructor delegates to itself directly or indirectly, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{class.base.init.delegate.itself}. \begin{example} \begin{codeblock} struct C { @@ -5818,7 +5836,7 @@ \item a postcondition assertion of a destructor\iref{dcl.contract.func}, \end{itemize} -the program has undefined behavior. +the program has undefined behavior\ubdef{class.base.init.mem.fun}. \begin{example} \begin{codeblock} class A { @@ -6015,9 +6033,10 @@ \indextext{destruction!member access}% For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in -undefined behavior. For an object with a non-trivial destructor, referring to +undefined behavior\ubdef{class.cdtor.before.ctor}. +For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes -execution results in undefined behavior. +execution results in undefined behavior\ubdef{class.cdtor.after.dtor}. \begin{example} \begin{codeblock} struct X { int i; }; @@ -6102,7 +6121,7 @@ indirectly derive from \tcode{B} shall have started and the destruction of these classes shall not have -completed, otherwise the conversion results in undefined behavior. +completed, otherwise the conversion results in undefined behavior\ubdef{class.cdtor.convert.pointer}. To form a pointer to (or access the value of) a direct non-static member of an object \tcode{obj}, @@ -6110,7 +6129,7 @@ \tcode{obj} shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member -value) results in undefined behavior. +value) results in undefined behavior\ubdef{class.cdtor.form.pointer}. \begin{example} \begin{codeblock} struct A { }; @@ -6154,7 +6173,7 @@ and the object expression refers to the complete object of \tcode{x} or one of that object's base class subobjects but not \tcode{x} or one of its base class subobjects, the behavior -is undefined. +is undefined\ubdef{class.cdtor.virtual.not.x}. \begin{example} \begin{codeblock} struct V { @@ -6211,7 +6230,7 @@ \tcode{typeid} refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor's class nor one of its -bases, the behavior is undefined. +bases, the behavior is undefined\ubdef{class.cdtor.typeid}. \pnum \indextext{construction!dynamic cast and}% @@ -6236,7 +6255,7 @@ the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, the \keyword{dynamic_cast} -results in undefined behavior. +results in undefined behavior\ubdef{class.cdtor.dynamic.cast}. \begin{example} \begin{codeblock} struct V { @@ -6341,7 +6360,7 @@ \end{itemize} Copy elision is not permitted where an expression is evaluated in a context -requiring a constant expression\iref{expr.const} +requiring a constant expression\iref{expr.const.const} and in constant initialization\iref{basic.start.static}. \begin{note} It is possible that copy elision is performed @@ -6377,7 +6396,7 @@ } constexpr A a; // well-formed, \tcode{a.p} points to \tcode{a} -constexpr A b = g(); // error: \tcode{b.p} would be dangling\iref{expr.const} +constexpr A b = g(); // error: \tcode{b.p} would be dangling\iref{expr.const.const} void h() { A c = g(); // well-formed, \tcode{c.p} can point to \tcode{c} or be dangling diff --git a/source/compatibility.tex b/source/compatibility.tex index a0ae25da56..51d2c511f8 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -222,6 +222,23 @@ type deductions from \#2 and \#3 both succeed. \end{example} +\rSec2[diff.cpp23.cpp]{\ref{cpp}: preprocessing directives} + +\diffref{cpp.replace.general} +\change +Additional restrictions on macro names. +\rationale +Avoid hard to diagnose or non-portable constructs. +\effect +Keywords, +names of identifiers with special meaning\iref{lex.name}, +and (unless otherwise specified) \grammarterm{attribute-token}{s} +specified in \ref{dcl.attr} +may not be used as macro names. +For example, valid \CppXXIII{} code that +defines \tcode{post} or \tcode{pre} as macros +is invalid in this revision of \Cpp{}. + \rSec2[diff.cpp23.library]{\ref{library}: library introduction} \diffref{headers} @@ -2916,11 +2933,10 @@ \diffref{basic.types} \change -C allows ``compatible types'' in several places, \Cpp{} does not.\\ +C allows mixing between ``compatible types'' in several places where \Cpp{} does not.\\ For example, -otherwise-identical \keyword{struct} types with different tag names -are ``compatible'' in C but are distinctly different types -in \Cpp{}. +enumerated types are ``compatible'' with their underlying types in C but, in \Cpp{}, +enumerations are types distinct from their underlying types. \rationale Stricter type checking is essential for \Cpp{}. \effect @@ -2928,9 +2944,8 @@ \difficulty Semantic transformation. The ``typesafe linkage'' mechanism will find many, but not all, -of such problems. -Those problems not found by typesafe linkage will continue to -function properly, +such problems. +Some cases are allowed by \Cpp{} according to the ``layout compatibility rules'' of this document. \howwide @@ -3449,14 +3464,15 @@ \diffref{dcl.enum} \change -In \Cpp{}, the type of an enumerator is its enumeration. In C, the type of an enumerator is \keyword{int}. +In \Cpp{}, the type of an enumerator is its enumeration. In C, the type of an enumerator is an integer type. \begin{example} \begin{codeblock} enum e { A }; -sizeof(A) == sizeof(int) // in C -sizeof(A) == sizeof(e) // in \Cpp{} -/* and @sizeof(int)@ is not necessarily equal to @sizeof(e)@ */ +void f() { + auto x = A; + int *p = &x; // valid C, invalid \Cpp{} +} \end{codeblock} \end{example} @@ -3468,10 +3484,6 @@ Semantic transformation. \howwide Seldom. -The only time this affects existing C code is when the size of an -enumerator is taken. -Taking the size of an enumerator is not a -common C coding practice. \diffref{dcl.align} \change diff --git a/source/concepts.tex b/source/concepts.tex index 3cbd110a4a..d1e15a6e1a 100644 --- a/source/concepts.tex +++ b/source/concepts.tex @@ -1033,7 +1033,7 @@ \item \tcode{\exposid{CONVERT_TO_LVALUE}(u1)} equals \tcode{\exposid{CONVERT_TO_LVALUE}(u2)} -if and only if \tcode{u1} equals \tcode{u2} +if and only if \tcode{u1} equals \tcode{u2}. \end{itemize} \rSec2[concept.equalitycomparable]{Concept \cname{equality_comparable}} diff --git a/source/containers.tex b/source/containers.tex index 771e3f1a06..63cf29baa1 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -7117,7 +7117,7 @@ constexpr size_type remove(const T& value); template constexpr size_type remove_if(Predicate pred); - size_type unique(); + constexpr size_type unique(); template constexpr size_type unique(BinaryPredicate binary_pred); constexpr void merge(forward_list& x); @@ -8847,7 +8847,8 @@ \pnum \throws \tcode{length_error} if any of \tcode{x}'s active blocks -are not within the bounds of \exposid{current-limits}. +are not within the bounds of \exposid{current-limits}, +as well as any exceptions thrown by the allocator. \pnum \complexity @@ -8931,7 +8932,7 @@ References, pointers, and iterators referring to elements in \tcode{*this}, as well as the past-the-end iterator, may be invalidated. \begin{note} -Not required to be stable\ref{algorithm.stable}. +Not required to be stable\iref{algorithm.stable}. \end{note} \end{itemdescr} @@ -9074,7 +9075,7 @@ \pnum The types \tcode{iterator} and \tcode{const_iterator} meet -the constexpr iterator requirements\ref{iterator.requirements.general}. +the constexpr iterator requirements\iref{iterator.requirements.general}. \begin{codeblock} namespace std { @@ -9235,7 +9236,7 @@ \begin{itemdescr} \pnum \effects -Constructs an empty list, using the specified allocator. +Constructs an empty \tcode{list}, using the specified allocator. \pnum \complexity @@ -10651,6 +10652,18 @@ \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator bool}{vector::reference}% +\begin{itemdecl} +constexpr reference::operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if the value of the bit referred to by \tcode{*this} is one, +\tcode{false} otherwise. +\end{itemdescr} + \indexlibrarymember{flip}{vector::reference}% \begin{itemdecl} constexpr void reference::flip() noexcept; @@ -10735,7 +10748,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(const T& ref, FormatContext& ctx) const; }; } @@ -10756,7 +10769,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(const T& ref, FormatContext& ctx) const; \end{itemdecl} @@ -17619,7 +17632,7 @@ \pnum \effects Equivalent to \tcode{flat_map(sorted_unique, key_cont, mapped_cont)} and -\tcode{flat_map(sorted_unique, key_cont, \linebreak{}mapped_cont, comp)}, respectively, +\tcode{flat_map(sorted_unique, key_cont, mapped_cont, comp)}, respectively, except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed with uses-allocator construction\iref{allocator.uses.construction}. @@ -18774,11 +18787,11 @@ \begin{itemdecl} template constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const Alloc& a); + const mapped_container_type& mapped_cont, const Alloc& a); template constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const key_compare& comp, - const Alloc& a); + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); \end{itemdecl} \begin{itemdescr} @@ -19494,8 +19507,8 @@ \effects Adds elements to \exposid{c} as if by: \begin{codeblock} -ranges::for_each(rg, [&](auto&& e) { - @\exposid{c}@.insert(@\exposid{c}@.end(), std::forward(e)); +ranges::for_each(rg, [&](value_type e) { + @\exposid{c}@.insert(@\exposid{c}@.end(), std::move(e)); }); \end{codeblock} Then, @@ -20182,8 +20195,8 @@ \effects Adds elements to \exposid{c} as if by: \begin{codeblock} -ranges::for_each(rg, [&](auto&& e) { - @\exposid{c}@.insert(@\exposid{c}@.end(), std::forward(e)); +ranges::for_each(rg, [&](value_type e) { + @\exposid{c}@.insert(@\exposid{c}@.end(), std::move(e)); }); \end{codeblock} Then, sorts the range of newly inserted elements with respect to \exposid{compare}, @@ -20308,7 +20321,7 @@ \tcode{queue}, \tcode{priority_queue}, and \tcode{stack}, -the library provides the following formatter specialization +the library provides the following constexpr-enabled formatter specialization where \tcode{\placeholder{adaptor-type}} is the name of the template: \indexlibraryglobal{formatter}% @@ -20330,7 +20343,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; }; } @@ -20352,7 +20365,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; \end{itemdecl} @@ -20392,10 +20405,7 @@ concept @\defexposconcept{integral-constant-like}@ = // \expos is_integral_v> && !is_same_v> && - @\libconcept{convertible_to}@ && - @\libconcept{equality_comparable_with}@ && - bool_constant::value && - bool_constant(T()) == T::value>::value; + @\exposconcept{constexpr-wrapper-like}@; template constexpr size_t @\defexposconcept{maybe-static-ext}@ = dynamic_extent; // \expos @@ -21289,12 +21299,12 @@ inline constexpr full_extent_t full_extent{}; template - constexpr auto submdspan_extents(const extents&, SliceSpecifiers...); + constexpr auto subextents(const extents&, SliceSpecifiers...); // \ref{mdspan.sub.canonical}, \tcode{submdspan} slice canonicalization template - constexpr auto submdspan_canonicalize_slices(const extents& src, - Slices... slices); + constexpr auto canonical_slices(const extents& src, + Slices... slices); // \ref{mdspan.sub.sub}, \tcode{submdspan} function template template constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos -> @\seebelow@; @@ -23424,7 +23434,7 @@ direct-non-list-initializes \exposid{stride-1} \begin{itemize} \item -with \tcode{ext.extent(0)} if padding_value is \tcode{dynamic_extent}, +with \tcode{ext.extent(0)} if \tcode{padding_value} is \tcode{dynamic_extent}, \item otherwise with \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.extent(0))}. @@ -23907,7 +23917,7 @@ index_type @\exposid{stride-rm2}@ = @\exposid{static-padding-stride}@; // \expos extents_type @\exposid{extents_}@{}; // \expos - // \ref{mdspan.sub.map}, submdspan mapping specialization + // \ref{mdspan.sub.map}, \tcode{submdspan} mapping specialization template constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos -> @\seebelow@; @@ -25033,7 +25043,7 @@ typename MappingType::layout_type>; template - mdspan(const typename AccessorType::data_handle_type&, const MappingType&, + mdspan(typename AccessorType::data_handle_type, const MappingType&, const AccessorType&) -> mdspan; @@ -25124,7 +25134,7 @@ \item \tcode{(is_convertible_v \&\& ...)} is \tcode{true}, \item -\tcode{(is_nothrow_constructible \&\& ...)} is \tcode{true}, +\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}, \item \tcode{N == rank() || N == rank_dynamic()} is \tcode{true}, \item @@ -25846,11 +25856,12 @@ \rSec4[mdspan.sub.canonical]{\tcode{submdspan} slice canonicalization} -\indexlibraryglobal{submdspan_canonicalize_slices}% +%FIXME: "Slices" is used instead of "SliceSpecifiers" in the synopsis declaration. +\indexlibraryglobal{canonical_slices}% \begin{itemdecl} template - constexpr auto submdspan_canonicalize_slices(const extents& src, - SliceSpecifiers... slices); + constexpr auto canonical_slices(const extents& src, + SliceSpecifiers... slices); \end{itemdecl} \begin{itemdescr} @@ -25882,20 +25893,20 @@ \tcode{make_tuple(\exposid{canonical-slice}(slices)...)}. \end{itemdescr} -\rSec4[mdspan.sub.extents]{\tcode{submdspan_extents} function} +\rSec4[mdspan.sub.extents]{\tcode{subextents} function} -\indexlibraryglobal{submdspan_extents}% +\indexlibraryglobal{subextents}% \begin{itemdecl} template - constexpr auto submdspan_extents(const extents& src, - SliceSpecifiers... raw_slices); + constexpr auto subextents(const extents& src, + SliceSpecifiers... raw_slices); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{slices} be the pack introduced by the following declaration: \begin{codeblock} -auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...); +auto [...slices] = canonical_slices(src, raw_slices...); \end{codeblock} \pnum @@ -25917,7 +25928,7 @@ \pnum \expects For each rank index $k$ of \tcode{src}, -\tcode{slices...[k]} is a valid \tcode{submdspan} slice +\tcode{slices...[$k$]} is a valid \tcode{submdspan} slice for the $k^\text{th}$ extent of \tcode{src}. \pnum @@ -25997,7 +26008,7 @@ \tcode{valid_slices} denote a pack of (possibly const) objects for which \tcode{sizeof...(valid_slices) == M_rank} is \tcode{true} and, for each rank index $i$ of \tcode{m.extents()}, - \tcode{valid_slices...[i]} is a valid \tcode{submdspan} slice + \tcode{valid_slices...[$i$]} is a valid \tcode{submdspan} slice for the $i^\text{th}$ extent of \tcode{m.extents()}; \item \tcode{invalid_slices} denote a pack of objects @@ -26034,7 +26045,7 @@ \begin{itemdescr} \pnum \result -A type SMR that is a specialization of type submdspan_mapping_result for some type SM such that +A type \tcode{SMR} that is a specialization of type \tcode{submdspan_mapping_result} for some type \tcode{SM} such that \begin{itemize} \item \tcode{SM} meets the layout mapping requirements\iref{mdspan.layout.policy.reqmts}, \item \tcode{SM::extents_type} is a specialization of \tcode{extents}, @@ -26048,7 +26059,7 @@ An object \tcode{smr} of type \tcode{SMR} such that \begin{itemize} \item - \tcode{smr.mapping.extents() == submdspan_extents(m.extents(), valid_slices...)} + \tcode{smr.mapping.extents() == subextents(m.extents(), valid_slices...)} is \tcode{true};\newline and \item for each integer pack \tcode{i} @@ -26105,7 +26116,7 @@ \pnum \constraints -\tcode{sizeof...(SpliceSpecifiers)} equals \tcode{extents_type::rank()}. +\tcode{sizeof...(SliceSpecifiers)} equals \tcode{extents_type::rank()}. \pnum \mandates @@ -26121,7 +26132,7 @@ \pnum Let \tcode{sub_ext} be -the result of \tcode{submdspan_extents(extents(), slices...)} and +the result of \tcode{subextents(extents(), slices...)} and let \tcode{SubExtents} be \tcode{decl\-type(sub_ext)}. \pnum @@ -26184,14 +26195,14 @@ \begin{itemize} \item for each $k$ in the range \range{0}{SubExtents::rank() - 1}, - \tcode{SpliceSpecifiers...[$k$]} denotes \tcode{full_extent_t}; and + \tcode{SliceSpecifiers...[$k$]} denotes \tcode{full_extent_t}; and \item for $k$ equal to \tcode{SubExtents::rank() - 1}, - \tcode{SpliceSpecifiers...[$k$]} is a unit-stride slice type; + \tcode{SliceSpecifiers...[$k$]} is a unit-stride slice type; \end{itemize} \begin{note} If the above conditions are true, -all \tcode{SpliceSpecifiers...[$k$]} with $k$ larger than \tcode{SubExtents\brk{}::rank\brk{}() - 1} +all \tcode{SliceSpecifiers...[$k$]} with $k$ larger than \tcode{SubExtents\brk{}::rank\brk{}() - 1} are convertible to \tcode{index_type}. \end{note} \item @@ -26202,7 +26213,7 @@ \end{codeblock} if for a value $u$ for which $u+1$ is the smallest value $p$ larger than zero -for which \tcode{SliceSpecifiers...\brk{}[\brk{}p]} is a unit-stride slice type, +for which \tcode{SliceSpecifiers...\brk{}[\brk{}$p$]} is a unit-stride slice type, the following conditions are met: \begin{itemize} \item @@ -26279,7 +26290,7 @@ \end{codeblock} if for a value $u$ for which $\exposid{rank_} - u - 2$ is the largest value $p$ smaller than \tcode{\exposid{rank_} - 1} -for which \tcode{SliceSpecifiers...[p]} is a unit-stride slice type, +for which \tcode{SliceSpecifiers...[$p$]} is a unit-stride slice type, the following conditions are met: \begin{itemize} \item @@ -26288,7 +26299,7 @@ \item for each $k$ in the range \range{\exposid{rank_} - SubExtents::rank() - $u$ + 1}{\exposid{rank_} - $u$ - 1},\newline -\tcode{SliceSpecifiers...[p]} denotes \tcode{full_extent_t}; and +\tcode{SliceSpecifiers...[$p$]} denotes \tcode{full_extent_t}; and \item for $k$ equal to \tcode{\exposid{rank_} - SubExtents::rank() - $u$}, \tcode{SliceSpecifiers...[$k$]} is a unit-stride slice type; @@ -26449,7 +26460,7 @@ \end{codeblock} if for a value $u$ for which \tcode{\exposid{rank_} - $u$ - 2} -is the largest value p smaller than \tcode{\exposid{rank_} - 1} +is the largest value $p$ smaller than \tcode{\exposid{rank_} - 1} for which \tcode{SliceSpecifiers...[$p$]} is a unit-stride slice type, the following conditions are met: \begin{itemize} @@ -26502,7 +26513,7 @@ \pnum Let \tcode{slices} be the pack introduced by the following declaration: \begin{codeblock} -auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...); +auto [...slices] = canonical_slices(src, raw_slices...); \end{codeblock} \pnum diff --git a/source/declarations.tex b/source/declarations.tex index 510def3e41..088cfa0a6c 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -328,7 +328,7 @@ In a \grammarterm{static_assert-declaration}, the \grammarterm{constant-expression} $E$ is contextually converted to \keyword{bool} and -the converted expression shall be a constant expression\iref{expr.const}. +the converted expression shall be a constant expression\iref{expr.const.const}. If the value of the expression $E$ when so converted is \tcode{true} or the expression is evaluated in the context of a template definition, the declaration has no effect and @@ -393,11 +393,11 @@ \begin{codeblock} [] static consteval -> void @\grammarterm{compound-statement}@ () \end{codeblock} -$E$ shall be a constant expression\iref{expr.const}. +$E$ shall be a constant expression\iref{expr.const.const}. \begin{note} The evaluation of the expression corresponding to a \grammarterm{consteval-block-declaration}\iref{lex.phases} -can produce injected declarations as side effects. +can produce injected declarations\iref{expr.const.reflect} as side effects. \end{note} \begin{example} \begin{codeblock} @@ -532,10 +532,10 @@ \grammarterm{storage-class-specifier} appears in a \grammarterm{decl-specifier-seq}, there can be no \tcode{typedef} specifier in the same \grammarterm{decl-specifier-seq} and -the \grammarterm{init-declarator-list} or \grammarterm{member-declarator-list} -of the declaration shall not be -empty (except for an anonymous union declared in a namespace scope\iref{class.union.anon}). The -\grammarterm{storage-class-specifier} applies to the name declared by each +the \grammarterm{init-declarator-list} of the \grammarterm{simple-declaration} or +the \grammarterm{member-declarator-list} of the \grammarterm{member-declaration} +shall not be empty (except for an anonymous union declared in a namespace scope\iref{class.union.anon}). +The \grammarterm{storage-class-specifier} applies to the name declared by each \grammarterm{init-declarator} in the list and not to any names declared by other specifiers. \begin{note} @@ -720,7 +720,7 @@ \pnum In an \grammarterm{explicit-specifier}, the \grammarterm{constant-expression}, if supplied, shall be a -contextually converted constant expression of type \tcode{bool}\iref{expr.const}. +contextually converted constant expression of type \tcode{bool}\iref{expr.const.const}. The \grammarterm{explicit-specifier} \keyword{explicit} without a \grammarterm{constant-expression} is equivalent to the \grammarterm{explicit-specifier} \tcode{explicit(true)}. @@ -918,7 +918,7 @@ : x(a), y(x) // OK, definition { square(x); } constexpr pixel small(2); // error: \tcode{square} not defined, so \tcode{small(2)} - // not constant\iref{expr.const} so \keyword{constexpr} not satisfied + // not constant\iref{expr.const.core} so \keyword{constexpr} not satisfied constexpr void square(int &x) { // OK, definition x *= x; @@ -938,7 +938,7 @@ a \defnx{constexpr function}{specifier!\idxcode{constexpr}!function}. \begin{note} A function declared with the \keyword{consteval} specifier -is an immediate function\iref{expr.const}. +is an immediate function\iref{expr.const.imm}. \end{note} A destructor, an allocation function, or a deallocation function shall not be declared with the \keyword{consteval} specifier. @@ -992,7 +992,7 @@ \begin{itemize} \item an invocation of a constexpr function -can appear in a constant expression\iref{expr.const} and +can appear in a constant expression\iref{expr.const.core} and \item copy elision is not performed in a constant expression\iref{class.copy.elision}. \end{itemize} @@ -1026,7 +1026,7 @@ Such an object shall have literal type and shall be initialized. -A \keyword{constexpr} variable shall be constant-initializable\iref{expr.const}. +A \keyword{constexpr} variable shall be constant-initializable\iref{expr.const.init}. A \keyword{constexpr} variable that is an object, as well as any temporary to which a \keyword{constexpr} reference is bound, shall have constant destruction. @@ -1064,7 +1064,7 @@ If the specifier is applied to any declaration of a variable, it shall be applied to the initializing declaration. No diagnostic is required if no \keyword{constinit} declaration -is reachable at the point of the initializing declaration. +is reachable at the point of the initializing declaration\ifndrdef{dcl.constinit.specifier.not.reachable}. \pnum If a variable declared with the \keyword{constinit} specifier has @@ -1123,7 +1123,7 @@ \end{note} \pnum -The inline specifier indicates to +The \keyword{inline} specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at @@ -1139,7 +1139,7 @@ is declared inline in one definition domain, an inline declaration of it shall be reachable from the end of every definition domain in which it is declared; -no diagnostic is required. +no diagnostic is required\ifndrdef{dcl.inline.missing.on.definition}. \begin{note} A call to an inline function or a use of an inline variable can be encountered before its definition becomes reachable in a translation unit. @@ -1258,9 +1258,10 @@ There are two \grammarterm{cv-qualifier}{s}, \keyword{const} and \tcode{volatile}. Each \grammarterm{cv-qualifier} shall appear at most once in a \grammarterm{cv-qualifier-seq}. If a \grammarterm{cv-qualifier} appears in a -\grammarterm{decl-specifier-seq}, the \grammarterm{init-declarator-list} -or \grammarterm{member-declarator-list} of -the declaration shall not be empty. +\grammarterm{decl-specifier-seq}, +the \grammarterm{init-declarator-list} of the \grammarterm{simple-declaration} or +the \grammarterm{member-declarator-list} of the \grammarterm{member-declaration} +shall not be empty. \begin{note} \ref{basic.type.qualifier} and \ref{dcl.fct} describe how cv-qualifiers affect object and function types. @@ -1274,7 +1275,7 @@ \pnum \begin{note} Declaring a variable \keyword{const} can affect its linkage\iref{dcl.stc} -and its usability in constant expressions\iref{expr.const}. As +and its usability in constant expressions\iref{expr.const.init}. As described in~\ref{dcl.init}, the definition of an object or subobject of const-qualified type must specify an initializer or be subject to default-initialization. @@ -1295,7 +1296,7 @@ \indextext{const object!undefined change to}% Any attempt to modify\iref{expr.assign,expr.post.incr,expr.pre.incr} a const object\iref{basic.type.qualifier} during its -lifetime\iref{basic.life} results in undefined behavior. +lifetime\iref{basic.life} results in undefined behavior\ubdef{dcl.type.cv.modify.const.obj}. \begin{example} \begin{codeblock} const int ci = 3; // cv-qualified (initialized as required) @@ -1339,7 +1340,7 @@ \impldef{semantics of an access through a volatile glvalue}. If an attempt is made to access an object defined with a volatile-qualified type through the use of a non-volatile glvalue, -the behavior is undefined. +the behavior is undefined\ubdef{dcl.type.cv.access.volatile}. \pnum \indextext{type specifier!\idxcode{volatile}}% @@ -1444,8 +1445,14 @@ if any, shall be non-dependent and the \grammarterm{template-name} or \grammarterm{splice-specifier} shall designate a deducible template. -A \defnadj{deducible}{template} is either a class template or -is an alias template whose \grammarterm{defining-type-id} is of the form +A \defnadj{deducible}{template} is +\begin{itemize} +\item +a class template, +\item +a type template template parameter, or +\item +an alias template \tcode{A} whose \grammarterm{defining-type-id} is of the form \begin{ncsimplebnf} \opt{\keyword{typename}} \opt{nested-name-specifier} \opt{\keyword{template}} simple-template-id @@ -1453,7 +1460,9 @@ where the \grammarterm{nested-name-specifier} (if any) is non-dependent and the \grammarterm{template-name} of the \grammarterm{simple-template-id} -names a deducible template. +names a deducible template +other than a type template template parameter of \tcode{A}. +\end{itemize} \begin{note} An injected-class-name is never interpreted as a \grammarterm{template-name} in contexts where class template argument deduction would be performed\iref{temp.local}. @@ -1537,11 +1546,11 @@ \pnum The \grammarterm{typedef-name} $P$ in a \grammarterm{pack-index-specifier} -shall denote a pack. +shall be an \grammarterm{identifier} that denotes a pack. \pnum The \grammarterm{constant-expression} shall be -a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +a converted constant expression\iref{expr.const.const} of type \tcode{std::size_t} whose value $V$, termed the index, is such that $0 \le V < \tcode{sizeof...($P$)}$. @@ -1755,7 +1764,7 @@ \pnum If the operand of a \grammarterm{decltype-specifier} is a prvalue -and is not a (possibly parenthesized) immediate invocation\iref{expr.const}, +and is not a (possibly parenthesized) immediate invocation\iref{expr.const.imm}, the temporary materialization conversion is not applied\iref{conv.rval} and no result object is provided for the prvalue. The type of the prvalue may be incomplete or an abstract class type. @@ -2409,8 +2418,10 @@ \end{note} \pnum -Each \grammarterm{init-declarator} or \grammarterm{member-declarator} -in a declaration is analyzed separately as if it were in a declaration by itself. +Each \grammarterm{init-declarator} of a \grammarterm{simple-declaration} +or \grammarterm{member-declarator} of a \grammarterm{member-declaration} +is analyzed separately as if it were in a +\grammarterm{simple-declaration} or \grammarterm{member-declaration} by itself. \begin{note} A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is, @@ -2713,19 +2724,19 @@ \begin{codeblock} template struct X {}; template struct Y {}; -X a; // type-id +X a; // \grammarterm{type-id} X b; // expression (ill-formed) -Y c; // type-id (ill-formed) +Y c; // \grammarterm{type-id} (ill-formed) Y d; // expression void foo(signed char a) { - sizeof(int()); // type-id (ill-formed) + sizeof(int()); // \grammarterm{type-id} (ill-formed) sizeof(int(a)); // expression - sizeof(int(unsigned(a))); // type-id (ill-formed) + sizeof(int(unsigned(a))); // \grammarterm{type-id} (ill-formed) - (int())+1; // type-id (ill-formed) + (int())+1; // \grammarterm{type-id} (ill-formed) (int(a))+1; // expression - (int(unsigned(a)))+1; // type-id (ill-formed) + (int(unsigned(a)))+1; // \grammarterm{type-id} (ill-formed) } typedef struct BB { int C[2]; } *B, C; @@ -2945,7 +2956,7 @@ specifier or an \grammarterm{explicit-specifier} applies directly to each \grammarterm{declarator-id} -in a declaration; +in a \grammarterm{simple-declaration} or \grammarterm{member-declaration}; the type specified for each \grammarterm{declarator-id} depends on both the \grammarterm{decl-specifier-seq} and its \grammarterm{declarator}. @@ -3274,11 +3285,11 @@ the converted initializer is a glvalue whose type is not call-compatible\iref{expr.call} with the type of the function's definition -results in undefined behavior. +results in undefined behavior\ubdef{dcl.ref.incompatible.function}. Attempting to bind a reference to an object where the converted initializer is a glvalue through which the object is not type-accessible\iref{basic.lval} -results in undefined behavior. +results in undefined behavior\ubdef{dcl.ref.incompatible.type}. \begin{note} \indextext{reference!null}% The object designated by such a glvalue can be @@ -3292,7 +3303,7 @@ \end{note} The behavior of an evaluation of a reference\iref{expr.prim.id, expr.ref} that does not happen after\iref{intro.races} the initialization of the reference -is undefined. +is undefined\ubdef{dcl.ref.uninitialized.reference}. \begin{example} \begin{codeblock} int &f(int&); @@ -3470,7 +3481,7 @@ the type of the \grammarterm{declarator-id} in \tcode{D} is ``\placeholder{derived-declarator-type-list} array of \tcode{N} \tcode{T}''. The \grammarterm{constant-expression} -shall be a converted constant expression of type \tcode{std::size_t}\iref{expr.const}. +shall be a converted constant expression of type \tcode{std::size_t}\iref{expr.const.const}. \indextext{bound, of array}% Its value \tcode{N} specifies the \defnx{array bound}{array!bound}, i.e., the number of elements in the array; @@ -4364,7 +4375,8 @@ \end{example} For a given inline function defined in different translation units, the accumulated sets of default arguments at the end of the -translation units shall be the same; no diagnostic is required. +translation units shall be the same; +no diagnostic is required\ifndrdef{dcl.fct.default.inline.same.defaults}. If a friend declaration $D$ specifies a default argument expression, that declaration shall be a definition and there shall be no other declaration of the function or function template @@ -4381,7 +4393,7 @@ The names in the default argument are looked up, and the semantic constraints are checked, at the point where the default argument appears, except that -an immediate invocation\iref{expr.const} that +an immediate invocation\iref{expr.const.imm} that is a potentially-evaluated subexpression\iref{intro.execution} of the \grammarterm{initializer-clause} in a \grammarterm{parameter-declaration} is neither evaluated @@ -4476,7 +4488,7 @@ A default argument is evaluated each time the function is called with no argument for the corresponding parameter. \indextext{argument!scope of default}% -A parameter shall not appear as a potentially-evaluated expression +A parameter shall not appear as a potentially evaluated expression in a default argument. \indextext{argument and name hiding!default}% \begin{note} @@ -4669,7 +4681,8 @@ a declaration $F_2$ is a first declaration of \tcode{f} in another translation unit, $F_1$ and $F_2$ shall specify the same -\grammarterm{function-contract-specifier-seq}, no diagnostic required. +\grammarterm{function-contract-specifier-seq}, +no diagnostic required\ifndrdef{dcl.contract.func.mismatched.contract.specifiers}. \pnum A \grammarterm{function-contract-specifier-seq} $S_1$ @@ -5412,7 +5425,7 @@ \end{itemize} \pnum -An immediate invocation\iref{expr.const} that is not evaluated where +An immediate invocation\iref{expr.const.imm} that is not evaluated where it appears\iref{dcl.fct.default,class.mem.general} is evaluated and checked for whether it is a constant expression at the point where @@ -7092,7 +7105,7 @@ A non-user-provided defaulted function (i.e., implicitly declared or explicitly defaulted in the class) that is not defined as deleted is implicitly defined when it is odr-used\iref{basic.def.odr} -or needed for constant evaluation\iref{expr.const}. +or needed for constant evaluation\iref{expr.const.defns}. \begin{note} The implicit definition of a non-user-provided defaulted function does not bind any names. @@ -7144,7 +7157,7 @@ This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not -potentially-evaluated. For an overload set, only the +potentially evaluated. For an overload set, only the function selected by overload resolution is referenced. The implicit odr-use\iref{term.odr.use} of a virtual function does not, by itself, constitute a reference. @@ -7387,7 +7400,7 @@ The evaluation that invoked a resumption member function is called the \defnx{resumer}{coroutine!resumer}. Invoking a resumption member function for a coroutine -that is not suspended results in undefined behavior. +that is not suspended results in undefined behavior\ubdef{dcl.fct.def.coroutine.resume.not.suspended}. \pnum An implementation may need to allocate additional storage for a coroutine. @@ -7481,7 +7494,7 @@ The storage for the coroutine state is released by calling a non-array deallocation function\iref{basic.stc.dynamic.deallocation}. If \tcode{destroy} is called for a coroutine that is not suspended, the -program has undefined behavior. +program has undefined behavior\ubdef{dcl.fct.def.coroutine.destroy.not.suspended}. \pnum The deallocation function's name is looked up by searching for it in the scope of the promise type. @@ -7578,7 +7591,7 @@ shall be such that it would be valid as a redeclaration of the declaration in that header; \end{itemize} -no diagnostic is required. +no diagnostic is required\ifndrdef{dcl.fct.def.replace.bad.replacement}. \begin{note} The one-definition rule\iref{basic.def.odr} applies to the definitions of a replaceable function @@ -7724,7 +7737,7 @@ whose value is non-negative; the structured binding size of \tcode{E} is equal to that value. Let \tcode{i} be an index prvalue of type \tcode{std::size_t} -corresponding to $\tcode{v}_i$. +corresponding to $\textrm{SB}_i$. If a search for the name \tcode{get} in the scope of \tcode{E}\iref{class.member.lookup} finds at least one declaration @@ -7741,10 +7754,10 @@ is an lvalue reference and an xvalue otherwise. Given the type $\tcode{T}_i$ designated by \tcode{std::tuple_element::type} and -the type $\tcode{U}_i$ designated by -either \tcode{$\tcode{T}_i$\&} or \tcode{$\tcode{T}_i$\&\&}, -where $\tcode{U}_i$ is an lvalue reference if -the initializer is an lvalue and an rvalue reference otherwise, +the type $\tcode{U}_i$ defined +as $\tcode{T}_i$ if the initializer is a prvalue, +as ``lvalue reference to $\tcode{T}_i$'' if the initializer is an lvalue, or +as ``rvalue reference to $\tcode{T}_i$'' otherwise, variables are introduced with unique names $\tcode{r}_i$ as follows: \begin{ncbnf} @@ -7969,7 +7982,7 @@ type and the \grammarterm{constant-expression} in the \grammarterm{enumerator-definition} shall be a converted constant expression of the underlying -type\iref{expr.const}. +type\iref{expr.const.const}. If the underlying type is not fixed, the type of each enumerator prior to the closing brace is determined as @@ -7979,7 +7992,7 @@ \item If an initializer is specified for an enumerator, the \grammarterm{constant-expression} shall be an integral constant -expression\iref{expr.const}. If the expression has +expression\iref{expr.const.const}. If the expression has unscoped enumeration type, the enumerator has the underlying type of that enumeration type, otherwise it has the same type as the expression. @@ -8803,14 +8816,14 @@ \grammarterm{using-declaration} cannot refer to a destructor for a base class. \end{note} -If a constructor or assignment operator brought from a base class into a derived class -has the signature of a copy/move constructor or assignment operator -for the derived class\iref{class.copy.ctor,class.copy.assign}, -the \grammarterm{using-declaration} does not by itself -suppress the implicit declaration of the derived class member; -the member from the base class is hidden or overridden -by the implicitly-declared copy/move constructor or assignment operator -of the derived class, as described below. +\begin{note} +A \grammarterm{using-declarator} that +names a member function of a base class +does not suppress the implicit declaration of a special member function +in the derived class, +even if their signatures are the +same\iref{class.default.ctor, class.copy.ctor, class.copy.assign}. +\end{note} \pnum A \grammarterm{using-declaration} shall not name a \grammarterm{template-id}. @@ -9299,7 +9312,7 @@ \pnum If two declarations of an entity give it different language linkages, the program is ill-formed; no diagnostic is required if neither declaration -is reachable from the other. +is reachable from the other\ifndrdef{dcl.link.mismatched.language.linkage}. \indextext{consistency!linkage specification}% A redeclaration of an entity without a linkage specification inherits the language linkage of the entity and (if applicable) its type. @@ -9512,6 +9525,13 @@ \grammarterm{attribute-token}. The \grammarterm{attribute-token} determines additional requirements on the \grammarterm{attribute-argument-clause} (if any). +\pnum +\begin{note} +Unless otherwise specified, +an \grammarterm{attribute-token} specified in this document cannot be used +as a macro name\iref{cpp.replace.general}. +\end{note} + \pnum An \grammarterm{annotation} followed by an ellipsis is a pack expansion\iref{temp.variadic}. @@ -9650,7 +9670,7 @@ \grammarterm{alignment-specifier}{}, every defining declaration of that entity shall specify an equivalent alignment. -No diagnostic is required if declarations of an entity have +No diagnostic is required\ifndrdef{dcl.align.diff.translation.units} if declarations of an entity have different \grammarterm{alignment-specifier}{s} in different translation units. \begin{example} @@ -9704,7 +9724,7 @@ at the point where the assumption appears, the assumption has no effect. Otherwise, -evaluation of the assumption has runtime-undefined behavior. +evaluation of the assumption has runtime-undefined behavior\ubdef{dcl.attr.assume.false}. \pnum \begin{note} @@ -9880,7 +9900,7 @@ in one translation unit and the same function is declared without the \tcode{indeterminate} attribute on the same parameter in its first declaration in another translation unit, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{dcl.attr.indet.mismatched.declarations}. \pnum \begin{note} @@ -10081,7 +10101,7 @@ \pnum \recommended Appearance of a nodiscard call as -a potentially-evaluated discarded-value expression\iref{expr.prop} +a potentially evaluated discarded-value expression\iref{expr.prop} of non-void type is discouraged unless explicitly cast to \keyword{void}. Implementations should issue a warning in such cases. @@ -10136,12 +10156,12 @@ specify the \tcode{noreturn} attribute if any declaration of that function specifies the \tcode{noreturn} attribute. If a function is declared with the \tcode{noreturn} attribute in one translation unit and the same function is declared without the \tcode{noreturn} attribute in another -translation unit, the program is ill-formed, no diagnostic required. +translation unit, the program is ill-formed, no diagnostic required\ifndrdef{dcl.attr.noreturn.trans.unit.mismatch}. \pnum If a function \tcode{f} is invoked where \tcode{f} was previously declared with the \tcode{noreturn} attribute and that invocation eventually returns, -the behavior is runtime-undefined. +the behavior is runtime-undefined\ubdef{dcl.attr.noreturn.eventually.returns}. \begin{note} The function can terminate by throwing an exception. @@ -10221,14 +10241,26 @@ \pnum An annotation may be applied to a \grammarterm{base-specifier} or -to any declaration of a +to a declaration $D$ of a type, type alias, variable, function, namespace, enumerator, or -non-static data member. +non-static data member, +unless +\begin{itemize} +\item the host scope of $X$ differs from its target scope or +\item $X$ is a non-defining friend declaration, +\end{itemize} +where $X$ is +\begin{itemize} +\item +$D'$ if $D$ is a function parameter declaration in +a function declarator\iref{dcl.fct} of a function declaration $D'$ and +\item $D$ otherwise. +\end{itemize} \pnum Let $E$ be the expression @@ -10237,11 +10269,8 @@ the result of $E$ is the \defnadj{underlying}{constant} of the annotation. \pnum -Each \grammarterm{annotation} produces a unique annotation. - -\pnum -Substituting into an \grammarterm{annotation} -is not in the immediate context. +Each \grammarterm{annotation} or instantiation thereof +produces a unique annotation. \begin{example} \begin{codeblock} [[=1]] void f(); @@ -10255,6 +10284,16 @@ \end{example} \begin{example} \begin{codeblock} +template int x [[=1]]; +static_assert(annotations_of(^^x<0>) != annotations_of(^^x<1>)); // OK +\end{codeblock} +\end{example} + +\pnum +Substituting into an \grammarterm{annotation} +is not in the immediate context. +\begin{example} +\begin{codeblock} template [[=T::type()]] void f(T t); diff --git a/source/diagnostics.tex b/source/diagnostics.tex index be2b863f7d..fc53cdb3bf 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -495,8 +495,11 @@ \pnum If \mname{VA_ARGS} does not expand to -an \grammarterm{assignment-expression}, +a well-formed \grammarterm{assignment-expression}, the program is ill-formed. +If such an \grammarterm{assignment-expression} is ill-formed when +treated as an unevaluated operand\iref{expr.await, expr.yield}, +the program is ill-formed, no diagnostic required. \pnum The macro \tcode{assert} is redefined according to @@ -2289,8 +2292,8 @@ \indexlibrarymember{swap}{basic_stacktrace}% \begin{itemdecl} template -void swap(basic_stacktrace& a, basic_stacktrace& b) - noexcept(noexcept(a.swap(b))); + void swap(basic_stacktrace& a, basic_stacktrace& b) + noexcept(noexcept(a.swap(b))); \end{itemdecl} \begin{itemdescr} @@ -2319,7 +2322,7 @@ \indexlibrarymember{to_string}{basic_stacktrace}% \begin{itemdecl} template -string to_string(const basic_stacktrace& st); + string to_string(const basic_stacktrace& st); \end{itemdecl} \begin{itemdescr} diff --git a/source/exceptions.tex b/source/exceptions.tex index 2a4d6d7bd5..2747ac462d 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -177,7 +177,7 @@ try : i(f(ii)), d(id) { // constructor statements } catch (...) { - // handles exceptions thrown from the ctor-initializer and from the constructor statements + // handles exceptions thrown from the \grammarterm{ctor-initializer} and from the constructor statements } \end{codeblock} \end{example} @@ -556,9 +556,9 @@ \item% a standard pointer conversion\iref{conv.ptr} not involving conversions -to pointers to private or protected or ambiguous classes +to pointers to private or protected or ambiguous classes, \item% -a function pointer conversion\iref{conv.fctptr} +a function pointer conversion\iref{conv.fctptr}, \item% a qualification conversion\iref{conv.qual}, or @@ -690,7 +690,7 @@ Referring to any non-static member or base class of an object in the handler for a \grammarterm{function-try-block} -of a constructor or destructor for that object results in undefined behavior. +of a constructor or destructor for that object results in undefined behavior\ubdef{except.handle.handler.ctor.dtor}. \pnum Exceptions thrown in destructors of objects with static storage duration or in @@ -781,7 +781,7 @@ \indextext{exception specification!noexcept!constant expression and}% In a \grammarterm{noexcept-specifier}, the \grammarterm{constant-expression}, if supplied, shall be a contextually converted constant expression -of type \keyword{bool}\iref{expr.const}; +of type \keyword{bool}\iref{expr.const.const}; that constant expression is the exception specification of the function type in which the \grammarterm{noexcept-specifier} appears. A \tcode{(} token that follows \keyword{noexcept} is part of the @@ -887,7 +887,7 @@ or \item any of the immediate subexpressions\iref{intro.execution} -of $E$ is potentially-throwing. +of $E$ that is not an unevaluated operand is potentially-throwing. \end{itemize} \pnum @@ -996,7 +996,9 @@ declaration (e.g., an explicit specialization or an overriding virtual function); -\item the function is defined; or +\item the function is defined; + +\item the function is represented by a reflection; or \item the exception specification is needed for a defaulted function that calls the function. @@ -1009,10 +1011,7 @@ \end{note} \end{itemize} The exception specification of a defaulted -function is evaluated as described above only when needed; similarly, the -\grammarterm{noexcept-specifier} of a specialization -of a templated function -is instantiated only when needed. +function is evaluated as described above only when needed. % \indextext{exception specification|)} diff --git a/source/exec.tex b/source/exec.tex index ddc8be2be3..cba1458af9 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -565,7 +565,7 @@ using @\exposidnc{single-sender-value-type}@ = @\seebelownc@; // \expos template - concept @\exposconcept{single-sender}@ = @\seebelow@; // \expos + concept @\exposconcept{single-sender}@ = @\seebelow@; // \expos template<@\libconcept{sender}@ Sndr> using tag_of_t = @\seebelow@; @@ -1030,34 +1030,38 @@ \rSec2[exec.get.compl.sched]{\tcode{execution::get_completion_scheduler}} \pnum -\tcode{get_completion_scheduler<\exposid{completion-tag>}} obtains +The name \tcode{get_completion_scheduler} denotes a query object template. + +\pnum +Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; +let \exposid{completion-fn-tag} be +the associated completion tag of \exposid{completion-fn}; +let \tcode{args} be a pack of subexpressions; and +let \tcode{sndr} be a subexpression +such that \tcode{\libconcept{sender}} is \tcode{true} and +\tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(get_env(sndr))} +is well-formed and denotes a scheduler \tcode{sch}. + +\pnum +\tcode{get_completion_scheduler<\exposid{completion-fn-tag>}} obtains the completion scheduler associated with a completion tag from a sender's attributes. \pnum -The name \tcode{get_completion_scheduler} denotes a query object template. For a subexpression \tcode{q}, -the expression \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)} -is ill-formed if \exposid{completion-tag} is not one of +the expression \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q)} +is ill-formed if \exposid{completion-fn-tag} is not one of \tcode{set_value_t}, \tcode{set_error_t}, or \tcode{set_stopped_t}. -Otherwise, \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)} +Otherwise, \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q)} is expression-equivalent to \begin{codeblock} -@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(q).query(get_completion_scheduler<@\exposid{completion-tag}@>)) +@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(q).query(get_completion_scheduler<@\exposid{completion-fn-tag}@>)) \end{codeblock} \mandates If the expression above is well-formed, its type satisfies \libconcept{scheduler}. \pnum -Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; -let \exposid{completion-tag} be -the associated completion tag of \exposid{completion-fn}; -let \tcode{args} be a pack of subexpressions; and -let \tcode{sndr} be a subexpression -such that \tcode{\libconcept{sender}} is \tcode{true} and -\tcode{get_completion_scheduler<\exposid{completion-tag}>(get_env(sndr))} -is well-formed and denotes a scheduler \tcode{sch}. If an asynchronous operation created by connecting \tcode{sndr} with a receiver \tcode{rcvr} causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)}, @@ -1067,7 +1071,7 @@ \pnum The expression -\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-tag}>)} +\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-fn-tag}>)} is a core constant expression and has value \tcode{true}. \rSec2[exec.get.await.adapt]{\tcode{execution::get_await_completion_adaptor}} @@ -1732,26 +1736,9 @@ that models \libconcept{semiregular}. \end{itemdescr} +\pnum \begin{codeblock} namespace std::execution { - template - concept @\defexposconceptnc{completion-tag}@ = // \expos - @\libconcept{same_as}@ || @\libconcept{same_as}@ || @\libconcept{same_as}@; - - struct @\exposidnc{default-impls}@ { // \expos - static constexpr auto @\exposidnc{get-attrs}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{get-env}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{get-state}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{start}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{complete}@ = @\seebelownc@; // \expos - - template - static consteval void @\exposidnc{check-types}@(); // \expos - }; - - template - struct @\exposidnc{impls-for}@ : @\exposidnc{default-impls}@ {}; // \expos - template // \expos using @\exposid{state-type}@ = decay_t<@\exposid{call-result-t}@< decltype(@\exposid{impls-for}@>::@\exposid{get-state}@), Sndr, Rcvr&>>; @@ -1779,7 +1766,26 @@ Rcvr @\exposidnc{rcvr}@; // \expos @\exposidnc{state-type}@ @\exposidnc{state}@; // \expos }; +} +\end{codeblock} +\pnum +The expression in the \tcode{noexcept} clause of +the constructor of \exposid{basic-state} is +\begin{codeblock} +is_nothrow_move_constructible_v && +@\exposconcept{nothrow-callable}@>::@\exposid{get-state}@), Sndr, Rcvr&> && +(@\libconcept{same_as}@<@\exposid{state-type}@, @\exposid{get-state-result}@> || + is_nothrow_constructible_v<@\exposid{state-type}@, @\exposid{get-state-result}@>) +\end{codeblock} +where \exposid{get-state-result} is +\begin{codeblock} +@\exposid{call-result-t}@>::@\exposid{get-state}@), Sndr, Rcvr&>. +\end{codeblock} + +\pnum +\begin{codeblock} +namespace std::execution { template requires @\exposconcept{valid-specialization}@<@\exposid{env-type}@, Index, Sndr, Rcvr> struct @\exposidnc{basic-receiver}@ { // \expos @@ -1812,77 +1818,19 @@ @\exposidnc{basic-state}@* @\exposidnc{op}@; // \expos }; +} +\end{codeblock} +\begin{codeblock} +namespace std::execution { constexpr auto @\exposidnc{connect-all}@ = @\seebelownc@; // \expos template using @\exposidnc{connect-all-result}@ = @\exposidnc{call-result-t}@< // \expos decltype(@\exposid{connect-all}@), @\exposid{basic-state}@*, Sndr, @\exposid{indices-for}@>; - - template - requires @\exposconcept{valid-specialization}@<@\exposid{state-type}@, Sndr, Rcvr> && - @\exposconcept{valid-specialization}@<@\exposid{connect-all-result}@, Sndr, Rcvr> - struct @\exposidnc{basic-operation}@ : @\exposidnc{basic-state}@ { // \expos - using operation_state_concept = operation_state_t; - using @\exposidnc{tag-t}@ = tag_of_t; // \expos - - @\exposidnc{connect-all-result}@ @\exposidnc{inner-ops}@; // \expos - - @\exposidnc{basic-operation}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelownc@) // \expos - : @\exposid{basic-state}@(std::forward(sndr), std::move(rcvr)), - @\exposid{inner-ops}@(@\exposid{connect-all}@(this, std::forward(sndr), @\exposid{indices-for}@())) - {} - - void start() & noexcept { - auto& [...ops] = @\exposid{inner-ops}@; - @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{start}@(this->@\exposid{state}@, this->@\exposid{rcvr}@, ops...); - } - }; - - template - struct @\exposidnc{basic-sender}@ : @\exposidnc{product-type}@ { // \expos - using sender_concept = sender_t; - using @\exposidnc{indices-for}@ = index_sequence_for; // \expos - - decltype(auto) get_env() const noexcept { - auto& [_, data, ...child] = *this; - return @\exposid{impls-for}@::@\exposid{get-attrs}@(data, child...); - } - - template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, @\libconcept{receiver}@ Rcvr> - auto connect(this Self&& self, Rcvr rcvr) noexcept(@\seebelow@) - -> @\exposid{basic-operation}@ { - return {std::forward(self), std::move(rcvr)}; - } - - template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, class... Env> - static constexpr auto get_completion_signatures(); - }; } \end{codeblock} -\pnum -It is unspecified whether a specialization of \exposid{basic-sender} -is an aggregate. - -\pnum -An expression of type \exposid{basic-sender} is usable as -the initializer of a structured binding declaration\iref{dcl.struct.bind}. - -\pnum -The expression in the \tcode{noexcept} clause of -the constructor of \exposid{basic-state} is -\begin{codeblock} -is_nothrow_move_constructible_v && -@\exposconcept{nothrow-callable}@>::@\exposid{get-state}@), Sndr, Rcvr&> && -(@\libconcept{same_as}@<@\exposid{state-type}@, @\exposid{get-state-result}@> || - is_nothrow_constructible_v<@\exposid{state-type}@, @\exposid{get-state-result}@>) -\end{codeblock} -where \exposid{get-state-result} is -\begin{codeblock} -@\exposid{call-result-t}@>::@\exposid{get-state}@), Sndr, Rcvr&>. -\end{codeblock} - \pnum The object \exposid{connect-all} is initialized with a callable object equivalent to the following lambda: @@ -1909,6 +1857,31 @@ otherwise, \tcode{false}. \end{itemdescr} +\pnum +\begin{codeblock} +namespace std::execution { + template + requires @\exposconcept{valid-specialization}@<@\exposid{state-type}@, Sndr, Rcvr> && + @\exposconcept{valid-specialization}@<@\exposid{connect-all-result}@, Sndr, Rcvr> + struct @\exposidnc{basic-operation}@ : @\exposidnc{basic-state}@ { // \expos + using operation_state_concept = operation_state_t; + using @\exposidnc{tag-t}@ = tag_of_t; // \expos + + @\exposidnc{connect-all-result}@ @\exposidnc{inner-ops}@; // \expos + + @\exposidnc{basic-operation}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelownc@) // \expos + : @\exposid{basic-state}@(std::forward(sndr), std::move(rcvr)), + @\exposid{inner-ops}@(@\exposid{connect-all}@(this, std::forward(sndr), @\exposid{indices-for}@())) + {} + + void start() & noexcept { + auto& [...ops] = @\exposid{inner-ops}@; + @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{start}@(this->@\exposid{state}@, this->@\exposid{rcvr}@, ops...); + } + }; +} +\end{codeblock} + \pnum The expression in the \tcode{noexcept} clause of the constructor of \exposid{basic-operation} is: @@ -1918,10 +1891,22 @@ \end{codeblock} \pnum -The expression in the \tcode{noexcept} clause of -the \tcode{connect} member function of \exposid{basic-sender} is: \begin{codeblock} -is_nothrow_constructible_v<@\exposid{basic-operation}@, Self, Rcvr> +namespace std::execution { + struct @\exposidnc{default-impls}@ { // \expos + static constexpr auto @\exposidnc{get-attrs}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{get-env}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{get-state}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{start}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{complete}@ = @\seebelownc@; // \expos + + template + static consteval void @\exposidnc{check-types}@(); // \expos + }; + + template + struct @\exposidnc{impls-for}@ : @\exposidnc{default-impls}@ {}; // \expos +} \end{codeblock} \pnum @@ -2011,6 +1996,46 @@ \end{note} \end{itemdescr} +\pnum +\begin{codeblock} +namespace std::execution { + template + struct @\exposidnc{basic-sender}@ : @\exposidnc{product-type}@ { // \expos + using sender_concept = sender_t; + using @\exposidnc{indices-for}@ = index_sequence_for; // \expos + + decltype(auto) get_env() const noexcept { + auto& [_, data, ...child] = *this; + return @\exposid{impls-for}@::@\exposid{get-attrs}@(data, child...); + } + + template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, @\libconcept{receiver}@ Rcvr> + auto connect(this Self&& self, Rcvr rcvr) noexcept(@\seebelow@) + -> @\exposid{basic-operation}@ { + return {std::forward(self), std::move(rcvr)}; + } + + template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, class... Env> + static constexpr auto get_completion_signatures(); + }; +} +\end{codeblock} + +\pnum +It is unspecified whether a specialization of \exposid{basic-sender} +is an aggregate. + +\pnum +An expression of type \exposid{basic-sender} is usable as +the initializer of a structured binding declaration\iref{dcl.struct.bind}. + +\pnum +The expression in the \tcode{noexcept} clause of +the \tcode{connect} member function of \exposid{basic-sender} is: +\begin{codeblock} +is_nothrow_constructible_v<@\exposid{basic-operation}@, Self, Rcvr> +\end{codeblock} + \indexlibrarymember{get_completion_signatures}{\exposid{basic-sender}}% \begin{itemdecl} template @@ -2117,11 +2142,11 @@ otherwise if \tcode{P} is a specialization of \exposid{product-type}, returns an object of type \tcode{P} whose elements are initialized using \begin{codeblock} -make_obj_using_allocator(std::forward_like(e), @\exposid{alloc}@) +make_obj_using_allocator(@\exposid{alloc}@, std::forward_like(e)) \end{codeblock} where \tcode{e} is the corresponding element of \tcode{obj}, \item -otherwise, returns \tcode{make_obj_using_allocator

(std::forward(obj), \exposid{alloc})}. +otherwise, returns \tcode{make_obj_using_allocator

(\exposid{alloc}, std::forward(obj))}. \end{itemize} \end{itemdescr} @@ -2226,7 +2251,7 @@ model \libconcept{sender}, and \tcode{false} for types that do not. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -3071,7 +3096,7 @@ \rSec3[exec.adapt.obj]{Closure objects} -\indexlibrarymisc{\idxcode{operator|}}{pipeable sender adaptor closure objects}% +\indexlibrarymisc{\idxcode{operator"|}}{pipeable sender adaptor closure objects}% \pnum A \defnadj{pipeable}{sender adaptor closure object} is a function object that accepts one or more \libconcept{sender} arguments and returns a \libconcept{sender}. @@ -3099,7 +3124,7 @@ direct-non-list-initialized with \tcode{c}. \item Its call pattern is \tcode{d2(c2(arg))}, -where arg is the argument used in a function call expression of \tcode{e}. +where \tcode{arg} is the argument used in a function call expression of \tcode{e}. \end{itemize} The expression \tcode{c | d} is well-formed if and only if the initializations of the state entities\iref{func.def} of \tcode{e} @@ -6735,7 +6760,7 @@ Initializes \exposid{state} with \begin{codeblock} connect(std::forward(sndr), - @\exposid{awaitable-receiver}@{addressof(result), coroutine_handle::from_promise(p)}) + @\exposid{awaitable-receiver}@{addressof(@\exposid{result}@), coroutine_handle::from_promise(p)}) \end{codeblock} \end{itemdescr} @@ -7202,7 +7227,6 @@ public: using sender_concept = sender_t; - using completion_signatures = @\seebelow@; using allocator_type = @\seebelow@; using scheduler_type = @\seebelow@; using stop_source_type = @\seebelow@; @@ -7215,6 +7239,9 @@ task(task&&) noexcept; ~task(); + template + static consteval auto get_completion_signatures(); + template<@\libconcept{receiver}@ Rcvr> @\exposid{state}@ connect(Rcvr&& rcvr) &&; @@ -7256,19 +7283,6 @@ contain an element which is not of the form \tcode{set_error_t(E)} for some type \tcode{E}. -\pnum -The type alias \tcode{completion_signatures} is a specialization -of \tcode{execution::completion_signatures} with the template -arguments (in unspecified order): -\begin{itemize} -\item \tcode{set_value_t()} if \tcode{T} is \tcode{void}, -and \tcode{set_value_t(T)} otherwise; -\item template arguments of the specialization of -\tcode{execution::completion_signatures} denoted by \tcode{error_types}; -and -\item \tcode{set_stopped_t()}. -\end{itemize} - \pnum \tcode{allocator_type} shall meet the \oldconcept{Allocator} requirements. @@ -7300,6 +7314,32 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{get_completion_signatures}{task}% +\begin{itemdecl} +template + static consteval auto get_completion_signatures(); +\end{itemdecl} +\begin{itemdescr} +\pnum +Let the type \tcode{C} be a specialization +of \tcode{execution::completion_signatures} +with the template arguments (in unspecified order): +\begin{itemize} +\item +\tcode{set_value_t()} if \tcode{T} is \tcode{void}, +and \tcode{set_value_t(T)} otherwise; +\item +template arguments of the specialization of +\tcode{execution::completion_signatures} denoted by \tcode{error_types}; +and +\item \tcode{set_stopped_t()}. +\end{itemize} + +\pnum +\returns +\tcode{C()}. +\end{itemdescr} + \indexlibrarymember{connect}{task}% \begin{itemdecl} template<@\libconcept{receiver}@ Rcvr> @@ -7451,8 +7491,8 @@ template @\unspec@ yield_value(with_error error); - template - auto await_transform(A&& a); + template<@\libconcept{sender}@ Sender> + auto await_transform(Sender&& sndr); template auto await_transform(change_coroutine_scheduler sch); @@ -7543,7 +7583,7 @@ \tcode{set_value(std::move(\exposid{RCVR}(*this)))} if \tcode{is_void} is \tcode{true}, and otherwise \item - \tcode{set_value(std::move(\exposid{RCVR}(*this)), *\exposid{result})}. + \tcode{set_value(std::move(\exposid{RCVR}(*this)), std::move(*\exposid{result}))}. \end{itemize} \end{itemdescr} @@ -7571,7 +7611,7 @@ \indexlibrarymember{await_transform}{task::promise_type}% \begin{itemdecl} template<@\libconcept{sender}@ Sender> - auto await_transform(Sender&& sndr) noexcept; + auto await_transform(Sender&& sndr); \end{itemdecl} \begin{itemdescr} \pnum @@ -7585,14 +7625,14 @@ \indexlibrarymember{await_transform}{task::promise_type}% \begin{itemdecl} template - auto await_transform(change_coroutine_scheduler sch) noexcept; + auto await_transform(change_coroutine_scheduler sch); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} -return await_transform(just(exchange(@\exposid{SCHED}@(*this), scheduler_type(sch.scheduler))), *this); +return as_awaitable(just(exchange(@\exposid{SCHED}@(*this), scheduler_type(sch.scheduler))), *this); \end{codeblock} \end{itemdescr} diff --git a/source/expressions.tex b/source/expressions.tex index 869c3de36a..70485761d1 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -64,7 +64,7 @@ \indextext{zero!remainder undefined}% If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for -its type, the behavior is undefined. +its type, the behavior is undefined\ubdef{expr.expr.eval}. \begin{note} \indextext{overflow}% Treatment of division by zero, forming a remainder using a zero divisor, @@ -95,7 +95,7 @@ \end{codeblock} due to the associativity and precedence of these operators. Thus, the result of the sum \tcode{(a + 32760)} is next added to \tcode{b}, and -that result is then added to 5 which results in the value assigned to +that result is then added to \tcode{5} which results in the value assigned to \tcode{a}. On a machine in which overflows produce an exception and in which the range of values representable by an \tcode{int} is \crange{-32768}{+32767}, the implementation cannot rewrite this @@ -317,7 +317,7 @@ If a program attempts to access\iref{defns.access} the stored value of an object through a glvalue through which it is not type-accessible, -the behavior is undefined. +the behavior is undefined\ubdef{expr.basic.lvalue.strict.aliasing.violation}. \begin{footnote} The intent of this list is to specify those circumstances in which an object can or cannot be aliased. @@ -326,7 +326,7 @@ a defaulted copy/move constructor or copy/move assignment operator for a union of type \tcode{U} with a glvalue argument that does not denote an object of type \cv{}~\tcode{U} within its lifetime, -the behavior is undefined. +the behavior is undefined\ubdef{expr.basic.lvalue.union.initialization}. \begin{note} In C, an entire object of structure type can be accessed, e.g., using assignment. By contrast, \Cpp{} has no notion of accessing an object of class type @@ -345,7 +345,7 @@ If a pointer to $X$ would be valid in the context of the evaluation of the expression\iref{basic.fundamental}, the result designates $X$; -otherwise, the behavior is undefined. +otherwise, the behavior is undefined\ubdef{expr.type.reference.lifetime}. \begin{note} Before the lifetime of the reference has started or after it has ended, the behavior is undefined (see~\ref{basic.life}). @@ -686,7 +686,7 @@ \item Otherwise, if the bits in the value representation of the object to which the glvalue refers -are not valid for the object's type, the behavior is undefined. +are not valid for the object's type, the behavior is undefined\ubdef{conv.lval.valid.representation}. \begin{example} \begin{codeblock} bool f() { @@ -989,7 +989,7 @@ that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an \impldef{result of inexact floating-point conversion} choice of either of those values. -Otherwise, the behavior is undefined. +Otherwise, the behavior is undefined\ubdef{conv.double.out.of.range}. \pnum The conversions allowed as floating-point promotions are excluded from @@ -1003,7 +1003,7 @@ integer type. The conversion truncates; that is, the fractional part is discarded. \indextext{value!undefined unrepresentable integral}% -The behavior is undefined if the truncated value cannot be represented +The behavior is undefined\ubdef{conv.fpint.float.not.represented} if the truncated value cannot be represented in the destination type. \begin{note} If the destination type is \keyword{bool}, see~\ref{conv.bool}. @@ -1024,7 +1024,9 @@ exactly as a value of the floating-point type. \end{note} If the value being converted is -outside the range of values that can be represented, the behavior is undefined. If the +outside the range of values that can be represented, +the behavior is undefined\ubdef{conv.fpint.int.not.represented}. +If the source type is \keyword{bool}, the value \keyword{false} is converted to zero and the value \keyword{true} is converted to one. @@ -1077,7 +1079,7 @@ that is within its lifetime or within its period of construction or destruction\iref{class.cdtor}, -the behavior is undefined. +the behavior is undefined\ubdef{conv.ptr.virtual.base}. Otherwise, the result is a pointer to the base class subobject of the derived class object. @@ -1111,7 +1113,8 @@ \tcode{D}, a program that necessitates this conversion is ill-formed. If class \tcode{D} does not contain the original member and is not a base class of the class containing the original member, -the behavior is undefined. Otherwise, +the behavior is undefined\ubdef{conv.member.missing.member}. +Otherwise, the result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to @@ -1436,7 +1439,7 @@ \pnum If an \grammarterm{id-expression} $E$ denotes -a member $M$ of an anonymous union\iref{class.union.anon} $U$: +a variant member $M$ of an anonymous union\iref{class.union.anon} $U$: \begin{itemize} \item If $U$ is a non-static data member, @@ -2034,7 +2037,7 @@ \pnum The \grammarterm{constant-expression} shall be -a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +a converted constant expression\iref{expr.const.const} of type \tcode{std::size_t} whose value $V$, termed the index, is such that $0 \le V < \tcode{sizeof...($P$)}$. @@ -2238,7 +2241,8 @@ \end{note} \pnum -The closure type is not an aggregate type\iref{dcl.init.aggr}; +The closure type is not an aggregate type\iref{dcl.init.aggr} +and is not \tcode{final}\iref{class.pre}; it is a structural type\iref{term.structural.type} if and only if the lambda has no \grammarterm{lambda-capture}. An implementation may define the closure type differently from what @@ -2800,7 +2804,8 @@ return x+2; }(); // Updates \tcode{::x} to 6, and initializes \tcode{y} to 7. -auto z = [a = 42](int a) { return 1; }; // error: parameter and conceptual local variable have the same name +auto z = [a = 42](int a) { return 1; }; // error: parameter and conceptual local variable + // have the same name auto counter = [i=0]() mutable -> decltype(i) { // OK, returns \tcode{int} return i++; }; @@ -3091,12 +3096,13 @@ \end{example} \pnum -When the \grammarterm{lambda-expression} is evaluated, the entities that are +The entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object, and the non-static data members corresponding to the \grammarterm{init-capture}{s} are initialized as indicated by the corresponding \grammarterm{initializer} (which may be copy- or direct-initialization). (For array members, the array elements are direct-initialized in increasing subscript order.) These initializations are performed +when the \grammarterm{lambda-expression} is evaluated and in the (unspecified) order in which the non-static data members are declared. \begin{note} This ensures that the destructions will occur in the reverse order of the constructions. @@ -3318,7 +3324,7 @@ \end{note} If the substitution of template arguments into a \grammarterm{requirement} would always result in a substitution failure, the program is ill-formed; -no diagnostic required. +no diagnostic required\ifndrdef{expr.prim.req.always.sub.fail}. \begin{example} \begin{codeblock} template concept C = @@ -3389,7 +3395,7 @@ typename T::inner; // required nested member name typename S; // required valid\iref{temp.names} \grammarterm{template-id}; fails if \tcode{T::type} does not exist as a type // to which \tcode{0} can be implicitly converted - typename Ref; // required alias template substitution, fails if \tcode{T} is void + typename Ref; // required alias template substitution, fails if \tcode{T} is \tcode{void} typename [:T::r1:]; // fails if \tcode{T::r1} is not a reflection of a type typename [:T::r2:]; // fails if \tcode{T::r2} is not a reflection of a template \tcode{Z} for which \tcode{Z} is a type }; @@ -3559,7 +3565,7 @@ \end{example} \pnum -For a \grammarterm{splice-expression} of the form \grammarterm{splice-specifier}, +For a \grammarterm{splice-expression} $E$ of the form \grammarterm{splice-specifier}, let $S$ be the construct designated by \grammarterm{splice-specifier}. \begin{itemize} \item @@ -3609,10 +3615,24 @@ Otherwise, if $S$ is a variable or a structured binding, $S$ shall either have static or thread storage duration or shall inhabit a scope enclosing the expression. -The expression is an lvalue referring to the object or function $X$ -associated with or referenced by $S$, -has the same type as that of $S$, and +The expression $E$ is an lvalue referring to the object or function $X$ +associated with or referenced by $S$, and is a bit-field if and only if $X$ is a bit-field. +If $E$ appears in the predicate of a contract assertion C\iref{basic.contract} +and $S$ is +\begin{itemize} +\item +a variable declared outside of $C$ +of object type \tcode{T}, +\item +a variable declared outside of $C$ +of type ``reference to \tcode{T}'', or +\item +a structured binding of type \tcode{T} +whose corresponding variable is declared outside of $C$, +\end{itemize} +then the type of $E$ is \tcode{const T}, +otherwise $E$ has the same type as that of $S$. \begin{note} The type of a \grammarterm{splice-expression} designating a variable or structured binding of reference type @@ -3843,7 +3863,7 @@ expression whose function type is not call-compatible with the type of the called function's -definition results in undefined behavior. +definition results in undefined behavior\ubdef{expr.call.different.type}. \begin{note} This requirement allows the case when the expression has the type of a @@ -4044,7 +4064,7 @@ After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer-to-member, or class type, the program is ill-formed. -Passing a potentially-evaluated argument +Passing a potentially evaluated argument of a scoped enumeration type\iref{dcl.enum} or of a class type\iref{class} having an eligible non-trivial copy constructor\iref{special,class.copy.ctor}, @@ -4375,7 +4395,7 @@ or direct base class relationship and the result of \tcode{E1} is an object whose type is not similar\iref{conv.qual} to the type of \tcode{E1}, -the behavior is undefined. +the behavior is undefined\ubdef{expr.ref.member.not.similar}. \begin{example} \begin{codeblock} struct A { int i; }; @@ -4504,14 +4524,14 @@ that is within its lifetime or within its period of construction or destruction\iref{class.cdtor}, -the behavior is undefined. +the behavior is undefined\ubdef{expr.dynamic.cast.pointer.lifetime}. If \tcode{v} is a glvalue of type \tcode{U} and \tcode{v} does not refer to an object whose type is similar to \tcode{U} and that is within its lifetime or within its period of construction or destruction, -the behavior is undefined. +the behavior is undefined\ubdef{expr.dynamic.cast.glvalue.lifetime}. \pnum If \tcode{T} is ``pointer to \cv{} \keyword{void}'', then the result @@ -4716,7 +4736,7 @@ type ``\cvqual{cv1} \tcode{B}''. If the object of type ``\cvqual{cv1} \tcode{B}'' is actually a base class subobject of an object of type \tcode{D}, the result refers to the enclosing object of type -\tcode{D}. Otherwise, the behavior is undefined. +\tcode{D}. Otherwise, the behavior is undefined\ubdef{expr.static.cast.base.class}. \begin{example} \begin{codeblock} struct B { }; @@ -4816,7 +4836,7 @@ the value is unchanged if the original value is within the range of the enumeration values\iref{dcl.enum}, and -otherwise, the behavior is undefined. +otherwise, the behavior is undefined\ubdef{expr.static.cast.enum.outside.range}. A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration\iref{conv.fpint}, and subsequently to @@ -4831,7 +4851,7 @@ the result of the conversion is an \impldef{result of inexact floating-point conversion} choice of either of those values. -Otherwise, the behavior is undefined. +Otherwise, the behavior is undefined\ubdef{expr.static.cast.fp.outside.range}. \pnum \indextext{cast!base class}% @@ -4852,7 +4872,7 @@ ``pointer to \cvqual{cv1} \tcode{B}'' points to a \tcode{B} that is actually a base class subobject of an object of type \tcode{D}, the resulting pointer points to the enclosing object of type \tcode{D}. Otherwise, the -behavior is undefined. +behavior is undefined\ubdef{expr.static.cast.downcast.wrong.derived.type}. \pnum \indextext{cast!pointer-to-member}% @@ -4875,7 +4895,7 @@ member pointer value of the destination type. If class \tcode{B} contains the original member, or is a base class of the class containing the original member, the resulting pointer to member points -to the original member. Otherwise, the behavior is undefined. +to the original member. Otherwise, the behavior is undefined\ubdef{expr.static.cast.does.not.contain.orignal.member}. \begin{note} Although class \tcode{B} need not contain the original member, the dynamic type of the object with which indirection through the pointer @@ -5253,7 +5273,8 @@ The operator yields an lvalue of type \tcode{T}. If the operand points to an object or function, the result denotes that object or function; -otherwise, the behavior is undefined except as specified in \ref{expr.typeid}. +otherwise, the behavior is undefined except as specified in \ref{expr.typeid} +\ubdef{expr.unary.dereference}. \begin{note} Indirection through a pointer to an out-of-lifetime object is valid\iref{basic.life}. \end{note} @@ -5448,7 +5469,7 @@ \end{bnf} \pnum -An \grammarterm{await-expression} shall appear only as a potentially-evaluated +An \grammarterm{await-expression} shall appear only as a potentially evaluated expression within the \grammarterm{compound-statement} of a \grammarterm{function-body} or \grammarterm{lambda-expression}, in either case @@ -5674,6 +5695,8 @@ When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array. +The amount and placement of padding in a class type +is a property of the implementation. The result of applying \keyword{sizeof} to a potentially-overlapping subobject is the size of the type, not the size of the subobject. @@ -5718,7 +5741,7 @@ \tcode{std::size_t}. \begin{note} A \keyword{sizeof} expression -is an integral constant expression\iref{expr.const}. +is an integral constant expression\iref{expr.const.const}. The \grammarterm{typedef-name} \tcode{std::size_t} is declared in the standard header \libheader{cstddef}\iref{cstddef.syn,support.types.layout}. \end{note} @@ -5737,7 +5760,7 @@ The result is a prvalue of type \tcode{std::size_t}. \begin{note} An \keyword{alignof} expression -is an integral constant expression\iref{expr.const}. +is an integral constant expression\iref{expr.const.const}. The \grammarterm{typedef-name} \tcode{std::size_t} is declared in the standard header \libheader{cstddef}\iref{cstddef.syn,support.types.layout}. \end{note} @@ -5771,7 +5794,7 @@ \tcode{true} otherwise. \begin{note} A \grammarterm{noexcept-expression} -is an integral constant expression\iref{expr.const}. +is an integral constant expression\iref{expr.const.const}. \end{note} \indextext{expression!unary|)} @@ -5915,7 +5938,7 @@ \pnum Every \grammarterm{constant-expression} in a \grammarterm{noptr-new-declarator} shall be a converted constant -expression\iref{expr.const} of type \tcode{std::size_t} and +expression\iref{expr.const.const} of type \tcode{std::size_t} and its value shall be greater than zero. \begin{example} Given the definition \tcode{int n = 42}, @@ -5980,7 +6003,7 @@ If the value of the \grammarterm{expression} is invalid after converting to \tcode{std::size_t}: \begin{itemize} \item -if the \grammarterm{expression} is a potentially-evaluated core constant expression, +if the \grammarterm{expression} is a potentially evaluated core constant expression, the program is ill-formed; \item otherwise, an allocation function is not called; instead @@ -6004,7 +6027,7 @@ the \grammarterm{new-initializer} is a \grammarterm{braced-init-list} or a parenthesized \grammarterm{expression-list}, and the \grammarterm{expression} -is potentially-evaluated and not a core constant expression, +is potentially evaluated and not a core constant expression, the semantic constraints of initializing a hypothetical element of the array are checked as follows: \begin{itemize} @@ -6096,7 +6119,7 @@ \pnum During an evaluation of a constant expression, -a call to a replaceable allocation function is always omitted\iref{expr.const}. +a call to a replaceable allocation function is always omitted\iref{expr.const.core}. \pnum The implementation may @@ -6267,7 +6290,7 @@ \end{note} If the allocation function is a non-allocating form\iref{new.delete.placement} that returns null, -the behavior is undefined. +the behavior is undefined\ubdef{expr.new.non.allocating.null}. Otherwise, if the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of @@ -6349,23 +6372,45 @@ searching for it in the global scope. \pnum -A declaration of a placement deallocation function matches the -declaration of a placement allocation function if it has the same number -of parameters and, after parameter transformations\iref{dcl.fct}, all -parameter types except the first are identical. If -the lookup finds a single matching deallocation function, that function -will be called; otherwise, no deallocation function will be called. If -the lookup finds a usual deallocation -function -and that function, -considered as a placement deallocation function, would have been -selected as a match for the allocation function, the program is -ill-formed. For a non-placement allocation function, the normal deallocation +For a non-placement allocation function, the normal deallocation function lookup is used to find the matching deallocation function\iref{expr.delete}. +For a placement allocation function, the selection process is described below. In any case, the matching deallocation function (if any) shall be non-deleted and accessible from the point where the \grammarterm{new-expression} appears. + +\pnum +For a placement allocation function, +the matching deallocation function is selected as follows: +\begin{itemize} +\item +Each candidate that is a function template is replaced by +the function template specializations (if any) +generated using template argument deduction\iref{temp.over,temp.deduct.call} +with arguments as specified below. +\item +Each candidate whose parameter-type-list is not identical to +that of the allocation function, +ignoring their respective first parameters, +is removed from the set of candidates. +\item +Each candidate whose associated constraints (if any) +are not satisfied\iref{temp.constr.constr} +is removed from the set of candidates. +\item +If exactly one function remains, that function is selected. +\item +Otherwise, no deallocation function is selected. +\end{itemize} +If a usual deallocation function is selected, the program is ill-formed. +\begin{note} +A deallocation function with an additional trailing parameter +compared to the allocation function is never matched, +even if a default argument is provided. +\end{note} + +\pnum \begin{example} \begin{codeblock} struct S { @@ -6379,7 +6424,55 @@ S* p = new (0) S; // error: non-placement deallocation function matches // placement allocation function \end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +struct A {}; +struct T { T(); }; + +void* operator new(std::size_t s, A& al); // \#1 + +template +void operator delete(void* p, A& al); // \#2 + +A al; +T* p = new (al) T; // OK, uses \#1 and \#2. +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +template +struct A {}; +struct T { T(); }; + +void* operator new(std::size_t s, A<0>& al); // \#1 + +template +void operator delete(void* p, A& al); +void operator delete(void* p, A<0>& al); + +A<0> al; +T* p = new (al) T; // OK, uses \#1. No deallocation function is selected (two candidates remain). +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +template +struct A {}; +struct T { T(); }; + +void* operator new(std::size_t s, A<0>& al); // \#1 +template requires (I > 0) +void operator delete(void* p, A& al); +void operator delete(void* p, A<0>& al); // \#2 + +A<0> al; +T* p = new (al) T; // OK, uses \#1 and \#2. +\end{codeblock} \end{example} \pnum @@ -6439,7 +6532,7 @@ that resulted from a previous non-array \grammarterm{new-expression}, or a pointer to a base class subobject of an object created by such a \grammarterm{new-expression}. -If not, the behavior is undefined. +If not, the behavior is undefined\ubdef{expr.delete.mismatch}. \indextext{array!\idxcode{delete}}% In an array delete expression, the value of the operand of \keyword{delete} may be a null pointer value or a pointer value that resulted from @@ -6451,7 +6544,7 @@ element of the array created by that \grammarterm{new-expression}. Zero-length arrays do not have a first element. \end{footnote} -If not, the behavior is undefined. +If not, the behavior is undefined\ubdef{expr.delete.array.mismatch}. \begin{note} This means that the syntax of the \grammarterm{delete-expression} must match the type of the object allocated by \keyword{new}, not the syntax of the @@ -6472,9 +6565,9 @@ is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall -have a virtual destructor or the behavior is undefined. In an array delete +have a virtual destructor or the behavior is undefined\ubdef{expr.delete.dynamic.type.differ}. In an array delete expression, if the dynamic type of the object to be deleted is not similar to -its static type, the behavior is undefined. +its static type, the behavior is undefined\ubdef{expr.delete.dynamic.array.dynamic.type.differ}. \pnum \indextext{type!incomplete}% @@ -6702,13 +6795,13 @@ that represents a template shall not be followed by \tcode{<}. \begin{example} \begin{codeblock} -static_assert(std::meta::is_type(^^int())); // \tcode{\caret\caret} applies to the type-id \tcode{int()} +static_assert(std::meta::is_type(^^int())); // \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int()} template struct X {}; consteval bool operator<(std::meta::info, X) { return false; } consteval void g(std::meta::info r, X xv) { r == ^^int && true; // error: \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int\&\&} - r == ^^int & true; // error: \tcode{\caret\caret} applies to the type-id \tcode{int\&} + r == ^^int & true; // error: \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int\&} r == (^^int) && true; // OK r == ^^int &&&& true; // error: \tcode{int \&\&\&\&} is not a valid \grammarterm{type-id} ^^X < xv; // error: \grammarterm{reflect-expression} that represents a template is followed by \tcode{<} @@ -7039,7 +7132,7 @@ whose type is not similar to the type of \tcode{E1}, or whose most derived object does not contain the member to which -\tcode{E2} refers, the behavior is undefined. +\tcode{E2} refers, the behavior is undefined\ubdef{expr.mptr.oper.not.contain.member}. The expression \tcode{E1} is sequenced before the expression \tcode{E2}. \pnum @@ -7091,7 +7184,7 @@ operand is an lvalue and an xvalue otherwise. The result of a \tcode{.*} expression whose second operand is a pointer to a member function is a prvalue. If the second operand is the null -member pointer value\iref{conv.mem}, the behavior is undefined. +member pointer value\iref{conv.mem}, the behavior is undefined\ubdef{expr.mptr.oper.member.func.null}. \rSec2[expr.mul]{Multiplicative operators}% \indextext{expression!multiplicative operators}% @@ -7132,7 +7225,7 @@ expression by the second. \indextext{zero!undefined division by}% If the second operand of \tcode{/} or \tcode{\%} is zero, the behavior is -undefined. +undefined\ubdef{expr.mul.div.by.zero}. For integral operands, the \tcode{/} operator yields the algebraic quotient with any fractional part discarded; \begin{footnote} @@ -7140,7 +7233,7 @@ \end{footnote} if the quotient \tcode{a/b} is representable in the type of the result, \tcode{(a/b)*b + a\%b} is equal to \tcode{a}; otherwise, the behavior -of both \tcode{a/b} and \tcode{a\%b} is undefined. +of both \tcode{a/b} and \tcode{a\%b} is undefined\ubdef{expr.mul.representable.type.result}. \rSec2[expr.add]{Additive operators}% \indextext{expression!additive operators}% @@ -7219,7 +7312,7 @@ and the expression \tcode{P - J} points to the (possibly-hypothetical) array element $i - j$ of \tcode{x} if $0 \le i - j \le n$. -\item Otherwise, the behavior is undefined. +\item Otherwise, the behavior is undefined\ubdef{expr.add.out.of.bounds}. \end{itemize} \begin{note} Adding a value other than $0$ or $1$ @@ -7245,13 +7338,13 @@ of type \tcode{std::ptrdiff_t}, the behavior is undefined\iref{expr.pre}. \end{note} -\item Otherwise, the behavior is undefined. +\item Otherwise, the behavior is undefined\ubdef{expr.add.sub.diff.pointers}. \end{itemize} \pnum For addition or subtraction, if the expressions \tcode{P} or \tcode{Q} have type ``pointer to \cv{}~\tcode{T}'', where \tcode{T} and the array element type -are not similar\iref{conv.qual}, the behavior is undefined. +are not similar\iref{conv.qual}, the behavior is undefined\ubdef{expr.add.not.similar}. \begin{example} \begin{codeblock} int arr[5] = {1, 2, 3, 4, 5}; @@ -7288,7 +7381,7 @@ promotions are performed. The type of the result is that of the promoted left operand. \indextext{left shift!undefined}% -The behavior is undefined if the right operand is negative, or greater +The behavior is undefined\ubdef{expr.shift.neg.and.width} if the right operand is negative, or greater than or equal to the width of the promoted left operand. \pnum @@ -8199,7 +8292,7 @@ If the value being stored in an object is read via another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the behavior is -undefined. +undefined\ubdef{expr.assign.overlap}. \begin{note} This restriction applies to the relationship between the left and right sides of the assignment operation; it is not a @@ -8279,20 +8372,10 @@ \end{example} \end{note} -\rSec1[expr.const]{Constant expressions}% +\rSec1[expr.const]{Constant evaluation}% \indextext{expression!constant} -\pnum -Certain contexts require expressions that satisfy additional -requirements as detailed in this subclause; other contexts have different -semantics depending on whether or not an expression satisfies these requirements. -Expressions that satisfy these requirements, -assuming that copy elision\iref{class.copy.elision} is not performed, -are called constant expressions. -\begin{note} -Constant expressions can be evaluated -during translation. -\end{note} +\rSec2[expr.const.general]{General} \begin{bnf} \nontermdef{constant-expression}\br @@ -8300,182 +8383,53 @@ \end{bnf} \pnum -The constituent values and constituent references of -a variable \tcode{x} are defined as follows: -\begin{itemize} -\item -If \tcode{x} declares an object, -the constituent values and references of that object\iref{intro.object} are -constituent values and references of \tcode{x}. -\item -If \tcode{x} declares a reference, -that reference is a constituent reference of \tcode{x}. -\end{itemize} -For any constituent reference \tcode{r} of a variable \tcode{x}, -if \tcode{r} is bound to a temporary object or subobject thereof -whose lifetime is extended to that of \tcode{r}, -the constituent values and references of that temporary object -are also constituent values and references of \tcode{x}, recursively. - -\pnum -An object $o$ is \defn{constexpr-referenceable} from a point $P$ if -\begin{itemize} -\item -$o$ has static storage duration, or -\item -$o$ has automatic storage duration, and, letting \tcode{v} denote -\begin{itemize} -\item -the variable corresponding to $o$'s complete object or -\item -the variable to whose lifetime that of $o$ is extended, -\end{itemize} -the smallest scope enclosing \tcode{v} and the smallest scope enclosing $P$ -that are neither -\begin{itemize} -\item -block scopes nor -\item -function parameter scopes associated with -a \grammarterm{requirement-parameter-list} -\end{itemize} -are the same function parameter scope. -\end{itemize} -\begin{example} -\begin{codeblock} -struct A { - int m; - const int& r; -}; -void f() { - static int sx; - thread_local int tx; // \tcode{tx} is never constexpr-referenceable - int ax; - A aa = {1, 2}; - static A sa = {3, 4}; - // The objects \tcode{sx}, \tcode{ax}, and \tcode{aa.m}, \tcode{sa.m}, and the temporaries to which \tcode{aa.r} and \tcode{sa.r} are bound, are constexpr-referenceable. - auto lambda = [] { - int ay; - // The objects \tcode{sx}, \tcode{sa.m}, and \tcode{ay} (but not \tcode{ax} or \tcode{aa}), and the - // temporary to which \tcode{sa.r} is bound, are constexpr-referenceable. - }; -} -\end{codeblock} -\end{example} - -\pnum -An object or reference \tcode{x} is -\defn{constexpr-representable} at a point $P$ if, -for each constituent value of \tcode{x} that points to or past an object $o$, -and for each constituent reference of \tcode{x} that refers to an object $o$, -$o$ is constexpr-referenceable from $P$. - -\pnum -\indextext{contract evaluation semantics!ignore} -A variable \tcode{v} is \defn{constant-initializable} if -\begin{itemize} -\item -the full-expression of its initialization is a constant expression -when interpreted as a \grammarterm{constant-expression} -with all contract assertions -using the ignore evaluation semantic\iref{basic.contract.eval}, -\begin{note} -Within this evaluation, -\tcode{std::is_constant_evaluated()}\iref{meta.const.eval} -returns \keyword{true}. -\end{note} +Certain contexts require expressions that satisfy additional +requirements as detailed in \ref{expr.const}; other contexts have different +semantics depending on whether or not an expression satisfies these requirements. +Expressions that satisfy these requirements, +assuming that copy elision\iref{class.copy.elision} is not performed, +are called constant expressions. \begin{note} -The initialization, when evaluated, -can still evaluate contract assertions -with other evaluation semantics, -resulting in a diagnostic or ill-formed program -if a contract violation occurs. +Certain constant expressions are evaluated during translation\iref{lex.phases}. \end{note} -\item -immediately after the initializing declaration of \tcode{v}, -the object or reference \tcode{x} declared by \tcode{v} -is constexpr-representable, and -\item -if \tcode{x} has static or thread storage duration, -\tcode{x} is constexpr-representable at the nearest point -whose immediate scope is a namespace scope -that follows the initializing declaration of \tcode{v}. -\end{itemize} \pnum -A constant-initializable variable is \defn{constant-initialized} -if either it has an initializer or -its type is const-default-constructible\iref{dcl.init.general}. +\recommended +Implementations should provide consistent results of floating-point evaluations, +irrespective of whether the evaluation is performed +during translation or during program execution. +\begin{note} +Since this document +imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the +evaluation of a floating-point expression during translation yields the same result as the +evaluation of the same expression (or the same operations on the same values) during program +execution. \begin{example} \begin{codeblock} -void f() { - int ax = 0; // \tcode{ax} is constant-initialized - thread_local int tx = 0; // \tcode{tx} is constant-initialized - static int sx; // \tcode{sx} is not constant-initialized - static int& rss = sx; // \tcode{rss} is constant-initialized - static int& rst = tx; // \tcode{rst} is not constant-initialized - static int& rsa = ax; // \tcode{rsa} is not constant-initialized - thread_local int& rts = sx; // \tcode{rts} is constant-initialized - thread_local int& rtt = tx; // \tcode{rtt} is not constant-initialized - thread_local int& rta = ax; // \tcode{rta} is not constant-initialized - int& ras = sx; // \tcode{ras} is constant-initialized - int& rat = tx; // \tcode{rat} is not constant-initialized - int& raa = ax; // \tcode{raa} is constant-initialized +bool f() { + char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation + int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime + return sizeof(array) == size; } \end{codeblock} +It is unspecified whether the value of \tcode{f()} will be \tcode{true} or \tcode{false}. \end{example} +\end{note} -\pnum -A variable is \defn{potentially-constant} if -it is constexpr or -it has reference or non-volatile const-qualified integral or enumeration type. +\rSec2[expr.const.core]{Core constant expressions} \pnum -A constant-initialized potentially-constant variable $V$ is -\defn{usable in constant expressions} at a point $P$ if -$V$'s initializing declaration $D$ is reachable from $P$ and -\begin{itemize} -\item $V$ is constexpr, -\item $V$ is not initialized to a TU-local value, or -\item $P$ is in the same translation unit as $D$. -\end{itemize} -An object or reference is -\defn{potentially usable in constant expressions} at point $P$ if it is +\indextext{type!constexpr-unknown representation}% +A type has \defnadj{constexpr-unknown}{representation} if it \begin{itemize} +\item is a union, +\item is a pointer or pointer-to-member type, +\item is volatile-qualified, +\item is a class type with a non-static data member of reference type, or \item -the object or reference declared by a variable -that is usable in constant expressions at $P$, -\item -a temporary object of non-volatile const-qualified literal type -whose lifetime is extended\iref{class.temporary} -to that of a variable that is usable in constant expressions at $P$, -\item -a template parameter object\iref{temp.param}, -\item -a string literal object\iref{lex.string}, -\item -a non-mutable subobject of any of the above, or -\item -a reference member of any of the above. +has a base class or a non-static member whose +type has constexpr-unknown representation. \end{itemize} -An object or reference is \defn{usable in constant expressions} at point $P$ -if it is an object or reference -that is potentially usable in constant expressions at $P$ and -is constexpr-representable at $P$. -\begin{example} -\begin{codeblock} -struct A { - int* const & r; -}; -void f(int x) { - constexpr A a = {&x}; - static_assert(a.r == &x); // OK - [&] { - static_assert(a.r != nullptr); // error: \tcode{a.r} is not usable in constant expressions at this point - }(); -} -\end{codeblock} -\end{example} \pnum An expression $E$ is a \defnadj{core constant}{expression} @@ -8655,10 +8609,11 @@ with an allocated type \tcode{T}, where \begin{itemize} \item -the placement argument to the \grammarterm{new-expression} points to -an object whose type is similar to \tcode{T}\iref{conv.qual} or, -if \tcode{T} is an array type, -to the first element of an object of a type similar to \tcode{T}, and +the placement argument to the \grammarterm{new-expression} points +to an object that is transparently replaceable\iref{basic.life} by +the object created by the \grammarterm{new-expression} +or, if \tcode{T} is an array type, +to the first element of such an object, and \item the placement argument points to storage whose duration began within the evaluation of $E$; @@ -8704,6 +8659,34 @@ relational\iref{expr.rel}, or equality\iref{expr.eq} operator where the result is unspecified; +\item +an equality operator comparing pointers to potentially non-unique objects, +if the pointer values of the two operands +are associated with different evaluations\iref{basic.compound} and either +they can both point to the same offset within +the same potentially non-unique object or +one of them points to an object whose +type has constexpr-unknown representation; +\begin{example} +\begin{codeblock} +constexpr const char *f() { return "foo"; } + +constexpr bool b1 = +"foo" == "foo"; // error: non-constant +constexpr bool b2 = f() == f(); // error: non-constant +constexpr const char *p = f(); +constexpr bool b3 = p == p; // OK, value of \tcode{b3} is \tcode{true} +constexpr bool b4 = "xfoo" + 1 == "foo\0y"; // error: non-constant; string literal + // object could contain \tcode{"xfoo\textbackslash{}0y"} +constexpr bool b5 = "foo" == "bar" + 0; // OK, value of \tcode{b5} is \tcode{false} +constexpr bool b6 = (const char*)"foo" == "oo"; // OK, value of \tcode{b6} is \tcode{false}; offsets would + // be different in a merged string literal object + +constexpr std::initializer_list il1 = { (int *)nullptr }; +constexpr std::initializer_list il2 = { 0 }; +constexpr bool b7 = il1.begin() == (void *)il2.begin(); // error: non-constant +\end{codeblock} +\end{example} + \item a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or \keyword{typeid}\iref{expr.typeid} expression @@ -8926,20 +8909,85 @@ \end{codeblock} \end{example} +\rSec2[expr.const.const]{Constant expressions} + \pnum -An object \tcode{a} is said to have \defnadj{constant}{destruction} if +A \defnadj{constant}{expression} is either \begin{itemize} \item - it is not of class type nor (possibly multidimensional) array thereof, or +a glvalue core constant expression $E$ for which +\begin{itemize} \item - it is of class type or (possibly multidimensional) array thereof, - that class type has a constexpr destructor\iref{dcl.constexpr}, and - for a hypothetical expression $E$ - whose only effect is to destroy \tcode{a}, - $E$ would be a core constant expression - if the lifetime of \tcode{a} and its non-mutable subobjects - (but not its mutable subobjects) were considered to start within $E$. +$E$ refers to a non-immediate function, +\item +$E$ designates an object \tcode{o}, and +if the complete object of \tcode{o} is of consteval-only type then so is $E$, +\begin{example} +\begin{codeblock} +struct Base { }; +struct Derived : Base { std::meta::info r; }; + +consteval const Base& fn(const Derived& derived) { return derived; } + +constexpr Derived obj{.r=^^::}; // OK +constexpr const Derived& d = obj; // OK +constexpr const Base& b = fn(obj); // error: not a constant expression because \tcode{Derived} + // is a consteval-only type but \tcode{Base} is not. +\end{codeblock} +\end{example} +\end{itemize} +or +\item +a prvalue core constant expression whose result object\iref{basic.lval} (if any) +satisfies the following constraints: +\begin{itemize} +\item +each constituent reference refers to an object or a non-immediate function, +\item +no constituent value of scalar type is an indeterminate or erroneous value\iref{basic.indet}, +\item +no constituent value of pointer type is a pointer to an immediate function or +an invalid pointer value\iref{basic.compound}, +\item +no constituent value of pointer-to-member type designates an immediate function, and +\item +unless the value is of consteval-only type, +\begin{itemize} +\item +no constituent value of pointer-to-member type points to +a direct member of a consteval-only class type, +\item +no constituent value of pointer type points to or past an object +whose complete object is of consteval-only type, and +\item +no constituent reference refers to an object +whose complete object is of consteval-only type. +\end{itemize} +\end{itemize} \end{itemize} +\begin{note} +A glvalue core constant expression +that either refers to or points to an unspecified object +is not a constant expression. +\end{note} +\begin{example} +\begin{codeblock} +consteval int f() { return 42; } +consteval auto g() { return f; } +consteval int h(int (*p)() = g()) { return p(); } +constexpr int r = h(); // OK +constexpr auto e = g(); // error: a pointer to an immediate function is + // not a permitted result of a constant expression + +struct S { + int x; + constexpr S() {} +}; +int i() { + constexpr S s; // error: \tcode{s.x} has erroneous value +} +\end{codeblock} +\end{example} \pnum An \defnadj{integral constant}{expression} @@ -9005,111 +9053,199 @@ \end{note} \indextext{contextually converted constant expression of type \tcode{bool}|see{conversion, contextual}}% \indextext{conversion!contextual to constant expression of type \tcode{bool}}% + +\pnum A \term{contextually converted constant expression of type \tcode{bool}} is an expression, contextually converted to \keyword{bool}\iref{conv}, where the converted expression is a constant expression and the conversion sequence contains only the conversions above. +\rSec2[expr.const.init]{Constant initialization} + \pnum -A \defnadj{constant}{expression} is either -\begin{itemize} -\item -a glvalue core constant expression $E$ for which +The constituent values and constituent references of +a variable \tcode{x} are defined as follows: \begin{itemize} \item -$E$ refers to a non-immediate function, +If \tcode{x} declares an object, +the constituent values and references of that object\iref{intro.object} are +constituent values and references of \tcode{x}. \item -$E$ designates an object \tcode{o}, and -if the complete object of \tcode{o} is of consteval-only type then so is $E$, -\begin{example} -\begin{codeblock} -struct Base { }; -struct Derived : Base { std::meta::info r; }; - -consteval const Base& fn(const Derived& derived) { return derived; } - -constexpr Derived obj{.r=^^::}; // OK -constexpr const Derived& d = obj; // OK -constexpr const Base& b = fn(obj); // error: not a constant expression because \tcode{Derived} - // is a consteval-only type but \tcode{Base} is not. -\end{codeblock} -\end{example} +If \tcode{x} declares a reference, +that reference is a constituent reference of \tcode{x}. \end{itemize} -or -\item -a prvalue core constant expression whose result object\iref{basic.lval} -satisfies the following constraints: +For any constituent reference \tcode{r} of a variable \tcode{x}, +if \tcode{r} is bound to a temporary object or subobject thereof +whose lifetime is extended to that of \tcode{r}, +the constituent values and references of that temporary object +are also constituent values and references of \tcode{x}, recursively. + +\pnum +An object $o$ is \defn{constexpr-referenceable} from a point $P$ if \begin{itemize} \item -each constituent reference refers to an object or a non-immediate function, -\item -no constituent value of scalar type is an indeterminate or erroneous value\iref{basic.indet}, +$o$ has static storage duration, or \item -no constituent value of pointer type is a pointer to an immediate function or -an invalid pointer value\iref{basic.compound}, +$o$ has automatic storage duration, and, letting \tcode{v} denote +\begin{itemize} \item -no constituent value of pointer-to-member type designates an immediate function, and +the variable corresponding to $o$'s complete object or \item -unless the value is of consteval-only type, +the variable to whose lifetime that of $o$ is extended, +\end{itemize} +the smallest scope enclosing \tcode{v} and the smallest scope enclosing $P$ +that are neither \begin{itemize} \item -no constituent value of pointer-to-member type points to -a direct member of a consteval-only class type, -\item -no constituent value of pointer type points to or past an object -whose complete object is of consteval-only type, and +block scopes nor \item -no constituent reference refers to an object -whose complete object is of consteval-only type. -\end{itemize} +function parameter scopes associated with +a \grammarterm{requirement-parameter-list} \end{itemize} +are the same function parameter scope. \end{itemize} -\begin{note} -A glvalue core constant expression -that either refers to or points to an unspecified object -is not a constant expression. -\end{note} \begin{example} \begin{codeblock} -consteval int f() { return 42; } -consteval auto g() { return f; } -consteval int h(int (*p)() = g()) { return p(); } -constexpr int r = h(); // OK -constexpr auto e = g(); // error: a pointer to an immediate function is - // not a permitted result of a constant expression - -struct S { - int x; - constexpr S() {} +struct A { + int m; + const int& r; }; -int i() { - constexpr S s; // error: \tcode{s.x} has erroneous value +void f() { + static int sx; + thread_local int tx; // \tcode{tx} is never constexpr-referenceable + int ax; + A aa = {1, 2}; + static A sa = {3, 4}; + // The objects \tcode{sx}, \tcode{ax}, and \tcode{aa.m}, \tcode{sa.m}, and the temporaries to which \tcode{aa.r} and \tcode{sa.r} are bound, are constexpr-referenceable. + auto lambda = [] { + int ay; + // The objects \tcode{sx}, \tcode{sa.m}, and \tcode{ay} (but not \tcode{ax} or \tcode{aa}), and the + // temporary to which \tcode{sa.r} is bound, are constexpr-referenceable. + }; } \end{codeblock} \end{example} \pnum -\recommended -Implementations should provide consistent results of floating-point evaluations, -irrespective of whether the evaluation is performed -during translation or during program execution. +An object or reference \tcode{x} is +\defn{constexpr-representable} at a point $P$ if, +for each constituent value of \tcode{x} that points to or past an object $o$, +and for each constituent reference of \tcode{x} that refers to an object $o$, +$o$ is constexpr-referenceable from $P$. + +\pnum +\indextext{contract evaluation semantics!ignore} +A variable \tcode{v} is \defn{constant-initializable} if +\begin{itemize} +\item +the full-expression of its initialization is a constant expression +when interpreted as a \grammarterm{constant-expression} +with all contract assertions +using the ignore evaluation semantic\iref{basic.contract.eval}, \begin{note} -Since this document -imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the -evaluation of a floating-point expression during translation yields the same result as the -evaluation of the same expression (or the same operations on the same values) during program -execution. +In the course of this determination, +\tcode{std::is_constant_evaluated()}\iref{meta.const.eval} +has the value \keyword{true}. +\end{note} +\begin{note} +Furthermore, if the initialization is manifestly constant-evaluated, +its evaluation during translation +can still evaluate contract assertions +with other evaluation semantics, +resulting in a diagnostic or ill-formed program +if a contract violation occurs. +\end{note} +\item +immediately after the initializing declaration of \tcode{v}, +the object or reference \tcode{x} declared by \tcode{v} +is constexpr-representable, and +\item +if \tcode{x} has static or thread storage duration, +\tcode{x} is constexpr-representable at the nearest point +whose immediate scope is a namespace scope +that follows the initializing declaration of \tcode{v}. +\end{itemize} + +\pnum +A constant-initializable variable is \defn{constant-initialized} +if either it has an initializer or +its type is const-default-constructible\iref{dcl.init.general}. \begin{example} \begin{codeblock} -bool f() { - char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation - int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime - return sizeof(array) == size; +void f() { + int ax = 0; // \tcode{ax} is constant-initialized + thread_local int tx = 0; // \tcode{tx} is constant-initialized + static int sx; // \tcode{sx} is not constant-initialized + static int& rss = sx; // \tcode{rss} is constant-initialized + static int& rst = tx; // \tcode{rst} is not constant-initialized + static int& rsa = ax; // \tcode{rsa} is not constant-initialized + thread_local int& rts = sx; // \tcode{rts} is constant-initialized + thread_local int& rtt = tx; // \tcode{rtt} is not constant-initialized + thread_local int& rta = ax; // \tcode{rta} is not constant-initialized + int& ras = sx; // \tcode{ras} is constant-initialized + int& rat = tx; // \tcode{rat} is not constant-initialized + int& raa = ax; // \tcode{raa} is constant-initialized } \end{codeblock} -It is unspecified whether the value of \tcode{f()} will be \tcode{true} or \tcode{false}. \end{example} -\end{note} + +\pnum +A variable is \defn{potentially-constant} if +it is constexpr or +it has reference or non-volatile const-qualified integral or enumeration type. + +\pnum +A constant-initialized potentially-constant variable $V$ is +\defn{usable in constant expressions} at a point $P$ if +$V$'s initializing declaration $D$ is reachable from $P$ and +\begin{itemize} +\item $V$ is constexpr, +\item $V$ is not initialized to a TU-local value, or +\item $P$ is in the same translation unit as $D$. +\end{itemize} + +\pnum +An object or reference is +\defn{potentially usable in constant expressions} at point $P$ if it is +\begin{itemize} +\item +the object or reference declared by a variable +that is usable in constant expressions at $P$, +\item +a temporary object of non-volatile const-qualified literal type +whose lifetime is extended\iref{class.temporary} +to that of a variable that is usable in constant expressions at $P$, +\item +a template parameter object\iref{temp.param}, +\item +a string literal object\iref{lex.string}, +\item +a non-mutable subobject of any of the above, or +\item +a reference member of any of the above. +\end{itemize} + +\pnum +An object or reference is \defn{usable in constant expressions} at point $P$ +if it is an object or reference +that is potentially usable in constant expressions at $P$ and +is constexpr-representable at $P$. +\begin{example} +\begin{codeblock} +struct A { + int* const & r; +}; +void f(int x) { + constexpr A a = {&x}; + static_assert(a.r == &x); // OK + [&] { + static_assert(a.r != nullptr); // error: \tcode{a.r} is not usable in constant expressions at this point + }(); +} +\end{codeblock} +\end{example} + +\rSec2[expr.const.imm]{Immediate functions} \pnum An expression or conversion is in an \defn{immediate function context} @@ -9126,7 +9262,7 @@ the \grammarterm{compound-statement} of a consteval if statement\iref{stmt.if}. \end{itemize} An invocation is an \defn{immediate invocation} -if it is a potentially-evaluated explicit or implicit invocation of +if it is a potentially evaluated explicit or implicit invocation of an immediate function and is not in an immediate function context. An aggregate initialization is an immediate invocation @@ -9138,7 +9274,7 @@ \indexdefn{conversion!immediate-escalating}% \indexdefn{immediate-escalating!expression|see{expression, immediate-escalating}}% \indexdefn{immediate-escalating!conversion|see{conversion, immediate-escalating}}% -A potentially-evaluated expression or conversion is \defn{immediate-escalating} +A potentially evaluated expression or conversion is \defn{immediate-escalating} if it is neither initially in an immediate function context nor a subexpression of an immediate invocation, and \begin{itemize} @@ -9159,7 +9295,7 @@ the call operator of a lambda that is not declared with the \keyword{consteval} specifier, \item -a defaulted special member function +a non-user-provided defaulted function that is not declared with the \keyword{consteval} specifier, or \item a function that is not a prospective destructor and @@ -9192,6 +9328,8 @@ are considered to be part of the function body\iref{dcl.fct.def.general}. \end{tailnote} \end{itemize} + +\pnum \begin{example} \begin{codeblock} consteval int id(int i) { return i; } @@ -9258,52 +9396,7 @@ \end{codeblock} \end{example} -\pnum -An expression or conversion is \defn{manifestly constant-evaluated} -if it is: -\begin{itemize} -\item a \grammarterm{constant-expression}, or -\item the condition of a constexpr if statement\iref{stmt.if}, or -\item an immediate invocation, or -\item the result of substitution into an atomic constraint expression -to determine whether it is satisfied\iref{temp.constr.atomic}, or -\item the initializer of a variable -that is usable in constant expressions or -has constant initialization\iref{basic.start.static}. -\begin{footnote} -Testing this condition -can involve a trial evaluation of its initializer, -with evaluations of contract assertions -using the ignore evaluation semantic\iref{basic.contract.eval}, -as described above. -\end{footnote} -\begin{example} -\begin{codeblock} -template struct X {}; -X x; // type \tcode{X} -int y; -const int a = std::is_constant_evaluated() ? y : 1; // dynamic initialization to 1 -double z[a]; // error: \tcode{a} is not usable - // in constant expressions -const int b = std::is_constant_evaluated() ? 2 : y; // static initialization to 2 -int c = y + (std::is_constant_evaluated() ? 2 : y); // dynamic initialization to \tcode{y+y} - -constexpr int f() { - const int n = std::is_constant_evaluated() ? 13 : 17; // \tcode{n} is 13 - int m = std::is_constant_evaluated() ? 13 : 17; // \tcode{m} can be 13 or 17 (see below) - char arr[n] = {}; // char[13] - return m + sizeof(arr); -} -int p = f(); // \tcode{m} is 13; initialized to 26 -int q = p + f(); // \tcode{m} is 17 for this call; initialized to 56 -\end{codeblock} -\end{example} -\end{itemize} -\begin{note} -Except for a \grammarterm{static_assert-message}, -a manifestly constant-evaluated expression -is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. -\end{note} +\rSec2[expr.const.reflect]{Reflection} \pnum The evaluation of an expression can introduce @@ -9351,6 +9444,8 @@ there is a function parameter scope or class scope that encloses exactly one of $C$ or $P$. \end{itemize} + +\pnum \begin{example} \begin{codeblock} struct S0 { @@ -9412,39 +9507,144 @@ \end{example} \pnum -The \defn{evaluation context} is a set of program points -that determines the behavior of certain functions -used for reflection\iref{meta.reflection}. -During the evaluation $V$ of an expression $E$ as a core constant expression, -the evaluation context of an evaluation $X$\iref{intro.execution} -consists of the following points: -\begin{itemize} -\item -The program point $\textit{EVAL-PT}(L)$, -where $L$ is the point at which $E$ appears, and -where $\textit{EVAL-PT}(P)$, for a point $P$, -is a point $R$ determined as follows: +During an evaluation $V$\iref{intro.execution} of +an expression, conversion, or initialization $E$ +as a core constant expression, the +\indextext{point of!evaluation}% +\indextext{point!of evaluation}% +\indextext{evaluation!point of evaluation, during}% +\defnx{point of evaluation of $E$ during $V$}{point of evaluation during evaluation} +is the program point $P$ determined as follows: \begin{itemize} \item -If a potentially-evaluated subexpression\iref{intro.execution} of -a default member initializer $I$ appears at $P$, and -a (possibly aggregate) initialization during $V$ is using $I$, -then $R$ is $\textit{EVAL-PT}(Q)$ -where $Q$ is the point at which that initialization appears. +If $E$ is a potentially-evaluated subexpression of +a default member initializer $I$, and +$V$ is the evaluation of $E$ in the evaluation of $I$ +as an immediate subexpression of a (possibly aggregate) initialization, then +$P$ is the point of evaluation of that initialization. +\begin{tailnote} +For example, +$E$ can be an immediate invocation in a default member initializer +used by an aggregate initialization appearing at $P$. +\end{tailnote} + \item -Otherwise, if a potentially-evaluated subexpression of -a default argument\iref{dcl.fct.default} appears at $P$, and -an invocation of a function\iref{expr.call} during $V$ -is using that default argument, -then $R$ is $\textit{EVAL-PT}(Q)$ -where $Q$ is the point at which that invocation appears. +Otherwise, +if $E$ is a potentially-evaluated subexpression of +a default argument $A$\iref{dcl.fct.default}, and +$V$ is the evaluation of $E$ in the evaluation of $A$ as +an immediate subexpression of a function call\iref{expr.call}, then +$P$ is the point of evaluation of that function call. + \item -Otherwise, $R$ is $P$. +Otherwise, +$P$ is the point at which $E$ appears. \end{itemize} +During the evaluation $V$ of an expression $E$ as a core constant expression, +the \defnadj{evaluation}{context} of an evaluation $X$ +during $V$ is the set $C$ of program points determined as follows: +\begin{itemize} +\item +If $X$ occurs during the evaluation $Y$ of +a manifestly constant-evaluated expression, +where $Y$ occurs during $V$, then +$C$ is the evaluation context of $X$ during $Y$. \item -Each synthesized point corresponding to an injected declaration produced by -any evaluation sequenced before $X$\iref{intro.execution}. +Otherwise, $C$ contains + \begin{itemize} + \item + the point of evaluation of $E$ during $V$ and + each synthesized point in the instantiation context thereof and + \item + each synthesized point corresponding to an injected declaration + produced by any evaluation executed during $V$ that + is sequenced before $X$\iref{intro.execution}. + \end{itemize} \end{itemize} +\begin{note} +The evaluation context determines the behavior of certain functions +used for reflection\iref{meta.reflection}. +\end{note} +\begin{example} +\begin{codeblock} +struct S; +consteval std::size_t f(int p) { + constexpr std::size_t r = /* @\tcode{Q}@ */ + std::meta::is_complete_type(^^S) ? 1 : 2; // \#1 + if (!std::meta::is_complete_type(^^S)) { // \#2 + std::meta::define_aggregate(^^S, {}); + } + return (p > 0) ? f(p - 1) : r; +} + +consteval { + if (f(1) != 2) { + throw; // OK, not evaluated + } +} +\end{codeblock} +During each evaluation of +\tcode{std::meta::is_complete_type(\caret\caret{}S)} +at \#1\iref{meta.reflection.queries} that is +executed during the evaluation of \tcode{f(1) != 2}, +the evaluation context contains \tcode{Q}, +but does not contain the synthesized point +associated with the injected declaration of \tcode{S}. +However, the synthesized point is in the evaluation context of +\tcode{std::meta::is_complete_type(\caret\caret{}S)} at \#2 +during the evaluation of \tcode{f(0)}. +\end{example} + +\rSec2[expr.const.defns]{Further definitions} + +\pnum +An expression or conversion is \defn{manifestly constant-evaluated} +if it is +\begin{itemize} +\item a \grammarterm{constant-expression}, or +\item the condition of a constexpr if statement\iref{stmt.if}, or +\item the expression corresponding to +a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, or +\item an immediate invocation, or +\item the result of substitution into an atomic constraint expression +to determine whether it is satisfied\iref{temp.constr.atomic}, or +\item the initializer of a variable +that is usable in constant expressions or +has constant initialization\iref{basic.start.static}. +\begin{footnote} +Testing this condition +can involve a notional evaluation of its initializer, +with evaluations of contract assertions +using the ignore evaluation semantic\iref{basic.contract.eval}, +as described above. +\end{footnote} +\begin{example} +\begin{codeblock} +template struct X {}; +X x; // type \tcode{X} +int y; +const int a = std::is_constant_evaluated() ? y : 1; // dynamic initialization to 1 +double z[a]; // error: \tcode{a} is not usable + // in constant expressions +const int b = std::is_constant_evaluated() ? 2 : y; // static initialization to 2 +int c = y + (std::is_constant_evaluated() ? 2 : y); // dynamic initialization to \tcode{y+y} + +constexpr int f() { + const int n = std::is_constant_evaluated() ? 13 : 17; // \tcode{n} is 13 + int m = std::is_constant_evaluated() ? 13 : 17; // \tcode{m} can be 13 or 17 (see below) + char arr[n] = {}; // \tcode{char[13]} + return m + sizeof(arr); +} +int p = f(); // \tcode{m} is 13; initialized to 26 +int q = p + f(); // \tcode{m} is 17 for this call; initialized to 56 +\end{codeblock} +\end{example} +\end{itemize} +\begin{note} +Except for a \grammarterm{static_assert-message}, +a manifestly constant-evaluated expression +is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. +\end{note} \pnum \indextext{expression!potentially constant evaluated}% @@ -9455,7 +9655,7 @@ a manifestly constant-evaluated expression, \item -a potentially-evaluated expression\iref{basic.def.odr}, +a potentially evaluated expression\iref{basic.def.odr}, \item an immediate subexpression of a \grammarterm{braced-init-list}, @@ -9489,4 +9689,19 @@ a potentially-constant variable named by a potentially constant evaluated expression. \end{itemize} +\pnum +An object \tcode{a} is said to have \defnadj{constant}{destruction} if +\begin{itemize} +\item + it is not of class type nor (possibly multidimensional) array thereof, or +\item + it is of class type or (possibly multidimensional) array thereof, + that class type has a constexpr destructor\iref{dcl.constexpr}, and + for a hypothetical expression $E$ + whose only effect is to destroy \tcode{a}, + $E$ would be a core constant expression + if the lifetime of \tcode{a} and its non-mutable subobjects + (but not its mutable subobjects) were considered to start within $E$. +\end{itemize} + \indextext{expression|)} diff --git a/source/future.tex b/source/future.tex index 14b1e41efe..a8772f6647 100644 --- a/source/future.tex +++ b/source/future.tex @@ -929,7 +929,7 @@ \begin{itemdescr} \pnum \returns -\tcode{system_encoded_string()}. +\tcode{native_encoded_string()}. \end{itemdescr} \indexlibrarymember{generic_string}{path}% @@ -940,7 +940,7 @@ \begin{itemdescr} \pnum \returns -\tcode{generic_system_encoded_string()}. +\tcode{generic_native_encoded_string()}. \end{itemdescr} \rSec1[depr.atomics]{Deprecated atomic operations} diff --git a/source/ifndr.tex b/source/ifndr.tex new file mode 100644 index 0000000000..651918b3b6 --- /dev/null +++ b/source/ifndr.tex @@ -0,0 +1,974 @@ +%!TEX root = std.tex +\infannex{ifndr}{Enumeration of Ill-formed, No Diagnostic Required} + +\rSec1[ifndr.general]{General} + +This Annex documents ill-formed no diagnostic required behavior called out in the main standard text by +the following phrases: no diagnostic is required, no diagnostic required and no diagnostic shall be issued. +Each entry contains a title, a numeric cross reference to the main standard text, a summary of the issue +and a code example demonstrating the issue. The code examples are there to clarify the ill-formed no +diagnostic required cases and will not exhaustively cover all possible ways of invoking that case. + +\rSec1[ifndr.lex]{\ref{lex}: Lexical conventions} + +\rSec2[ifndr.lex.name]{Identifiers} + +\pnum +\ifndrxref{lex.name.reserved} +Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no +diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +int _z; // no diagnostic required, \tcode{\_z} is reserved because it starts with \tcode{\_} at global scope + +int main() { + int __x; // no diagnostic required, \tcode{\_\_x} is reserved because it starts with \tcode{\_\_} + int _Y; // no diagnostic required, \tcode{\_Y} is reserved because it starts with \tcode{\_} followed by a capital letter + int x__y; // no diagnostic required, \tcode{x\_\_y} is reserved because it contains \tcode{\_\_} +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.basic]{\ref{basic}: Basics} + +\rSec2[ifndr.basic.link]{Program and linkage} + +\pnum +\ifndrxref{basic.link.consistent.types} +Multiple declarations of an entity must be consistent, +no diagnostic is required if neither declaration is reachable +from the other. + +\pnum +\begin{example} +\begin{codeblocktu}{Module interface of \tcode{M}} +void g(); // \#1 +void h(); // \#2 +template int j; // \#3 +\end{codeblocktu} +\begin{codeblocktu}{Module interface of \tcode{N}} +int g(); // same entity as \#1, different type +namespace h {} // same entity as \#2, not both namespaces +template int j; // same entity as \#3, non-equivalent template heads +\end{codeblocktu} +\begin{codeblocktu}{Other translation unit} +import M; +import N; + // ill-formed, no diagnostic required due to the mismatched pairs above +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.basic.def.odr]{One-definition rule} + +\pnum +\ifndrxref{basic.def.odr.exact.one.def} +Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in +that program outside of a discarded statement\iref{stmt.if}; no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +auto f() { + struct A {}; + return A{}; +} +decltype(f()) g(); +auto x = g(); // ill-formed, no diagnostic required, function \tcode{g} is used but not defined + // in this translation unit, and cannot be defined in any other translation unit + // because its type does not have linkage +\end{codeblock} +\end{example} + + +\pnum +\ifndrxref{basic.def.odr.unnamed.enum.same.type} +If, at any point in the program, there is more than one reachable unnamed enumeration definition in the same scope that have +the same first enumerator name and do not have typedef names for linkage purposes\iref{dcl.enum}, those unnamed enumeration +types shall be the same; no diagnostic required. + + +\pnum +\begin{example} +\begin{codeblock} +// a.h +enum { a }; + +// b.h +enum { a, b }; + +// main.cpp +import "a.h"; +import "b.h"; +auto n = decltype(a)::b; // ill-formed no diagnostic required, more than one unnammed enum + // definition reachable at this point but their types are not the same +\end{codeblock} +\end{example} + + +\rSec2[ifndr.basic.contract]{Contract assertions} + +\rSec3[ifndr.basic.contract.general]{General} + +\pnum +\ifndrxref{basic.contract.vastart.contract.predicate} +The use of \tcode{va_start}\iref{cstdarg.syn} +within the predicate of a contract assertion +is ill-formed, no diagnostic required; + +\pnum +\begin{example} +\begin{codeblock} +void f(...) +{ + va_list args; + contract_assert((va_start(const_cast(args)), true)) // ill-formed, no diagnostic required +} +\end{codeblock} +\end{example} + +\rSec3[ifndr.basic.contract.handler]{Contract-violation handler} + +\pnum +\ifndrxref{basic.contract.handler.replacing.nonreplaceable} +On platforms where +the contract-violation handler +is not replaceable\iref{term.replaceable.function} +a function definition which could be such a replacement function +is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#include +void handle_contract_violation(const std::contract_violation& violation) {} + // ill-formed, no diagnostic required if violation-handler is not replaceable +\end{codeblock} +\end{example} + + +\rSec2[ifndr.class.member.lookup]{Member name lookup} + +\pnum +\ifndrxref{class.member.lookup.name.refers.diff.decl} +A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. + +\pnum +\begin{example} +\begin{codeblock} +struct foo {}; + +struct bar { + foo *m_foo; + + foo *foo() { + return m_foo; + } // IFNDR, foo now refers to member function foo() while previously referred to struct foo +}; +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +struct B { + static int f(); +}; + +struct D : public B { + using B::f; + int g(decltype(f()) x) { + return 0; + } // Ill-formed no diagnostic required, + // decltype(f()) will refer to B::f() here but if + // moved to the end of D would refer to D::f() + static float f(); +}; + +int main() { + D d; + + return d.g(0); +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.expr]{\ref{expr}: Expressions} + +\rSec2[ifndr.expr.prim.req]{Requires expressions} + +\pnum +\ifndrxref{expr.prim.req.always.sub.fail} +If the substitution of template arguments into a \grammarterm{requirement} +would always result in a substitution failure, the program is ill-formed; no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template concept C = requires { + new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required, the size of the allocation is + // required to be greater than zero but can never be +}; +\end{codeblock} +\end{example} + + +\rSec1[ifndr.stmt.stmt]{\ref{stmt}: Statements} + +\rSec2[ifndr.stmt.ambig]{Ambiguity resolution} + +\pnum +\ifndrxref{stmt.ambig.bound.diff.parse} +If, during +parsing, a name in a template parameter is bound differently than it would be bound during a trial parse, +the program is ill-formed. No diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +template struct A { const static int a = 20; }; + +template <> struct A<100> { using a = char; }; + +const int x = 10; + +int main() { + using T = const int; + T(x) + (100), (y)(A::a); // ill-formed no diagnostic required, during trial parse the template + // parameter \tcode{x} is bound to the global \tcode{x} later during parsing the template + // parameter \tcode{x} is bound to the local \tcode{x} declared on the same line +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.dcl.dcl]{\ref{dcl}: Declarations} + +\rSec2[ifndr.dcl.spec]{Specifiers} + +\rSec3[ifndr.dcl.constinit]{The \keyword{constinit} specifier} + +\pnum +\ifndrxref{dcl.constinit.specifier.not.reachable} +If the initializing declaration +of a variable that has the \tcode{constinit} specifier +applied to declarations not reachable from +that initializing declaration +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int x = 5; // initializing declaration of \tcode{z} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +extern constinit int x; // IFNDR, not reachable from initializing declaration of \tcode{x} +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.inline]{The \keyword{inline} specifier} + +\pnum +\ifndrxref{dcl.inline.missing.on.definition} +If a function or variable +with external or module linkage +is declared inline +but there is no inline declaration +reachable from the end of some definition domain +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline int f(); +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int f() { return 17; } + // IFNDR, end of definition domain but no inline declaration of \tcode{f} is reachable. +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.fct]{Functions} + +\rSec3[ifndr.dcl.fct.default]{Default arguments} + +\pnum +\ifndrxref{dcl.fct.default.inline.same.defaults} +If the accumulated set of default arguments +for a given inline function +with definitions in multiple translation units +is different at the end +of different translation units, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline int f(int x, int y = 2); +inline int f(int x = 1, int y); + // IFNDR, default arguments of \tcode{f} are \tcode{1} and \tcode{2} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +inline int f(int x = 3, int y = 4); + // IFNDR, default arguments of \tcode{f} are \tcode{3} and \tcode{4} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.contract]{Function contract specifiers} + +\rSec3[ifndr.dcl.contract.func]{General} + +\pnum +\ifndrxref{dcl.contract.func.mismatched.contract.specifiers} +If two different first declarations of a function +(which must therefore not be reachable from one another) +do not have equivalent function contract specifiers +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int f(int x) pre(x >= 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{f} +int g(int x) pre(x == 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{g} +int h(int x) pre(x <= 0); // OK, equivalent function contract specifiers to the other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int f(int x); // IFNDR, different function contract specifiers from the other first declaration of \tcode{f} +int g(int x) pre(x != 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{g} +int h(int y) pre(y <= 0); // OK, equivalent function contract specifiers to the other first declaration of \tcode{h} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.fct.def]{Function definitions} + +\rSec3[ifndr.dcl.fct.def.replace]{Replaceable function definitions} + +\pnum +\ifndrxref{dcl.fct.def.replace.bad.replacement} +A declaration of a replaceable function +that is inline, +not attached to the global module, +does not have \Cpp{} language linkage, +does not have the required return type, +or is not a valid redeclaration of the +corresponding declaration in a standard library header (if there is one) +then the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +extern "C" // IFNDR, wrong language linkage +inline // IFNDR, inline +int // IFNDR, wrong return type +handle_contract_violation(const std::contract::contract_violation&) {} + +void* operator new(decltype(sizeof(0)) noexcept; // IFNDR, mismatched exception specification to declaration + // in \tcode{} +\end{codeblock} +\end{example} + +\rSec2[ifndr.dcl.link]{Linkage specifications} + +\pnum +\ifndrxref{dcl.link.mismatched.language.linkage} +If two declarations of an entity +do not have the same language linkage +and neither is reachable from the other +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +\rSec2[ifndr.dcl.attr]{Attributes} + +\rSec3[ifndr.dcl.align]{Alignment specifier} + +\pnum +\ifndrxref{dcl.align.diff.translation.units} +No diagnostic is required if declarations of an entity have different \grammarterm{alignment-specifier}s in different +translation units. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +struct S { int x; } s, *p = &s; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +struct alignas(16) S; // ill-formed, no diagnostic required, definition of \tcode{S} lacks alignment +extern S* p; +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.attr.indet]{Indeterminate storage} + +\pnum +\ifndrxref{dcl.attr.indet.mismatched.declarations} +If two first declarations of a function +declare a function parameter with +mismatched uses of the \tcode{indeterminate} attribute, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int h(int x [[indeterminate]]; // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int h(int x); // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.attr.noreturn]{Noreturn attribute} + +\pnum +\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} +No diagnostic is requried if a function is declared +in one translation unit with the \tcode{noreturn} attribute +but has declarations in other translation units +without the attribute. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +[[noreturn]] void f() {} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +void f(int i); // ill-formed no diagnostic required, declared without \tcode{noreturn} +\end{codeblocktu} +\end{example} + +\rSec1[ifndr.module]{\ref{module}: Modules} + +\rSec2[ifndr.module.unit]{Module units and purviews} + +\pnum +\ifndrxref{module.unit.reserved.identifiers} +All \grammarterm{module-name}s either beginning with an identifier consisting of +std followed by zero or more digits or containing a reserved identifier\iref{lex.token} are reserved and shall not be +specified in a \grammarterm{module-declaration}; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +module std; // ill-formed no diagnostic required, \tcode{std} is not allowed at the beginning +module module; // ill-formed no diagnostic required, \tcode{module} is a reserved identifier +module std0; // ill-formed no diagnostic required, \tcode{std} followed by digits is not allowed at the beginning +export module _Test; // ill-formed no diagnostic required, \tcode{_Test} is a reserved identifier +export module te__st; // ill-formed no diagnostic required, \tcode{te__st} is a reserved identifier +\end{codeblock} +\end{example} + + +\pnum +\ifndrxref{module.unit.named.module.no.partition} +A named module shall contain exactly one module interface +unit with no module-partition, known as the primary module interface unit of the module; no diagnostic is +required. + +\pnum +\begin{example} +\begin{codeblock} +module A; +export import :Internals; // ill-formed no diagnostic required, module partition not allowed +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{module.unit.unexported.module.partition} +If a module partition of a module +that is a module interface unit +but is not directly or indirectly exported +by the primary module interface unit\iref{module.import}, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M; // primary module interface unit +export import :A; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +export module M:A; // OK, directly exported by \tcode{M} +export import :B; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#3} +export module M:B; // OK, indirectly exported by \tcode{M} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#4} +export module M:C; // IFNDR, not directl or indirectly exported by \tcode{M} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.module.private.frag]{Private module fragment} + +\pnum +\ifndrxref{module.private.frag.other.module.units} +If a module has a private module fragment +and there is another module unit of that module, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M; +module :private; // private module fragment +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +module M:A; // IFNDR, partition of \tcode{M} with private module fragment +\end{codeblocktu} +\end{example} + + +\rSec1[ifndr.class]{\ref{class}: Classes} + +\rSec2[ifndr.class.base.init]{Initializing bases and members} + +\pnum +\ifndrxref{class.base.init.delegate.itself} +If a constructor delegates to itself directly or indirectly, +the program is ill-formed, no diagnostic required + +\pnum +\begin{example} +\begin{codeblock} +struct C { + C( int ) { } // \#1: non-delegating constructor + C(): C(42) { } // \#2: delegates to \#1 + C( char c ) : C(42.0) { } // \#3: ill-formed no diagnostic required due to recursion with \#4 + C( double d ) : C('a') { } // \#4: ill-formed no diagnostic required due to recursion with \#3 +}; +\end{codeblock} +\end{example} + + +\rSec2[ifndr.class.virtual]{Virtual functions} + +\pnum +\ifndrxref{class.virtual.pure.or.defined} +A virtual function must be declared pure or defined, no diagnostic required. A virtual function declared pure can be defined +out of line + +\pnum +\begin{example} +\begin{codeblock} +class A { + virtual void f(); +}; + +int main() { + A a; // ill-formed no diagnostic required, virtual function that is not pure but has not definition +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.over]{\ref{over}: Overloading} + +\rSec2[ifndr.over.literal]{User-defined literals} + +\pnum +\ifndrxref{over.literal.reserved} +Some literal suffix identifiers are +reserved for future standardization. A declaration whose literal-operator-id uses such a literal +suffix identifier is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +float operator ""E(const char*); // ill-formed, no diagnostic required, reserved literal suffix +double operator"" _Bq(long double); // ill-formed, no diagnostic required, // uses the reserved identifier \tcode{_Bq} +\end{codeblock} +\end{example} + +\rSec1[ifndr.temp]{\ref{temp}: Templates} + +\rSec2[ifndr.temp.pre]{Preamble} + +\pnum +\ifndrxref{temp.pre.reach.def} +A definition of a function template, member function of a class template, variable template, or static data +member of a class template shall be reachable from the end of every definition domain\iref{basic.def.odr} in which it is +implicitly instantiated\iref{temp.inst} unless the corresponding specialization is explicitly instantiated\iref{temp.explicit} in +some translation unit; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +// a.h +template +void f(); + +// a.cpp +#include "a.h" +int main() { + f(); // ill-formed no diagnostic required, function template implicity + // instantiated but not reachable definition +} +\end{codeblock} +\end{example} + + +\rSec2[ifndr.temp.arg.template]{Template template arguments} + +\pnum +\ifndrxref{temp.arg.template.sat.constraints} +Any partial specializations\iref{temp.spec.partial} associated with the primary template are considered when a specialization +based on the template template-parameter is instantiated. If a specialization is not reachable from the point of +instantiation, and it would have been selected had it been reachable, the program is ill-formed, no diagnostic +required. + +\pnum +\begin{example} +\begin{codeblock} +template struct A { + int x; +}; + +template class V> struct C { + V y; + V z; +}; + +C c; + +// Ill-formed no diagnostic required, specialization is not reachable from point +// of instantiation above and it would have been selected if it had +template struct A { + long x; +}; +\end{codeblock} +\end{example} + + +\rSec2[ifndr.constr.atomic]{Atomic constraints} + +\pnum +\ifndrxref{temp.constr.atomic.equiv.but.not.equiv} +If the validity or meaning of the program depends on whether two atomic +constraints are equivalent, +and they are functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template void f2() +requires Add1<2 * N>; +template int f2() +requires Add1 && true; +void h2() { +f2<0>(); // ill-formed, no diagnostic required, + // requires determination of subsumption between atomic constraints that are + // functionally equivalent but not equivalent +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{temp.constr.atomic.sat.result.diff} +If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template +concept Complete = sizeof(T) == sizeof(T); + +struct A; +static_assert(!Complete); // \#1 +struct A {}; +static_assert(Complete); // ill-formed no diagnostic required, satisfaction + // result differs from point \#1 +\end{codeblock} +\end{example} + + +\rSec2[ifndr.temp.constr.normal]{Constraint normalization} + +\pnum +\ifndrxref{temp.constr.normal.invalid} +If during constraint normalization any such substitution results in an invalid type or expression, +the program is ill-formed; no diagnostic is required + +\pnum +\begin{example} +\begin{codeblock} +template concept A = T::value || true; +template concept B = A; +template concept C = B; // Ill-formed no diagnostic required, it + // would form the invalid type V\&* in the parameter mapping +\end{codeblock} +\end{example} + + +%TODO: There are two earlier "no diagnostic requireds" in this section, i am +% not sure if they a really are worth calling distinct cases of ifndr. + +\rSec2[ifndr.temp.spec.partial]{Partial specialization} + +\pnum +\ifndrxref{temp.spec.partial.general.partial.reachable} +A partial specialization shall be reachable from any use of a template specialization that would make use of the +partial specialization as the result of an implicit or explicit instantiation; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +template class X{ +public: + void foo(){}; +}; + +template class X; // ill-formed no diagnostic required, explicit instantiation + // and partial specialization is not reachable + +template class X{ +public: + void baz(); +}; +\end{codeblock} +\end{example} + + +\rSec2[ifndr.temp.names]{Names of template specializations} + + +\rSec2[ifndr.temp.fct]{Function templates} + +\rSec3[ifndr.temp.over.link]{Function template overloading} + +\pnum +\ifndrxref{temp.over.link.equiv.not.equiv} +If the validity or meaning of the program depends on whether two constructs are equivalent, and they are +functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template +struct A{}; + +// ill-formed, no diagnostic required, the following declarations are functionally equivalent but not equivalent +template void f(A, A); +template void f(A, A); +\end{codeblock} +\end{example} + +\rSec2[ifndr.temp.res]{Name resolution} + +\rSec3[ifndr.temp.res.general]{General} + +\pnum +\ifndrxref{temp.res.general.default.but.not.found} +If the validity or meaning of the program would be changed by considering a default argument or default +template argument introduced in a declaration that is reachable from the point of instantiation of a +specialization\iref{temp.point} but is not found by lookup for the specialization, the program is ill-formed, no +diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: SY, JMB: We need to produce an example for this case. + +\rSec3[ifndr.temp.dep.res]{Dependent name resolution} + +\rSec4[ifndr.temp.point]{Point of instantiation} + +\pnum +\ifndrxref{temp.point.diff.pt.diff.meaning} +A specialization for a class template has at most one point of instantiation within a translation unit. A +specialization for any template may have points of instantiation in multiple translation units. If two different +points of instantiation give a template specialization different meanings according to the one-definition +rule (6.3), the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +// a.h +#include + +template +struct is_complete : std::false_type {}; + +template +struct is_complete> : std::true_type {}; + +// a.cpp +#include "a.h" +struct X; +static_assert(!is_complete::value); + +// b.cpp +#include "a.h" +struct X { }; +static_assert(is_complete::value); +\end{codeblock} +\end{example} + +\rSec4[ifndr.temp.dep.candidate]{Candidate functions} + +\pnum +\ifndrxref{temp.dep.candidate.different.lookup.different} +If considering all function declarations +with external linkage +in the associated namespaces in all translations +would make a dependent call\iref{temp.dep} ill-formed +or find a better match, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + + +\rSec3[ifndr.temp.explicit]{Explicit instantiation} + +\pnum +\ifndrxref{temp.explicit.decl.implicit.inst} +An entity that is the subject of +an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit +instantiation\iref{temp.inst} in the translation unit shall be the subject of an explicit instantiation definition +somewhere in the program; otherwise the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +// Explicit instantiation declaration +extern template class std::vector; + +int main() { + std::cout << std::vector().size(); // ill-formed no diagnostic required, implicit instantiation + // but no explicit instantiation definition +} +\end{codeblock} +\end{example} + +\rSec3[ifndr.temp.expl.spec]{Explicit specialization} + +\pnum +\ifndrxref{temp.expl.spec.unreachable.declaration} +If an implicit instantiation of a template would occur +and there is an unreachable explicit specialization +that would have matched, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + +\pnum +\ifndrxref{temp.expl.spec.missing.definition} +If an explicit specialization of a template is +declared but there is no definition provided +for that specialization, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + + +\rSec2[ifndr.temp.deduct]{Template argument deduction} + +\rSec3[ifndr.temp.deduct.general]{General} + +\pnum +\ifndrxref{temp.deduct.general.diff.order} +If substitution +into different declarations +of the same function template +would cause template instantiations to occur +in a different order or not at all, +the program is ill-formed; no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template struct A { using X = typename T::X; }; +template typename T::X h(typename A::X); // \#1 +template auto h(typename A::X) -> typename T::X; // redeclaration \#2 +template void h(...) { } + +void x() { + h(0); // ill-formed, no diagnostic required + // \#1 fails to find \tcode{T::X} and instantiates nothing + // \#2 instantiates \tcode{A} +} +\end{codeblock} +\end{example} + +%TODO: JMB: Someone should confirm that the comments correctly describe why +%this example is ill-formed. + + +\rSec1[ifndr.cpp]{\ref{cpp}: Preprocessing directives} + +\rSec2[ifndr.cpp.cond]{Conditional inclusion} + +\pnum +\ifndrxref{cpp.cond.defined.after.macro} +If the expansion of a macro produces the preprocessing token \tcode{defined} +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#define A defined +#if A // Ill-formed no diagnostic required, \tcode{defined} is generated by macro replacement + // in controlling expression +#endif +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{cpp.cond.defined.malformed} +If the \tcode{defined} unary operator is used when it +does not match +one of the specified grammatical forms, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#define A +#define B A) +#if defined ( B // Ill-formed no diagnostic required, unary operator \tcode{defined} did not match + // valid form before replacement +#endif +\end{codeblock} +\end{example} + +\rSec2[ifndr.cpp.include]{Source file inclusion} + +\pnum +\ifndrxref{cpp.include.malformed.headername} +If the \grammarterm{header-name-tokens} after +an \tcode{include} directive +cannot be formed into a \grammarterm{header-name} +(with implementation-defined treatment of whitespace), +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#include `` // Ill-formed no diagnoatic required, does not match one of the two allowable forms +\end{codeblock} +\end{example} diff --git a/source/intro.tex b/source/intro.tex index 5cb98d2101..3e24d06dce 100644 --- a/source/intro.tex +++ b/source/intro.tex @@ -213,7 +213,7 @@ \definition{constant evaluation}{defns.const.eval} \indexdefn{constant evaluation}% evaluation that is performed as part of evaluating an expression -as a core constant expression\iref{expr.const} +as a core constant expression\iref{expr.const.core} \definition{constant subexpression}{defns.const.subexpr} \indexdefn{constant subexpression}% @@ -265,7 +265,7 @@ Erroneous behavior is always the consequence of incorrect program code. Implementations are allowed, but not required, to diagnose it\iref{intro.compliance.general}. -Evaluation of a constant expression\iref{expr.const} +Evaluation of a constant expression\iref{expr.const.core} never exhibits behavior specified as erroneous in \ref{intro} through \ref{\lastcorechapter}. \end{defnote} @@ -462,6 +462,11 @@ \end{codeblock} \end{example} +\indexdefn{property!of the implementation}% +\definition{property of the implementation}{defns.impl.prop} +behavior, for a well-formed program\iref{defns.well.formed} +construct and correct data, that depends on the implementation + \definition{referenceable type}{defns.referenceable} \indexdefn{type!referenceable}% type that is either an @@ -525,7 +530,7 @@ it is \impldef{whether runtime-undefined behavior results in the expression being deemed non-constant} whether runtime-undefined behavior results in the expression being deemed non-constant -(as specified in~\ref{expr.const}) and +(as specified in~\ref{expr.const.core}) and \item runtime-undefined behavior has no other effect. \end{itemize} @@ -670,7 +675,7 @@ \termref{defns.diagnostic}{diagnostic message}{}), to terminating a translation or execution (with the issuance of a diagnostic message). Many incorrect program constructs do not engender undefined behavior; they are required to be diagnosed. -Evaluation of a constant expression\iref{expr.const} never exhibits behavior explicitly +Evaluation of a constant expression\iref{expr.const.core} never exhibits behavior explicitly specified as undefined in \ref{intro} through \ref{\lastcorechapter}. \end{defnote} @@ -782,7 +787,7 @@ \item a contract assertion\iref{basic.contract.eval} evaluated with a checking semantic -in a manifestly constant-evaluated context\iref{expr.const} +in a manifestly constant-evaluated context\iref{expr.const.defns} resulting in a contract violation, \end{itemize} a conforming implementation @@ -805,7 +810,7 @@ a \grammarterm{static_assert-declaration} that fails\iref{dcl.pre}, or \item a contract assertion evaluated with a terminating semantic\iref{basic.contract.eval} -in a manifestly constant-evaluated context\iref{expr.const} +in a manifestly constant-evaluated context\iref{expr.const.defns} resulting in a contract violation. \end{itemize} @@ -860,6 +865,7 @@ results in a contract violation\iref{structure.specifications}. \pnum +\recommended An implementation is encouraged to document its limitations in the size or complexity of the programs it can successfully process, if possible and where known. @@ -919,10 +925,14 @@ \pnum \indextext{behavior!implementation-defined}% -Certain aspects and operations of the abstract machine are described in this +Certain aspects and operations of the abstract machine +constitute the parameters of the abstract machine and +are described in this document as implementation-defined behavior (for example, -\tcode{sizeof(int)}). These constitute the parameters of the abstract machine. -Each implementation shall include documentation describing its characteristics +\tcode{sizeof(int)}) +or as properties of the implementation (for example, padding in class types). +For implementation-defined behavior, +each implementation shall include documentation describing its characteristics and behavior in these respects. \begin{footnote} This documentation also includes diff --git a/source/iostreams.tex b/source/iostreams.tex index d5d867ad11..a430c8dc69 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -363,17 +363,19 @@ serves as a base class for class templates \tcode{basic_stringbuf}, \tcode{basic_filebuf}, +\tcode{basic_syncbuf}, and -\tcode{basic_syncbuf}. +\tcode{basic_spanbuf}. \pnum The class template specialization \tcode{basic_istream} serves as a base class for class templates -\tcode{basic_istringstream} +\tcode{basic_istringstream}, +\tcode{basic_ifstream}, and -\tcode{basic_ifstream}. +\tcode{basic_ispanstream}. \pnum The @@ -382,17 +384,19 @@ serves as a base class for class templates \tcode{basic_ostringstream}, \tcode{basic_ofstream}, +\tcode{basic_osyncstream}, and -\tcode{basic_osyncstream}. +\tcode{basic_ospanstream}. \pnum The class template specialization \tcode{basic_iostream} serves as a base class for class templates -\tcode{basic_stringstream} +\tcode{basic_stringstream}, +\tcode{basic_fstream}, and -\tcode{basic_fstream}. +\tcode{basic_spanstream}. \pnum \begin{note} @@ -404,9 +408,8 @@ \end{note} \pnum -Other \grammarterm{typedef-name}{s} define instances of -class templates -specialized for +Other \grammarterm{typedef-name}{s} designate +class template specializations for \tcode{char} or \keyword{wchar_t} @@ -5651,7 +5654,7 @@ calls \tcode{setstate(badbit)} (which may throw -\tcode{ios_base::failure}\iref{iostate.flags}, +\tcode{ios_base::failure}\iref{iostate.flags}), and returns \tcode{-1}. Otherwise, returns zero. @@ -9328,7 +9331,7 @@ template void str(const T& t); - private: + private: basic_stringbuf @\exposid{sb}@; // \expos }; } @@ -13714,7 +13717,7 @@ basic_string string(const Allocator& a = Allocator()) const; std::string display_string() const; - std::string system_encoded_string() const; + std::string native_encoded_string() const; std::wstring wstring() const; std::u8string u8string() const; std::u16string u16string() const; @@ -13726,7 +13729,7 @@ basic_string generic_string(const Allocator& a = Allocator()) const; std::string generic_display_string() const; - std::string generic_system_encoded_string() const; + std::string generic_native_encoded_string() const; std::wstring generic_wstring() const; std::u8string generic_u8string() const; std::u16string generic_u16string() const; @@ -14048,7 +14051,8 @@ so no conversion from \tcode{char} value type arguments or to \tcode{char} value type return values is performed. For Windows-based operating systems, the -native ordinary encoding is determined by calling a Windows API function. +native ordinary encoding is determined by +the current locale encoding and the Windows \tcode{AreFileApisANSI} function. \end{note} \begin{note} This results in behavior identical to other C and \Cpp{} @@ -14701,7 +14705,7 @@ \indexlibrarymember{u16string}{path}% \indexlibrarymember{u32string}{path}% \begin{itemdecl} -std::string system_encoded_string() const; +std::string native_encoded_string() const; std::wstring wstring() const; std::u8string u8string() const; std::u16string u16string() const; @@ -14776,7 +14780,7 @@ \indexlibrarymember{generic_u16string}{path}% \indexlibrarymember{generic_u32string}{path}% \begin{itemdecl} -std::string generic_system_encoded_string() const; +std::string generic_native_encoded_string() const; std::wstring generic_wstring() const; std::u8string generic_u8string() const; std::u16string generic_u16string() const; @@ -17685,7 +17689,7 @@ \begin{itemdecl} void filesystem::create_hard_link(const path& to, const path& new_hard_link); void filesystem::create_hard_link(const path& to, const path& new_hard_link, - error_code& ec) noexcept; + error_code& ec) noexcept; \end{itemdecl} \begin{itemdescr} @@ -17720,7 +17724,7 @@ \begin{itemdecl} void filesystem::create_symlink(const path& to, const path& new_symlink); void filesystem::create_symlink(const path& to, const path& new_symlink, - error_code& ec) noexcept; + error_code& ec) noexcept; \end{itemdecl} \begin{itemdescr} @@ -18276,7 +18280,7 @@ \begin{itemdecl} void filesystem::last_write_time(const path& p, file_time_type new_time); void filesystem::last_write_time(const path& p, file_time_type new_time, - error_code& ec) noexcept; + error_code& ec) noexcept; \end{itemdecl} \begin{itemdescr} diff --git a/source/iterators.tex b/source/iterators.tex index 7a8c8b6ff7..7d97d4395a 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -1675,6 +1675,7 @@ template concept @\deflibconcept{sentinel_for}@ = @\libconcept{semiregular}@ && + !@\exposid{is-integer-like}@ && @\libconcept{input_or_output_iterator}@ && @\exposconcept{weakly-equality-comparable-with}@; // see \ref{concept.equalitycomparable} \end{itemdecl} @@ -1752,7 +1753,7 @@ for cv-unqualified non-array object types \tcode{S} and \tcode{I} if \tcode{S} and/or \tcode{I} is a program-defined type. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -6591,7 +6592,7 @@ \pnum \remarks If the initializer \tcode{T()} in the declaration \tcode{auto x = T();} -is a constant initializer\iref{expr.const}, +is a constant initializer\iref{expr.const.init}, then these constructors are \keyword{constexpr} constructors. \end{itemdescr} diff --git a/source/lex.tex b/source/lex.tex index 80f2e8c1e6..b15fc493bf 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -42,6 +42,13 @@ Translation units can be separately translated and then later linked to produce an executable program\iref{basic.link}. \end{note} +\begin{note} +Source files, translation units, and translated translation units +need not necessarily be stored as files, nor need there be any one-to-one +correspondence between these entities and any external representation. +The description is conceptual only, +and does not specify any particular implementation. +\end{note} \indextext{compilation!separate|)} \rSec1[lex.phases]{Phases of translation}% @@ -192,13 +199,6 @@ dependency\iref{module.unit,module.import} are required to be available. \begin{note} -Source files, translation -units and translated translation units need not necessarily be stored as -files, nor need there be any one-to-one correspondence between these -entities and any external representation. The description is conceptual -only, and does not specify any particular implementation. -\end{note} -\begin{note} Previously translated translation units can be preserved individually or in libraries. The separate translation units of a program communicate\iref{basic.link} by (for example) calls to functions whose names have external or module linkage, @@ -227,11 +227,14 @@ that it be instantiated at an earlier point\iref{temp.inst}. \end{note} -Each instantiation results in new program constructs. The program is ill-formed if any instantiation fails. During the analysis and translation of tokens, -certain expressions are evaluated\iref{expr.const}. +each manifestly constant-evaluated expression is evaluated\iref{expr.const}. +The values of these expressions affect +the types named and reflection values used in the program and +thus the syntactic analysis. +Their evaluation also can produce side effects that affect that analysis. Constructs appearing at a program point $P$ are analyzed in a context where each side effect of evaluating an expression $E$ as a full-expression is complete if and only if @@ -261,19 +264,19 @@ void fn() { /* @$p_1$@ */ Incomplete i; // OK } - }; /* @$p_2$@ */ + } /* @$p_2$@ */ ; consteval { define_aggregate(^^Incomplete, {}); } -}; /* @$p_3$@ */ +} /* @$p_3$@ */ ; \end{codeblock} Constructs at $p_1$ are analyzed in a context -where the side effect of the call to \tcode{define_aggregate} is evaluated +where the side effect of the call to \tcode{define_aggregate} is complete because \begin{itemize} \item -$E$ is the expression corresponding to a consteval block, and +the call appears in a consteval block, and \item $p_1$ is in a complete-class context of \tcode{S} and the consteval block is reachable from $p_3$. @@ -585,6 +588,7 @@ \pnum Each preprocessing token that is converted to a token\iref{lex.token} shall have the lexical form of a keyword, an identifier, a literal, +a header name, or an operator or punctuator. \pnum @@ -872,12 +876,14 @@ identifier\br keyword\br literal\br + header-name\br operator-or-punctuator \end{bnf} \pnum \indextext{\idxgram{token}}% -There are five kinds of tokens: identifiers, keywords, literals, +There are six kinds of tokens: identifiers, keywords, literals, +header names, operators, and other separators. \indextext{token|)} @@ -979,6 +985,12 @@ \keyword{pre} \\ \end{multicolfloattable} +\pnum +\begin{note} +Identifiers with special meaning +cannot be used as macro names\iref{cpp.replace.general}. +\end{note} + \pnum \indextext{\idxcode{_}|see{character, underscore}}% \indextext{character!underscore!in identifier}% @@ -987,7 +999,7 @@ appearing as a \grammarterm{token} or \grammarterm{preprocessing-token} are reserved for use by \Cpp{} implementations and shall -not be used otherwise; no diagnostic is required. +not be used otherwise; no diagnostic is required \ifndrdef{lex.name.reserved}. \begin{itemize} \item Each identifier that contains a double underscore @@ -1021,7 +1033,7 @@ \indextext{keyword|(}% The identifiers shown in \tref{lex.key} are reserved for use as keywords (that is, they are unconditionally treated as keywords in -phase 7) except in an \grammarterm{attribute-token}\iref{dcl.attr.grammar}. +phases 6 and 7) except in an \grammarterm{attribute-token}\iref{dcl.attr.grammar}. \begin{note} The \keyword{register} keyword is unused but is reserved for future use. @@ -1117,6 +1129,11 @@ \keyword{while} \\ \end{multicolfloattable} +\pnum +\begin{note} +Keywords cannot be used as macro names\iref{cpp.replace.general}. +\end{note} + \pnum Furthermore, the alternative representations shown in \tref{lex.key.digraph} for certain operators and @@ -1781,6 +1798,15 @@ else the larger or smaller representable value nearest the scaled value, chosen in an \impldef{choice of larger or smaller value of \grammarterm{floating-point-literal}} manner. +\begin{example} +The following example assumes that +\tcode{std::float32_t} is supported\iref{basic.extended.fp}. +\begin{codeblock} +std::float32_t x = 0.0f32; // value \tcode{0} is exactly representable +std::float32_t y = 0.1f32; // rounded to one of two values nearest to \tcode{0.1} +std::float32_t z = 1e1000000000f32; // either greatest finite value or positive infinity +\end{codeblock} +\end{example} \rSec2[lex.string]{String literals} diff --git a/source/lib-intro.tex b/source/lib-intro.tex index c0b53ee3ad..9422f9ea21 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -541,11 +541,11 @@ namespace std { template requires @\libconcept{convertible_to}@> - constexpr decay_t @\exposidnc{decay-copy}@(T&& v) // \expos + constexpr decay_t @\exposidnc{decay-copy}@(T&& v) // \expos noexcept(is_nothrow_convertible_v>) { return std::forward(v); } - constexpr auto @\exposidnc{synth-three-way}@ = // \expos + constexpr auto @\exposidnc{synth-three-way}@ = // \expos [](const T& t, const U& u) requires requires { { t < u } -> @\exposconcept{boolean-testable}@; @@ -562,8 +562,15 @@ }; template - using @\exposidnc{synth-three-way-result}@ = // \expos + using @\exposidnc{synth-three-way-result}@ = // \expos decltype(@\exposidnc{synth-three-way}@(declval(), declval())); + + template + concept @\defexposconceptnc{constexpr-wrapper-like}@ = // \expos + @\libconcept{convertible_to}@ && + @\libconcept{equality_comparable_with}@ && + bool_constant::value && + bool_constant(T()) == T::value>::value; } \end{codeblock} @@ -1850,7 +1857,6 @@ \tcode{<} is a strict weak ordering relation\iref{alg.sorting} \\ \end{oldconcepttable} -\enlargethispage{-3\baselineskip} \begin{oldconcepttable}{DefaultConstructible}{}{cpp17.defaultconstructible} {x{2.15in}p{3in}} \topline @@ -2347,12 +2353,12 @@ \pnum \remarks -If \tcode{Allocator} is a class template instantiation of the form +If \tcode{Allocator} is a class template specialization of the form \tcode{SomeAllocator}, where \tcode{Args} is zero or more type arguments, and \tcode{Allocator} does not supply a \tcode{rebind} member template, the standard \tcode{allocator_traits} template uses \tcode{SomeAllocator} in place of \tcode{Allocator::re\-bind::other} -by default. For allocator types that are not template instantiations of the +by default. For allocator types that are not template specializations of the above form, no default is provided. \pnum @@ -3074,7 +3080,7 @@ Let \tcode{\placeholder{F}} denote a standard library function\iref{global.functions}, a standard library static member function, -or an instantiation +or a specialization of a standard library function template. Unless \tcode{\placeholder{F}} is designated an \defnadj{addressable}{function}, @@ -3096,7 +3102,7 @@ or if it attempts to form a pointer-to-member designating either a standard library non-static member function\iref{member.functions} -or an instantiation of a standard library member function template. +or a specialization of a standard library member function template. \pnum Let \tcode{\placeholder{F}} denote @@ -3104,6 +3110,14 @@ Unless \tcode{\placeholder{F}} is designated an addressable function, it is unspecified if or how a reflection value designating the associated entity can be formed. +For any value \tcode{\placeholder{p}} of type \tcode{meta::info} that +represents a reflection of a parameter of \tcode{\placeholder{F}}, +it is unspecified if \tcode{has_identifier(\placeholder{p})} +returns \tcode{true} or \tcode{false}, and +if \tcode{meta::has_identifier(\placeholder{p})} is \tcode{true}, then +the \ntmbs{} produced by +\tcode{meta::identifier_of(\placeholder{p})} and +\tcode{meta::u8identifier_of(\placeholder{p})} is unspecified. %FIXME: Why is this not an example, but a note that begins with "For example"? \begin{note} For example, it is possible that \tcode{std::meta::members_of} @@ -3788,6 +3802,16 @@ the \Cpp{} standard library may be recursively reentered} which functions in the \Cpp{} standard library may be recursively reentered. +\pnum +During the execution of +a standard library non-static member function $F$ on an object, +if that object is accessed through a glvalue that is not obtained, +directly or indirectly, +from the object parameter of $F$, +in a manner that can conflict\iref{intro.races} +with any access that $F$ is permitted to perform\iref{res.on.data.races}, +the behavior is undefined unless otherwise specified. + \rSec3[res.on.data.races]{Data race avoidance} \pnum @@ -3977,7 +4001,7 @@ \rSec3[value.error.codes]{Value of error codes} \pnum -Certain functions in the \Cpp{} standard library report errors via a +Certain functions in the \Cpp{} standard library report errors via an \tcode{error_code}\iref{syserr.errcode.overview} object. That object's \tcode{category()} member shall return \tcode{system_category()} for errors originating from the operating system, or a reference to an diff --git a/source/limits.tex b/source/limits.tex index bdc1f3deb6..e0596a320a 100644 --- a/source/limits.tex +++ b/source/limits.tex @@ -111,7 +111,7 @@ \item% Recursive constexpr function invocations\iref{dcl.constexpr} [512]. \item% -Full-expressions evaluated within a core constant expression\iref{expr.const} [1\,048\,576]. +Full-expressions evaluated within a core constant expression\iref{expr.const.core} [1\,048\,576]. \item% Template parameters in a template declaration\iref{temp.param} [1\,024]. \item% diff --git a/source/macros.tex b/source/macros.tex index ae5591106e..dad5db884e 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -386,6 +386,17 @@ \newcommand{\ctype}{\Fundesc{Type}} \newcommand{\templalias}{\Fundesc{Alias template}} +%% Undefined behavior and ill-formed, no diagnostic required +% Use in main body of text to mark undefined behavior +\newcommand{\ubdef}[1]{\nolinebreak[3] (\label{ub:#1}\ref{ubx:#1})} +% Use in Annex to cross-reference marked undefined behavior +\newcommand{\ubxref}[1]{\label{ubx:#1}\textbf{Specified in:}\space\ref{ub:#1}\newline} + +% Use in main body of text to mark IFNDR +\newcommand{\ifndrdef}[1]{\nolinebreak[3] (\label{ifndr:#1}\ref{ifndrx:#1})} +% Use in Annex to cross-reference marked IFNDR +\newcommand{\ifndrxref}[1]{\label{ifndrx:#1}\textbf{Specified in:}\space\ref{ifndr:#1}} + %% Cross-reference \newcommand{\xref}[1]{\textsc{See also:}\space #1} \newcommand{\xrefc}[1]{\xref{\IsoC{}, #1}} @@ -406,8 +417,10 @@ \ExplSyntaxOff %% Inline non-parenthesized table reference (override memoir's \tref) +\providecommand{\tref}{} \renewcommand{\tref}[1]{\hyperref[tab:#1]{\tablerefname \nolinebreak[3] \ref*{tab:#1}}} %% Inline non-parenthesized figure reference (override memoir's \fref) +\providecommand{\fref}{} \renewcommand{\fref}[1]{\hyperref[fig:#1]{\figurerefname \nolinebreak[3] \ref*{fig:#1}}} %% NTBS, etc. @@ -609,7 +622,7 @@ #1:}}\CodeBlockSetup}{} % An environment for command / program output that is not C++ code. -\lstnewenvironment{outputblock}{\lstset{language=}}{} +\lstnewenvironment{outputblock}{\lstset{escapechar=@, language=}}{} % A code block in which single-quotes are digit separators % rather than character literals. diff --git a/source/memory.tex b/source/memory.tex index efbf7fee28..eb7c889a51 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -88,6 +88,8 @@ bool is_sufficiently_aligned(T* ptr); // freestanding // \ref{obj.lifetime}, explicit lifetime management + template + constexpr void start_lifetime(T& r) noexcept; // freestanding template T* start_lifetime_as(void* p) noexcept; // freestanding template @@ -837,7 +839,7 @@ the \grammarterm{qualified-id} \tcode{Ptr::rebind} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{SomePointer} if -\tcode{Ptr} is a class template instantiation of the form \tcode{SomePointer}, +\tcode{Ptr} is a class template specialization of the form \tcode{SomePointer}, where \tcode{Args} is zero or more type arguments; otherwise, the instantiation of \tcode{rebind} is ill-formed. \end{itemdescr} @@ -1019,6 +1021,10 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{Alignment} is a power of two. + \pnum \expects \tcode{p} points to @@ -1036,6 +1042,31 @@ \rSec2[obj.lifetime]{Explicit lifetime management} +\indexlibraryglobal{start_lifetime}% +\begin{itemdecl} +template + constexpr void start_lifetime(T& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete type and +an implicit-lifetime\iref{basic.types} aggregate\iref{dcl.init.aggr}. + +\pnum +\effects +If the object referenced by \tcode{r} +is already within its lifetime\iref{basic.life}, +no effects. +Otherwise, begins the lifetime of the object referenced by \tcode{r}. +\begin{note} +No initialization is performed and no subobject has its lifetime started. +If \tcode{r} denotes a member of a union $U$, +it becomes the active member of $U$\iref{class.union}. +\end{note} +\end{itemdescr} + \indexlibraryglobal{start_lifetime_as}% \begin{itemdecl} template @@ -1710,7 +1741,7 @@ \templalias \tcode{Alloc::rebind::other} if the \grammarterm{qualified-id} \tcode{Alloc::rebind::other} is valid and denotes a type\iref{temp.deduct}; otherwise, -\tcode{Alloc} if \tcode{Alloc} is a class template instantiation +\tcode{Alloc} if \tcode{Alloc} is a class template specialization of the form \tcode{Alloc}, where \tcode{Args} is zero or more type arguments; otherwise, the instantiation of \tcode{rebind_alloc} is ill-formed. \end{itemdescr} @@ -2637,6 +2668,10 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{*declval()} is a well-formed expression. + \pnum \mandates \tcode{reference_converts_from_temporary_v, decltype(\linebreak{}*declval())>} is \tcode{false}. @@ -4401,7 +4436,7 @@ shared_ptr p = make_shared(1.0); // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} shared_ptr q = make_shared({1.0, 0.0}); - // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each double[2] element is \tcode{\{1.0, 0.0\}} + // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each \tcode{double[2]} element is \tcode{\{1.0, 0.0\}} shared_ptr[4]> r = make_shared[4]>({1, 2}); // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} \end{codeblock} @@ -6796,7 +6831,7 @@ using the allocator \exposid{alloc}. \end{itemdescr} -\indexlibraryctor{indirect}% +\indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); \end{itemdecl} diff --git a/source/meta.tex b/source/meta.tex index 76ba9b3dbd..b2a168331b 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -810,46 +810,46 @@ // pseudo-mutators template<@\exposconcept{constexpr-param}@ T> constexpr auto operator++(this T) noexcept - -> constant_wrapper<++Y> { return {}; } + -> constant_wrapper<(++T::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T> constexpr auto operator++(this T, int) noexcept - -> constant_wrapper { return {}; } + -> constant_wrapper<(T::value++)> { return {}; } template<@\exposconcept{constexpr-param}@ T> constexpr auto operator--(this T) noexcept - -> constant_wrapper<--Y> { return {}; } + -> constant_wrapper<(--T::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T> constexpr auto operator--(this T, int) noexcept - -> constant_wrapper { return {}; } + -> constant_wrapper<(T::value--)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator+=(T, R) noexcept + constexpr auto operator+=(this T, R) noexcept -> constant_wrapper<(T::value += R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator-=(T, R) noexcept + constexpr auto operator-=(this T, R) noexcept -> constant_wrapper<(T::value -= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator*=(T, R) noexcept + constexpr auto operator*=(this T, R) noexcept -> constant_wrapper<(T::value *= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator/=(T, R) noexcept + constexpr auto operator/=(this T, R) noexcept -> constant_wrapper<(T::value /= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator%=(T, R) noexcept + constexpr auto operator%=(this T, R) noexcept -> constant_wrapper<(T::value %= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator&=(T, R) noexcept + constexpr auto operator&=(this T, R) noexcept -> constant_wrapper<(T::value &= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator|=(T, R) noexcept + constexpr auto operator|=(this T, R) noexcept -> constant_wrapper<(T::value |= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator^=(T, R) noexcept + constexpr auto operator^=(this T, R) noexcept -> constant_wrapper<(T::value ^= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator<<=(T, R) noexcept + constexpr auto operator<<=(this T, R) noexcept -> constant_wrapper<(T::value <<= R::value)> { return {}; } template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator>>=(T, R) noexcept + constexpr auto operator>>=(this T, R) noexcept -> constant_wrapper<(T::value >>= R::value)> { return {}; } }; @@ -861,9 +861,9 @@ template<@\exposconcept{constexpr-param}@ R> constexpr auto operator=(R) const noexcept - -> constant_wrapper { return {}; } + -> constant_wrapper<(value = R::value)> { return {}; } - constexpr operator decltype(auto)() const noexcept { return value; } + constexpr operator decltype(value)() const noexcept { return value; } }; } \end{codeblock} @@ -871,7 +871,7 @@ \pnum The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring that the evaluation of expressions comprised entirely of \tcode{constant_wrapper} -are core constant expressions\iref{expr.const}, +are core constant expressions\iref{expr.const.core}, regardless of the context in which they appear. In particular, this enables use of \tcode{constant_wrapper} values that are passed as arguments to constexpr functions to be used in constant expressions. @@ -1548,6 +1548,8 @@ the initialization \tcode{T t(\exposidnc{VAL});} is well-formed and binds \tcode{t} to a temporary object whose lifetime is extended\iref{class.temporary}. + The full-expression of the variable initialization is + treated as an unevaluated operand\iref{expr.context}. Access checking is performed as if in a context unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context of @@ -1571,6 +1573,8 @@ the initialization \tcode{T t = \exposidnc{VAL};} is well-formed and binds \tcode{t} to a temporary object whose lifetime is extended\iref{class.temporary}. + The full-expression of the variable initialization is + treated as an unevaluated operand\iref{expr.context}. Access checking is performed as if in a context unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context of @@ -1639,6 +1643,8 @@ \begin{note} These tokens are never interpreted as a function declaration. \end{note} +The full-expression of the variable initialization is +treated as an unevaluated operand\iref{expr.context}. Access checking is performed as if in a context unrelated to \tcode{T} and any of the \tcode{Args}. Only the validity of the immediate context of the variable initialization is considered. @@ -1937,7 +1943,8 @@ \indexlibraryglobal{is_convertible}% \pnum The predicate condition for a template specialization \tcode{is_convertible} -shall be satisfied if and only if the return expression in the following code would be +shall be satisfied if and only if +the return statement\iref{stmt.return} in the following code would be well-formed, including any implicit conversions to the return type of the function: \begin{codeblock} @@ -1951,9 +1958,11 @@ array types, function types, and \cv{}~\keyword{void}. \end{note} Access checking is performed -in a context unrelated to \tcode{To} and \tcode{From}. Only the validity of -the immediate context of the \grammarterm{expression} of the \tcode{return} statement\iref{stmt.return} -(including initialization of the returned object or reference) is considered. +in a context unrelated to \tcode{To} and \tcode{From}. +The operand of the \tcode{return} statement +(including initialization of the returned object or reference, if any) +is treated as an unevaluated operand\iref{expr.context}, and +only the validity of its immediate context is considered. \begin{note} The initialization can result in side effects such as the @@ -3089,7 +3098,7 @@ // \ref{meta.reflection.extract}, value extraction template - consteval T extract(info); + consteval T extract(info r); // \ref{meta.reflection.substitute}, reflection substitution template @@ -3113,7 +3122,7 @@ consteval info data_member_spec(info type, data_member_options options); consteval bool is_data_member_spec(info r); template<@\libconcept{reflection_range}@ R = initializer_list> - consteval info define_aggregate(info type_class, R&&); + consteval info define_aggregate(info type_class, R&& mdescrs); // associated with \ref{meta.unary.cat}, primary type categories consteval bool is_void_type(info type); @@ -3352,7 +3361,7 @@ \returns \begin{itemize} \item - If \tcode{p} points to an unspecified object\iref{expr.const}, + If \tcode{p} points to an unspecified object\iref{expr.const.core}, \tcode{false}. \item Otherwise, if \tcode{p} points to a subobject @@ -3416,30 +3425,44 @@ \begin{itemdescr} \pnum -Let \tcode{T} be \tcode{ranges::range_value_t} and -$\tcode{\placeholder{e}}_i$ be \tcode{static_cast(*$\tcode{\placeholder{it}}_i$)}, -where $\tcode{\placeholder{it}}_i$ is an iterator to the $i^\text{th}$ element of \tcode{r}. +Let \tcode{U} be \tcode{ranges::range_value_t} and +\tcode{T} be \tcode{remove_all_extents_t}. \pnum \mandates -\tcode{T} is a structural type\iref{temp.param}, -\tcode{is_constructible_v>} is \tcode{true}, and -\tcode{T} satisfies \libconcept{copy_constructible}. +\begin{itemize} +\item \tcode{T} is a structural type\iref{temp.param}, +\item \tcode{T} satisfies \libconcept{copy_constructible}, and +\item +if \tcode{U} is not an array type, then +\tcode{is_constructible_v>} is \tcode{true}. +\end{itemize} \pnum Let $V$ be the pack of values of type \tcode{info} of the same size as \tcode{r}, where the $i^\text{th}$ element is -\tcode{reflect_constant($\tcode{\placeholder{e}}_i$)}. +\begin{itemize} +\item +\tcode{reflect_constant_array(*$\tcode{\placeholder{it}}_i$)} +if \tcode{U} is an array type, +\item +\tcode{reflect_constant(static_cast(*$\tcode{\placeholder{it}}_i$))} +otherwise, +\end{itemize} +and $\tcode{\placeholder{it}}_i$ is an iterator to +the $i^\text{th}$ element of \tcode{r}. \pnum Let $P$ be \begin{itemize} \item the template parameter object\iref{temp.param} - of type \tcode{const T[sizeof...(\brk{}$V$)]} - initialized with\linebreak - \tcode{\{[:$V$:]...\}} if \tcode{sizeof...($V$) > 0} is \tcode{true}, otherwise + of type \tcode{const T[sizeof...($V$)]}, + such that \tcode{$P$[$I$]} is template-argument-equivalent\iref{temp.type} + to the object represented by \tcode{$V$...[$I$]} + for all $I$ in the range \range{0}{sizeof...($V$)} + if \tcode{sizeof...($V$) > 0} is \tcode{true}, otherwise \item the template parameter object of type \tcode{const array} initialized with \tcode{\{\}}. @@ -3451,10 +3474,21 @@ \pnum \throws -Any exception thrown by the evaluation of any $\tcode{\placeholder{e}}_i$, or +Any of +\begin{itemize} +\item +an exception thrown by any operation +on \tcode{r} or +on iterators and sentinels referring to \tcode{r}, +\item +an exception thrown +by the evaluation of any argument of \tcode{reflect_constant} or +by any evaluation of \tcode{reflect_constant_array}, or +\item \tcode{meta::exception} -if evaluation of any \tcode{reflect_constant($\tcode{\placeholder{e}}_i$)} +if any invocation of \tcode{reflect_constant} would exit via an exception. +\end{itemize} \pnum \begin{note} @@ -3510,8 +3544,12 @@ Equivalent to: \begin{codeblock} using U = remove_cvref_t; -if constexpr (meta::is_class_type(^^U)) { - return addressof(meta::extract(meta::reflect_constant(std::forward(t)))); +if constexpr (meta::is_class_type(^^U) || meta::is_union_type(^^U)) { + return addressof(meta::extract( + meta::reflect_constant(std::forward(t)))); +} else if constexpr (meta::is_array_type(^^U)) { + return addressof(meta::extract( + meta::reflect_constant_array(std::forward(t)))); } else { return define_static_array(span(addressof(t), 1)).data(); } @@ -3815,7 +3853,7 @@ Otherwise, if \tcode{r} represents the parameter $P$ of a function $F$, then let $S$ be the set of declarations, ignoring any explicit instantiations, - that precede some point in the evaluation context + that are reachable from a point in the evaluation context and that declare either $F$ or a templated function of which $F$ is a specialization; \tcode{true} if @@ -3901,7 +3939,7 @@ Otherwise, if \tcode{r} represents the parameter $P$ of a function $F$, then let $S$ be the set of declarations, ignoring any explicit instantiations, - that precede some point in the evaluation context + that are reachable from a point in the evaluation context and that declare either $F$ or a templated function of which $F$ is a specialization; the name that was introduced by a declaration in $S$ @@ -4030,7 +4068,7 @@ \begin{itemize} \item If $E$ is defined by a declaration $D$ - that precedes a point $P$ in the evaluation context + that is reachable from a point $P$ in the evaluation context and $P$ does not occur within an \grammarterm{enum-specifier} of $D$, then a reflection of $E$. \item @@ -4085,7 +4123,7 @@ and if that variable is a reference $R$, then either \begin{itemize} \item - $R$ is usable in constant expressions\iref{expr.const}, or + $R$ is usable in constant expressions\iref{expr.const.init}, or \item the lifetime of $R$ began within the core constant expression currently under evaluation. @@ -4348,7 +4386,7 @@ \pnum \returns -\tcode{true} if \tcode{T} represents a const or volatile type, respectively, +\tcode{true} if $T$ represents a const or volatile type, respectively, or a const- or volatile-qualified function type, respectively. Otherwise, \tcode{false}. \end{itemdescr} @@ -4662,13 +4700,13 @@ \item If $F$ is a specialization of a templated function $T$, then \tcode{true} if there exists a declaration $D$ of $T$ - that precedes some point in the evaluation context + that is reachable from a point in the evaluation context and $D$ specifies a default argument for the parameter of $T$ corresponding to $P$. Otherwise, \tcode{false}. \item Otherwise, if there exists a declaration $D$ of $F$ - that precedes some point in the evaluation context + that is reachable from a point in the evaluation context and $D$ specifies a default argument for $P$, then \tcode{true}. \end{itemize} @@ -5985,8 +6023,9 @@ \pnum \returns A \tcode{vector} containing all of the reflections $R$ -representing each annotation applying to each declaration of $E$ that precedes either -some point in the evaluation context\iref{expr.const} or +representing each annotation applying to each declaration of $E$ +that is reachable from either +a point in the evaluation context\iref{expr.const.reflect} or a point immediately following the \grammarterm{class-specifier} of the outermost class for which such a point is in a complete-class context. For any two reflections $R_1$ and $R_2$ in the returned \tcode{vector}, @@ -6611,6 +6650,9 @@ \item if $V$ equals \tcode{0}, then \tcode{options.name} does not contain a value; and + \item + if \tcode{options.name} does not contain a value, then + \tcode{is_const(type) || is_volatile(type)} is \tcode{false}; and \end{itemize} \item if \tcode{options.alignment} contains a value, @@ -6679,7 +6721,7 @@ \pnum \effects -Produces an injected declaration $D$\iref{expr.const} +Produces an injected declaration $D$\iref{expr.const.reflect} that defines $C$ and has properties as follows: \begin{itemize} \item @@ -6690,7 +6732,7 @@ follows immediately after the core constant expression currently under evaluation. \item - The characteristic sequence of $D$\iref{expr.const} + The characteristic sequence of $D$\iref{expr.const.reflect} is the sequence of reflection values $r_K$. \item If $C$ is a specialization of a templated class $T$, diff --git a/source/modules.tex b/source/modules.tex index 551e1ecc62..9ecef29d77 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -39,7 +39,7 @@ consisting of \tcode{std} followed by zero or more \grammarterm{digit}{s} or containing a reserved identifier\iref{lex.name} are reserved and shall not be specified in a \grammarterm{module-declaration}; -no diagnostic is required. +no diagnostic is required\ifndrdef{module.unit.reserved.identifiers}. If any \grammarterm{identifier} in a reserved \grammarterm{module-name} is a reserved identifier, the module name is reserved for use by \Cpp{} implementations; @@ -54,7 +54,7 @@ A named module shall contain exactly one module interface unit with no \grammarterm{module-partition}, known as the \defn{primary module interface unit} of the module; -no diagnostic is required. +no diagnostic is required\ifndrdef{module.unit.named.module.no.partition}. \pnum A \defn{module partition} is @@ -66,7 +66,8 @@ that are module interface units shall be directly or indirectly exported by the primary module interface unit\iref{module.import}. -No diagnostic is required for a violation of these rules. +No diagnostic is required +for a violation of these rules\ifndrdef{module.unit.unexported.module.partition}. \begin{note} Module partitions can be imported only by other module units in the same module. @@ -254,7 +255,7 @@ namespace { export int a2; // error: export of name with internal linkage } -export static int b; // error: b explicitly declared static +export static int b; // error: \tcode{b} explicitly declared static export int f(); // OK export namespace N { } // OK export using namespace N; // OK @@ -810,7 +811,7 @@ in a primary module interface unit\iref{module.unit}. A module unit with a \grammarterm{private-module-fragment} shall be the only module unit of its module; -no diagnostic is required. +no diagnostic is required\ifndrdef{module.private.frag.other.module.units}. \pnum \begin{note} @@ -921,7 +922,7 @@ that resulted from the evaluation of an expression as a core constant expression, the instantiation context contains -each point in the evaluation context\iref{expr.const}. +each point in the evaluation context\iref{expr.const.reflect}. \begin{note} Implicit instantiations can result from invocations of library functions\iref{meta.reflection}. @@ -1064,7 +1065,7 @@ The value of \tcode{n} is 1. The member \tcode{Incomplete::x} members-of-precedes\iref{meta.reflection.member.queries} -the synthesized point P associated with the injected declaration +the synthesized point $P$ associated with the injected declaration produced by the call to \tcode{define_aggregate}. \end{example} diff --git a/source/numerics.tex b/source/numerics.tex index b2d2e2ca07..46bb6d73b8 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -51,7 +51,7 @@ These include arithmetic types, pointers, the library class \tcode{complex}, -and instantiations of +and specializations of \tcode{valarray} for value types. \end{footnote} @@ -4452,7 +4452,7 @@ \pnum \begin{note} If the values $g_i$ produced by \tcode{g} are uniformly distributed, -the instantiation's results are distributed as uniformly as possible. +\tcode{generate_canonical}'s results are distributed as uniformly as possible. Obtaining a value in this way can be a useful step in the process of transforming @@ -10964,7 +10964,7 @@ struct explicit_diagonal_t; inline constexpr explicit_diagonal_t explicit_diagonal; - // \ref{linalg.layout.packed}, class template layout_blas_packed + // \ref{linalg.layout.packed}, class template \tcode{layout_blas_packed} template class layout_blas_packed; @@ -13834,12 +13834,21 @@ \tcode{InVec::value_type} and \tcode{Scalar} are either a floating-point type, or a specialization of \tcode{complex}. Let \tcode{a} be -\tcode{\exposid{abs-if-needed}(declval())}. -Then, \tcode{decltype(\linebreak init + a * a} is convertible to \tcode{Scalar}. +\tcode{\exposid{abs-if-needed}(declval())} and +let \tcode{init_abs} be \tcode{\exposid{abs-if-needed}(init)}. +Then, \tcode{decltype(init_abs * init_abs + a * a)} +is convertible to \tcode{Scalar}. \pnum \returns -The square root of the sum of the square of \tcode{init} and the squares of the absolute values of the elements of \tcode{v}. +The square root of the sum +whose terms are the following: +\begin{itemize} +\item +the square of the absolute value of \tcode{init}, and +\item +the squares of the absolute values of the elements of \tcode{v}. +\end{itemize} \begin{note} For \tcode{init} equal to zero, this is the Euclidean norm (also called 2-norm) of the vector \tcode{v}. @@ -14032,17 +14041,24 @@ \pnum \mandates -\tcode{InVec::value_type} and \tcode{Scalar} are either a floating-point type, or +\tcode{InMat::value_type} and \tcode{Scalar} are either a floating-point type, or a specialization of \tcode{complex}. Let \tcode{a} be -\tcode{\exposid{abs-if-needed}(declval())}. -Then, \tcode{decltype(\linebreak init + a * a)} +\tcode{\exposid{abs-if-needed}(declval())} and +let \tcode{init_abs} be \tcode{\exposid{abs-if-needed}(init)}. +Then, \tcode{decltype(init_abs * init_abs + a * a)} is convertible to \tcode{Scalar}. \pnum \returns -The square root of the sum of squares -of \tcode{init} and the absolute values of the elements of \tcode{A}. +The square root of the sum +whose terms are the following: +\begin{itemize} +\item +the square of the absolute value of \tcode{init}, and +\item +the squares of the absolute values of the elements of \tcode{A}. +\end{itemize} \begin{note} For \tcode{init} equal to zero, this is the Frobenius norm of the matrix \tcode{A}. @@ -15163,7 +15179,7 @@ \pnum \begin{note} These functions correspond to the BLAS functions -\tcode{xSYR2},\tcode{xSPR2}, \tcode{xHER2} and \tcode{xHPR2}\supercite{blas2}. +\tcode{xSYR2}, \tcode{xSPR2}, \tcode{xHER2} and \tcode{xHPR2}\supercite{blas2}. \end{note} \pnum @@ -15973,7 +15989,7 @@ \tcode{\exposid{multipliable}(A, transposed(B), C)} is \tcode{true}, \item -\tcode{multipliable(B, transposed(A), C)} +\tcode{\exposid{multipliable}(B, transposed(A), C)} is \tcode{true}, and \begin{note} This and the previous imply that \tcode{C} is square. @@ -16038,6 +16054,8 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\effects Computes $C = E + A B^T + B A^T$. \end{itemdescr} @@ -16532,6 +16550,11 @@ \tcode{T} is \defn{value-preserving} if all possible values of \tcode{U} can be represented with type \tcode{T}. +\pnum +If a program declares an explicit or partial specialization of +any of the templates specified in subclause \ref{simd}, +the program is ill-formed, no diagnostic required. + \rSec2[simd.expos]{Exposition-only types, variables, and concepts} \begin{codeblock} @@ -16542,13 +16565,6 @@ constexpr @\exposidnc{simd-size-type} \exposidnc{simd-size-v} = \seebelownc@; // \expos template constexpr size_t @\exposidnc{mask-element-size} = \seebelownc@; // \expos -template - concept @\defexposconceptnc{constexpr-wrapper-like}@ = // \expos - @\libconcept{convertible_to}@ && - @\libconcept{equality_comparable_with}@ && - bool_constant::value && - bool_constant(T()) == T::value>::value; - template concept @\defexposconceptnc{explicitly-convertible-to}@ = // \expos requires { @@ -16966,33 +16982,33 @@ template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-vec-type}@ V, class IdxMap> constexpr resize_t permute(const V& v, IdxMap&& idxmap); - template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ M, class IdxMap> - constexpr resize_t permute(const M& v, IdxMap&& idxmap); + template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ V, class IdxMap> + constexpr resize_t permute(const V& v, IdxMap&& idxmap); // \ref{simd.permute.dynamic}, dynamic permute template<@\exposconcept{simd-vec-type}@ V, @\exposconcept{simd-integral}@ I> constexpr resize_t permute(const V& v, const I& indices); - template<@\exposconcept{simd-mask-type}@ M, @\exposconcept{simd-integral}@ I> - constexpr resize_t permute(const M& v, const I& indices); + template<@\exposconcept{simd-mask-type}@ V, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const V& v, const I& indices); // \ref{simd.permute.mask}, mask permute template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector); - template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector); + template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector); template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector, const typename V::value_type& fill_value); - template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector, - const typename M::value_type& fill_value); + template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector, + const typename V::value_type& fill_value); template<@\exposconcept{simd-vec-type}@ V> constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); - template<@\exposconcept{simd-mask-type}@ M> - constexpr M expand(const M& v, const type_identity_t& selector, - const M& original = {}); + template<@\exposconcept{simd-mask-type}@ V> + constexpr V expand(const V& v, const type_identity_t& selector, + const V& original = {}); // \ref{simd.permute.memory}, memory permute template @@ -17489,10 +17505,6 @@ (converting) loads and stores for the given type \tcode{T} on arrays of type \tcode{U}. \end{note} - -\pnum -The behavior of a program that adds specializations for \tcode{alignment} -is undefined. \end{itemdescr} \indexlibrarymember{rebind}{simd} @@ -17589,7 +17601,7 @@ \rSec3[simd.flags.oper]{\tcode{flags} operators} -\indexlibrarymember{operator|}{simd::flags} +\indexlibrarymember{operator"|}{simd::flags} \begin{itemdecl} template friend consteval auto operator|(flags a, flags b); @@ -18386,7 +18398,7 @@ A copy of \tcode{*this} before decrementing. \end{itemdescr} -\indexlibrarymember{operator!}{basic_vec} +\indexlibrarymember{operator"!}{basic_vec} \begin{itemdecl} constexpr mask_type operator!() const noexcept; \end{itemdecl} @@ -18402,7 +18414,7 @@ \tcode{!operator[]($i$)} for all $i$ in the range of \range{0}{size()}. \end{itemdescr} -\indexlibrarymember{operator~}{basic_vec} +\indexlibrarymember{operator\~{}}{basic_vec} \begin{itemdecl} constexpr basic_vec operator~() const noexcept; \end{itemdecl} @@ -18459,7 +18471,7 @@ \indexlibrarymember{operator/}{basic_vec} \indexlibrarymember{operator\%}{basic_vec} \indexlibrarymember{operator\&}{basic_vec} -\indexlibrarymember{operator|}{basic_vec} +\indexlibrarymember{operator"|}{basic_vec} \indexlibrarymember{operator\caret}{basic_vec} \indexlibrarymember{operator<<}{basic_vec} \indexlibrarymember{operator>>}{basic_vec} @@ -18523,7 +18535,7 @@ \indexlibrarymember{operator/=}{basic_vec} \indexlibrarymember{operator\%=}{basic_vec} \indexlibrarymember{operator\&=}{basic_vec} -\indexlibrarymember{operator|=}{basic_vec} +\indexlibrarymember{operator"|=}{basic_vec} \indexlibrarymember{operator\caret=}{basic_vec} \indexlibrarymember{operator<<=}{basic_vec} \indexlibrarymember{operator>>=}{basic_vec} @@ -18583,7 +18595,7 @@ \rSec3[simd.comparison]{Comparison operators} \indexlibrarymember{operator==}{basic_vec} -\indexlibrarymember{operator!=}{basic_vec} +\indexlibrarymember{operator"!=}{basic_vec} \indexlibrarymember{operator>=}{basic_vec} \indexlibrarymember{operator<=}{basic_vec} \indexlibrarymember{operator>}{basic_vec} @@ -19100,8 +19112,8 @@ \begin{itemdecl} template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-vec-type}@ V, class IdxMap> constexpr resize_t permute(const V& v, IdxMap&& idxmap); -template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ M, class IdxMap> - constexpr resize_t permute(const M& v, IdxMap&& idxmap); +template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ V, class IdxMap> + constexpr resize_t permute(const V& v, IdxMap&& idxmap); \end{itemdecl} \begin{itemdescr} @@ -19159,8 +19171,8 @@ \begin{itemdecl} template<@\exposconcept{simd-vec-type}@ V, @\exposconcept{simd-integral}@ I> constexpr resize_t permute(const V& v, const I& indices); -template<@\exposconcept{simd-mask-type}@ M, @\exposconcept{simd-integral}@ I> - constexpr resize_t permute(const M& v, const I& indices); +template<@\exposconcept{simd-mask-type}@ V, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const V& v, const I& indices); \end{itemdecl} \begin{itemdescr} @@ -19181,8 +19193,8 @@ \begin{itemdecl} template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector); -template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector); +template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector); \end{itemdecl} \begin{itemdescr} @@ -19214,9 +19226,9 @@ template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector, const typename V::value_type& fill_value); -template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector, - const typename M::value_type& fill_value); +template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector, + const typename V::value_type& fill_value); \end{itemdecl} \begin{itemdescr} @@ -19243,8 +19255,8 @@ \begin{itemdecl} template<@\exposconcept{simd-vec-type}@ V> constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); -template<@\exposconcept{simd-mask-type}@ M> - constexpr M expand(const M& v, const type_identity_t& selector, const M& original = {}); +template<@\exposconcept{simd-mask-type}@ V> + constexpr V expand(const V& v, const type_identity_t& selector, const V& original = {}); \end{itemdecl} \begin{itemdescr} @@ -20143,7 +20155,7 @@ \pnum \remarks A function call expression that violates the precondition in the \expects -element is not a core constant expression\iref{expr.const}. +element is not a core constant expression\iref{expr.const.core}. \end{itemdescr} \indexlibrarymember{bit_floor}{simd} @@ -20617,10 +20629,10 @@ \rSec3[simd.mask.unary]{Unary operators} -\indexlibrarymember{operator!}{basic_mask} +\indexlibrarymember{operator"!}{basic_mask} \indexlibrarymember{operator+}{basic_mask} \indexlibrarymember{operator-}{basic_mask} -\indexlibrarymember{operator~}{basic_mask} +\indexlibrarymember{operator\~{}}{basic_mask} \begin{itemdecl} constexpr basic_mask operator!() const noexcept; constexpr @\seebelow@ operator+() const noexcept; @@ -20711,9 +20723,9 @@ \rSec3[simd.mask.binary]{Binary operators} \indexlibrarymember{operator\&\&}{basic_mask} -\indexlibrarymember{operator||}{basic_mask} +\indexlibrarymember{operator"|"|}{basic_mask} \indexlibrarymember{operator\&}{basic_mask} -\indexlibrarymember{operator|}{basic_mask} +\indexlibrarymember{operator"|}{basic_mask} \indexlibrarymember{operator\caret}{basic_mask} \begin{itemdecl} friend constexpr basic_mask @@ -20742,7 +20754,7 @@ \rSec3[simd.mask.cassign]{Compound assignment} \indexlibrarymember{operator\&=}{basic_mask} -\indexlibrarymember{operator|=}{basic_mask} +\indexlibrarymember{operator"|=}{basic_mask} \indexlibrarymember{operator\caret=}{basic_mask} \begin{itemdecl} friend constexpr basic_mask& @@ -20770,7 +20782,7 @@ \rSec3[simd.mask.comparison]{Comparisons} \indexlibrarymember{operator==}{basic_mask} -\indexlibrarymember{operator!=}{basic_mask} +\indexlibrarymember{operator"!=}{basic_mask} \indexlibrarymember{operator>=}{basic_mask} \indexlibrarymember{operator<=}{basic_mask} \indexlibrarymember{operator<}{basic_mask} diff --git a/source/overloading.tex b/source/overloading.tex index fe6c4d0852..0a0bfbd5fb 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -1056,7 +1056,8 @@ class. The argument list is the \grammarterm{expression-list} or \grammarterm{assignment-expression} -of the \grammarterm{initializer}. +of the \grammarterm{initializer}; +for default-initialization, the argument list is empty. For default-initialization in the context of copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. @@ -1431,6 +1432,21 @@ \end{codeblock} \end{example} +\pnum +When resolving a placeholder for a deduced class type +where the \grammarterm{template-name} +designates a type template template parameter \tcode{P}, +the type template template argument for \tcode{P} +shall be a deducible template. +Let \tcode{A} be an alias template +whose template parameter list is that of \tcode{P} and +whose \grammarterm{defining-type-id} is a \grammarterm{simple-template-id} +whose \grammarterm{template-name} designates the type template template argument and +whose \grammarterm{template-argument-list} is the template argument list of \tcode{P}. +The alias template \tcode{A} is then used +instead of the original \grammarterm{template-name} +to resolve the placeholder. + \pnum When resolving a placeholder for a deduced class type\iref{dcl.type.simple} where @@ -1688,6 +1704,25 @@ \indextext{overloading!argument lists|)}% \indextext{overloading!candidate functions|)} +\pnum +\begin{example} +\begin{codeblock} +template +struct Y { + Y(); + Y(Ts ...); +}; +template class X> +void f() { + X x; // OK, deduces \tcode{Y} + X x0{}; // OK, deduces \tcode{Y} + X x1{1}; // OK, deduces \tcode{Y} + X x2{1, 2}; // error: cannot deduce \tcode{X} from \tcode{Y} +} +template void f(); +\end{codeblock} +\end{example} + \rSec2[over.match.viable]{Viable functions}% \indextext{overloading!resolution!viable functions|(} @@ -3898,7 +3933,7 @@ \pnum For every pair of types \tcode{\placeholder{L}} and \tcode{\placeholder{R}}, where each of \tcode{\placeholder{L}} and \tcode{\placeholder{R}} is a -floating-point or promoted integral type, +cv-unqualified floating-point or promoted integral type, there exist candidate operator functions of the form \begin{codeblock} @\placeholder{LR}@ operator*(@\placeholder{L}@, @\placeholder{R}@); @@ -3920,14 +3955,14 @@ \tcode{\placeholder{R}}. \pnum -For every integral type \tcode{\placeholder{T}} +For every cv-unqualified integral type \tcode{\placeholder{T}} there exists a candidate operator function of the form \begin{codeblock} std::strong_ordering operator<=>(@\placeholder{T}@, @\placeholder{T}@); \end{codeblock} \pnum -For every pair of floating-point types +For every pair of cv-unqualified floating-point types \tcode{\placeholder{L}} and \tcode{\placeholder{R}}, there exists a candidate operator function of the form \begin{codeblock} @@ -4004,8 +4039,9 @@ \pnum For every triple (\tcode{\placeholder{L}}, \cvqual{vq}, \tcode{\placeholder{R}}), -where \tcode{\placeholder{L}} is an arithmetic type, -and \tcode{\placeholder{R}} is a floating-point or promoted integral type, +where \tcode{\placeholder{L}} is a cv-unqualified arithmetic type +and \tcode{\placeholder{R}} is +a cv-unqualified floating-point or promoted integral type, there exist candidate operator functions of the form \begin{codeblock} @\cvqual{vq} \placeholder{L}@& operator=(@\cvqual{vq} \placeholder{L}@&, @\placeholder{R}@); @@ -4055,7 +4091,7 @@ \tcode{\placeholder{R}}), where \tcode{\placeholder{L}} -is an integral type, and +is a cv-unqualified integral type and \tcode{\placeholder{R}} is a promoted integral type, there exist candidate operator functions of the form @@ -4079,7 +4115,7 @@ \pnum For every pair of types \tcode{\placeholder{L}} and \tcode{\placeholder{R}}, where each of \tcode{\placeholder{L}} and \tcode{\placeholder{R}} is a -floating-point or promoted integral type, +cv-unqualified floating-point or promoted integral type, there exist candidate operator functions of the form \begin{codeblock} @\placeholder{LR}@ operator?:(bool, @\placeholder{L}@, @\placeholder{R}@); @@ -4132,7 +4168,7 @@ The first form of \grammarterm{literal-operator-id} is deprecated\iref{depr.lit}. Some literal suffix identifiers are reserved for future standardization; see~\ref{usrlit.suffix}. A declaration whose \grammarterm{literal-operator-id} uses -such a literal suffix identifier is ill-formed, no diagnostic required. +such a literal suffix identifier is ill-formed, no diagnostic required\ifndrdef{over.literal.reserved}. \pnum A declaration whose \grammarterm{declarator-id} is a diff --git a/source/preprocessor.tex b/source/preprocessor.tex index b9809ae664..1cec9096e5 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -508,12 +508,6 @@ The identifiers \xname{has_include}, \xname{has_embed}, and \xname{has_cpp_attribute} shall not appear in any context not mentioned in this subclause. -\pnum -Each preprocessing token that remains (in the list of preprocessing tokens that -will become the controlling expression) -after all macro replacements have occurred -shall be in the lexical form of a token\iref{lex.token}. - \pnum Preprocessing directives of the forms \begin{ncsimplebnf} @@ -542,12 +536,12 @@ as a macro\iref{cpp.replace.general}, the program is ill-formed. If the preprocessing token \tcode{defined} -is generated as a result of this replacement process +is generated as a result of this replacement process\ifndrdef{cpp.cond.defined.after.macro} or use of the \tcode{defined} unary operator does not match one of the two specified forms prior to macro replacement, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{cpp.cond.defined.malformed}. \pnum After all replacements due to macro expansion and @@ -574,7 +568,7 @@ \pnum The resulting tokens comprise the controlling constant expression -which is evaluated according to the rules of~\ref{expr.const} +which is evaluated according to the rules of~\ref{expr.const.core} using arithmetic that has at least the ranges specified in~\ref{support.limits}. For the purposes of this token conversion and evaluation all signed and unsigned integer types @@ -772,7 +766,8 @@ is \impldef{treatment of whitespace when processing a \tcode{\#include} directive}. If the attempt succeeds, the directive with the so-formed \grammarterm{header-name} is processed as specified for the previous form. -Otherwise, the program is ill-formed, no diagnostic required. +Otherwise, the program is +ill-formed, no diagnostic required\ifndrdef{cpp.include.malformed.headername}. \begin{note} Adjacent \grammarterm{string-literal}s are not concatenated into a single \grammarterm{string-literal} @@ -1224,7 +1219,7 @@ \begin{bnf} \nontermdef{pp-module}\br - \opt{\keyword{export}} \keyword{module} \opt{pp-tokens} \terminal{;} new-line + \opt{\keyword{export}} \keyword{module} \opt{pp-tokens} new-line \end{bnf} \pnum @@ -1233,8 +1228,7 @@ \begin{ncsimplebnf} pp-module-name \opt{pp-module-partition} \opt{pp-tokens} \end{ncsimplebnf} -where the \grammarterm{pp-tokens} (if any) shall not begin with -a \tcode{(} preprocessing token and +where the grammar non-terminals are defined as: \begin{ncbnf} \nontermdef{pp-module-name}\br @@ -1251,15 +1245,9 @@ \end{ncbnf} No \grammarterm{identifier} in the \grammarterm{pp-module-name} or \grammarterm{pp-module-partition} -shall currently be defined as an object-like macro. - -\pnum -Any preprocessing tokens after the \tcode{module} preprocessing token -in the \tcode{module} directive are processed just as in normal text. -\begin{note} -Each identifier currently defined as a macro name -is replaced by its replacement list of preprocessing tokens. -\end{note} +shall currently be defined as an object-like macro +or followed by \tcode{(} as the next preprocessing token at +the start of phase 4 of translation\iref{lex.phases}. \pnum The \tcode{module} and \tcode{export} (if it exists) preprocessing tokens @@ -1269,6 +1257,69 @@ This makes the line no longer a directive so it is not removed at the end of phase 4. \end{note} +After this replacement, +the preprocessing tokens that constituted the directive are +a \grammarterm{text-line} and are processed as normal text. +\begin{note} +No macro expansion is possible for +the \grammarterm{pp-module-name} and \grammarterm{pp-module-partition}. +\end{note} +After such processing, +there shall be a \tcode{;} or \tcode{[} preprocessing token following +the \grammarterm{pp-module-name} and +optional \grammarterm{pp-module-partition}. + +\pnum +\begin{example} +\begin{codeblocktu}{Importable header \tcode{"common.h"}} +#define DOT_BAR .bar +#define MOD_ATTR [[vendor::shiny_module]] +\end{codeblocktu} + +\begin{codeblocktu}{Translation unit \tcode{\#1}} +module; +#include "common.h" + +export module foo DOT_BAR; // error: expansion of \tcode{DOT_BAR;} does not begin with \tcode{;} or \tcode{[} +\end{codeblocktu} + +\begin{codeblocktu}{Translation unit \tcode{\#2}} +module; +#include "common.h" + +export module M MOD_ATTR ; // OK +\end{codeblocktu} +\end{example} + +\begin{example} +\begin{codeblock} +export module a +.b; // error: preprocessing token after \grammarterm{pp-module-name} is not \tcode{;} or \tcode{[} +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +export module M [[ +attr1, +attr2 ]] ; // OK +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +export module M +[[ attr1, +attr2 ]] ; // OK +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +export module M; int +n; // OK +\end{codeblock} +\end{example} \rSec1[cpp.import]{Header unit importation} \indextext{header unit!preprocessing}% @@ -1530,7 +1581,7 @@ \indextext{unit!translation}% A translation unit shall not \tcode{\#define} or \tcode{\#undef} macro names lexically identical -to keywords, +to keywords\iref{lex.key}, to the identifiers listed in \tref{lex.name.special}, or to the \grammarterm{attribute-token}{s} described in~\ref{dcl.attr}, except that the macro names \tcode{likely} and \tcode{unlikely} may be @@ -2097,9 +2148,8 @@ the following sequence of source lines begins with a source line that has a line number as specified by the digit sequence (interpreted as a decimal integer). -If the digit sequence specifies zero -or a number greater than 2147483647, -the program is ill-formed. +Digit sequences representing a number +outside of the range \crange{1}{2147483647} are conditionally supported. \pnum A preprocessing directive of the form @@ -2230,7 +2280,9 @@ \item \indextext{__line__@\mname{LINE}}% \mname{LINE}\\ -An integer literal representing the presumed line number of +The integer literal \tcode{0} or a decimal integer literal\iref{lex.icon}, +with no digit separators and no \grammarterm{integer-suffix}, +representing the presumed line number of the current source line within the current source file. \begin{note} The presumed line number can be changed by the \tcode{\#line} directive\iref{cpp.line}. @@ -2400,7 +2452,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_union} & \tcode{202502L} \\ \rowsep +\defnxname{cpp_trivial_union} & \tcode{202603L} \\ \rowsep \defnxname{cpp_unicode_characters} & \tcode{200704L} \\ \rowsep \defnxname{cpp_unicode_literals} & \tcode{200710L} \\ \rowsep \defnxname{cpp_user_defined_literals} & \tcode{200809L} \\ \rowsep @@ -2446,7 +2498,7 @@ \item \indextext{__stdcpp_threads__@\mname{STDCPP_THREADS}}% \mname{STDCPP_THREADS}\\ -Defined, and has the value integer literal 1, if and only if a program +Defined, and has the value integer literal \tcode{1}, if and only if a program can have more than one thread of execution\iref{intro.multithread}. \end{description} diff --git a/source/ranges.tex b/source/ranges.tex index 6d8022e929..18bed31c3c 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -1409,7 +1409,7 @@ Pursuant to \ref{namespace.std}, users may specialize \tcode{enable_borrowed_range} for cv-unqualified program-defined types. Such specializations shall be -usable in constant expressions\iref{expr.const} and +usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -1518,7 +1518,7 @@ users may specialize \tcode{disable_sized_range} for cv-unqualified program-defined types. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -1623,7 +1623,7 @@ for cv-unqualified program-defined types that model \libconcept{view}, and \tcode{false} for types that do not. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \end{itemdescr} @@ -4213,7 +4213,7 @@ \rSec2[range.adaptor.object]{Range adaptor objects} -\indexlibrarymisc{\idxcode{operator|}}{range adaptor closure objects}% +\indexlibrarymisc{\idxcode{operator"|}}{range adaptor closure objects}% \pnum A \defnadj{range adaptor closure}{object} is a unary function object that accepts a range argument. For @@ -7925,7 +7925,8 @@ } } - constexpr auto begin() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ { + constexpr auto begin() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ && + @\libconcept{forward_range}@ { return @\exposid{outer-iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } @@ -7935,7 +7936,8 @@ } constexpr auto end() const { - if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && @\libconcept{common_range}@) + if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && @\libconcept{common_range}@ && + @\libconcept{forward_range}@) return @\exposid{outer-iterator}@{*this, ranges::end(@\exposid{base_}@)}; else return default_sentinel; diff --git a/source/statements.tex b/source/statements.tex index 8b9e733dc0..3742c06e8a 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -35,6 +35,11 @@ \begin{bnf} \nontermdef{condition}\br expression\br + condition-declaration +\end{bnf} + +\begin{bnf} +\nontermdef{condition-declaration}\br \opt{attribute-specifier-seq} decl-specifier-seq declarator brace-or-equal-initializer\br structured-binding-declaration initializer \end{bnf} @@ -143,15 +148,15 @@ \pnum If a \grammarterm{condition} can be syntactically resolved -as either an expression or a declaration, +as either an \grammarterm{expression} or a \grammarterm{condition-declaration}, it is interpreted as the latter. \pnum -Let $D$ be any \grammarterm{condition} or \grammarterm{for-range-declaration}. -In the \grammarterm{decl-specifier-seq} of $D$, +For any \grammarterm{condition} or \grammarterm{for-range-declaration} $D$, +each \grammarterm{decl-specifier} +in the \grammarterm{decl-specifier-seq} of $D$, including that of any \grammarterm{structured-binding-declaration} of $D$, -each -\grammarterm{decl-specifier} shall be either a \grammarterm{type-specifier} +shall be either a \grammarterm{type-specifier} or \keyword{constexpr}. \rSec1[stmt.label]{Label}% @@ -262,7 +267,6 @@ \pnum \begin{note} A compound statement defines a block scope\iref{basic.scope}. -A declaration is a \grammarterm{statement}\iref{stmt.dcl}. \end{note} \rSec1[stmt.select]{Selection statements}% @@ -320,7 +324,7 @@ If the \keyword{if} statement is of the form \tcode{if constexpr}, the value of the condition is contextually converted to \keyword{bool} and -the converted expression shall be a constant expression\iref{expr.const}; +the converted expression shall be a constant expression\iref{expr.const.const}; this form is called a \defn{constexpr if} statement. If the value of the converted condition is \tcode{false}, the first substatement is a @@ -405,7 +409,7 @@ \pnum If a consteval if statement is evaluated in a context -that is manifestly constant-evaluated\iref{expr.const}, +that is manifestly constant-evaluated\iref{expr.const.defns}, the first substatement is executed. \begin{note} The first substatement is an immediate function context. @@ -461,7 +465,7 @@ \keyword{case} constant-expression \terminal{:} \end{ncbnf} where the \grammarterm{constant-expression} shall be -a converted constant expression\iref{expr.const} of the +a converted constant expression\iref{expr.const.const} of the adjusted type of the switch condition. No two of the case constants in the same switch shall have the same value after conversion. @@ -584,7 +588,7 @@ (or \tcode{true}, if the \tcode{for} statement has no \grammarterm{expression}). A \defnadj{trivial infinite}{loop} is a trivially empty iteration statement for which the converted controlling expression is a constant expression, -when interpreted as a \grammarterm{constant-expression}\iref{expr.const}, and +when interpreted as a \grammarterm{constant-expression}\iref{expr.const.const}, and evaluates to \tcode{true}. The \grammarterm{statement} of a trivial infinite loop is replaced with a call to the function \tcode{std::this_thread::yield}\iref{thread.thread.this}; @@ -822,7 +826,7 @@ \tcode{E.begin()} and \tcode{E.end()}, or \item argument-dependent lookups for \tcode{begin(E)} and for \tcode{end(E)} -each find at least one function or function template. +each find at least one viable candidate\iref{over.match.viable}. \end{itemize} \pnum @@ -869,10 +873,8 @@ \begin{codeblock} { @\grammarterm{init-statement}@ - constexpr auto&& @\exposidnc{range}@ = @\grammarterm{expansion-initializer}@; - constexpr auto @\exposidnc{begin}@ = @\exposidnc{begin-expr}@; // see \ref{stmt.ranged} - constexpr auto @\exposidnc{end}@ = @\exposidnc{end-expr}@; // see \ref{stmt.ranged} - + @\opt{constexpr}@ decltype(auto) @\exposidnc{range}@ = (@\grammarterm{expansion-initializer}@); + @\opt{constexpr}@ auto @\exposidnc{begin}@ = @\exposidnc{begin-expr}@; // see \ref{stmt.ranged} @$S_{0}$@ @\vdots@ @$S_{N-1}$@ @@ -880,30 +882,34 @@ \end{codeblock} where $N$ is the result of evaluating the expression \begin{codeblock} -[] consteval { +[&] consteval { std::ptrdiff_t result = 0; - for (auto i = @\exposid{begin}@; i != @\exposid{end}@; ++i) ++result; + auto b = @\exposid{begin-expr}@; + auto e = @\exposid{end-expr}@; + for (; b != e; ++b) ++result; return result; // distance from \exposid{begin} to \exposid{end} }() \end{codeblock} and $S_{i}$ is \begin{codeblock} { - constexpr auto @\exposid{iter}@ = @\exposid{begin}@ + decltype(begin - begin){@\placeholder{i}@}; + @\opt{constexpr}@ auto @\exposid{iter}@ = @\exposid{begin}@ + decltype(begin - begin){@\placeholder{i}@}; @\grammarterm{for-range-declaration}@ = *@\exposid{iter}@; @\grammarterm{compound-statement}@ } \end{codeblock} -The variables \exposid{range}, \exposid{begin}, \exposid{end}, and \exposid{iter} +The variables \exposid{range}, \exposid{begin}, and \exposid{iter} are defined for exposition only. +The keyword \keyword{constexpr} is present in the declarations +of \exposid{range}, \exposid{begin}, and \exposid{iter} +if and only if +\keyword{constexpr} is one of the \grammarterm{decl-specifier}{s} of +the \grammarterm{decl-specifier-seq} of +the \grammarterm{for-range-declaration}. The identifier \tcode{\placeholder{i}} is considered to be a prvalue of type \tcode{std::ptrdiff_t}; the program is ill-formed if \tcode{\placeholder{i}} is not representable as such a value. -\begin{note} -The instantiation is ill-formed if \exposid{range} -is not a constant expression\iref{expr.const}. -\end{note} \item Otherwise, $S$ is a destructuring expansion statement and, @@ -928,11 +934,14 @@ of the \grammarterm{expansion-initializer} and $S_{i}$ is \begin{codeblock} { - @\grammarterm{for-range-declaration}@ = @$u_{i}$@; + @\grammarterm{for-range-declaration}@ = @$v_{i}$@; @\grammarterm{compound-statement}@ } \end{codeblock} -The keyword \keyword{constexpr} is present in the declaration +If the \grammarterm{expansion-initializer} is an lvalue, then +$v_{i}$ is $u_{i}$; +otherwise, $v_{i}$ is \tcode{static_cast($u_{i}$)}. +The keyword \keyword{constexpr} is present in the \grammarterm{structured-binding-declaration} of $u_{0}, u_{1}, \dotsc, u_{N-1}$ if and only if \keyword{constexpr} is one of the \grammarterm{decl-specifier}s of the \grammarterm{decl-specifier-seq} @@ -1121,7 +1130,7 @@ equivalent to a \tcode{return} with no operand. Otherwise, flowing off the end of a function that is neither \tcode{main}\iref{basic.start.main} nor a coroutine\iref{dcl.fct.def.coroutine} -results in undefined behavior. +results in undefined behavior\ubdef{stmt.return.flow.off}. \pnum The copy-initialization of the result of the call is sequenced before the @@ -1217,7 +1226,7 @@ flowing off the end of a coroutine's \grammarterm{function-body} is equivalent to a \keyword{co_return} with no operand; otherwise flowing off the end of a coroutine's \grammarterm{function-body} -results in undefined behavior. +results in undefined behavior\ubdef{stmt.return.coroutine.flow.off}. \rSec2[stmt.goto]{The \keyword{goto} statement}% \indextext{statement!\idxcode{goto}} @@ -1300,7 +1309,8 @@ after its \grammarterm{init-declarator}. \indextext{initialization!jump past}% \indextext{\idxcode{goto}!initialization and}% -Upon each transfer of control (including sequential execution of statements) +Upon each transfer of control (including sequential execution of statements, +but excluding function calls) within a function from point $P$ to point $Q$, all block variables with automatic storage duration that are active at $P$ and not at $Q$ are destroyed in the reverse order of their construction. @@ -1356,7 +1366,7 @@ \end{note} If control re-enters the declaration recursively while -the variable is being initialized, the behavior is undefined. +the variable is being initialized, the behavior is undefined\ubdef{stmt.dcl.local.static.init.recursive}. \begin{example} \begin{codeblock} int foo(int i) { @@ -1448,7 +1458,7 @@ that a name in a template argument is bound to (part of) the declaration being parsed, the program is ill-formed. -No diagnostic is required. +No diagnostic is required\ifndrdef{stmt.ambig.bound.diff.parse}. \begin{example} \begin{codeblock} struct T1 { @@ -1464,7 +1474,7 @@ T1(a) = 3, T2(4), // \tcode{T2} will be declared as a variable of type \tcode{T1}, but this will not (*(*b)(T2(c)))(int(d)); // allow the last part of the declaration to parse properly, - // since it depends on \tcode{T2} being a type-name + // since it depends on \tcode{T2} being a \grammarterm{type-name} } \end{codeblock} \end{example} diff --git a/source/std.tex b/source/std.tex index ab1d082396..7180e68e55 100644 --- a/source/std.tex +++ b/source/std.tex @@ -166,6 +166,8 @@ \include{limits} \include{compatibility} \include{future} +\include{ub} +\include{ifndr} \include{uax31} %%-------------------------------------------------- diff --git a/source/strings.tex b/source/strings.tex index 3bc1e0268a..d2c0d62791 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -2014,6 +2014,8 @@ \tcode{data() + size()} points at an object with value \tcode{charT()} (a ``null terminator''\indextext{string!null terminator}), and \tcode{size() <= capacity()} is \tcode{true}. +The program has undefined behavior if +the null terminator is modified to any value other than \tcode{charT()}. \indexlibraryglobal{basic_string}% @@ -3101,10 +3103,7 @@ \pnum \returns -\tcode{*(begin() + pos)} if \tcode{pos < size()}. Otherwise, -returns a reference to an object of type \tcode{charT} with value -\tcode{charT()}, where modifying the object to any value other than -\tcode{charT()} leads to undefined behavior. +\tcode{data()[pos]}. \pnum \throws @@ -4291,42 +4290,17 @@ \begin{itemdecl} constexpr const charT* c_str() const noexcept; constexpr const charT* data() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A pointer \tcode{p} such that \tcode{p + i == addressof(operator[](i))} for each -\tcode{i} in \crange{0}{size()}. - -\pnum -\complexity -Constant time. - -\pnum -\remarks -The program shall not modify any of the values stored in the character array; otherwise, the behavior is undefined. -\end{itemdescr} - -\indexlibrarymember{data}{basic_string}% -\begin{itemdecl} constexpr charT* data() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -A pointer \tcode{p} such that \tcode{p + i == addressof(operator[](i))} for each -\tcode{i} in \crange{0}{size()}. +\tcode{to_address(begin())}. \pnum \complexity Constant time. - -\pnum -\remarks -The program shall not modify the value stored at \tcode{p + size()} -to any value other than \tcode{charT()}; otherwise, the behavior is undefined. \end{itemdescr} \indexlibrarymember{operator basic_string_view}{basic_string}% @@ -4443,7 +4417,11 @@ Equivalent to: \begin{codeblock} basic_string_view s = *this, sv = t; -return s.@\placeholder{G}@(sv, pos); +if (auto result = s.@\placeholder{G}@(sv, pos); result == s.npos) { + return npos; +} else { + return result; +} \end{codeblock} \pnum diff --git a/source/support.tex b/source/support.tex index f4f632944b..ce4a1c9271 100644 --- a/source/support.tex +++ b/source/support.tex @@ -844,6 +844,7 @@ #define @\defnlibxname{cpp_lib_ssize}@ 201902L // freestanding, also in \libheader{iterator} #define @\defnlibxname{cpp_lib_sstream_from_string_view}@ 202306L // also in \libheader{sstream} #define @\defnlibxname{cpp_lib_stacktrace}@ 202011L // also in \libheader{stacktrace} +#define @\defnlibxname{cpp_lib_start_lifetime}@ 202603L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_start_lifetime_as}@ 202207L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_starts_ends_with}@ 201711L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_stdatomic_h}@ 202011L // also in \libheader{stdatomic.h} @@ -997,7 +998,9 @@ \item \indexlibraryglobal{round_to_nearest}% \tcode{round_to_nearest} -if the rounding style is to the nearest representable value +if the rounding style is to the nearest representable value; +if there are two equally near such values, +the one with an even least significant digit is chosen \item \indexlibraryglobal{round_toward_infinity}% \tcode{round_toward_infinity} @@ -1110,11 +1113,6 @@ \pnum \indextext{signal-safe!\idxcode{numeric_limits} members}% Each member function defined in this subclause is signal-safe\iref{support.signal}. -\begin{note} -\indextext{LIA-1}% -The arithmetic specification described in ISO/IEC 10967-1:2012 is -commonly termed LIA-1. -\end{note} \indexlibrarymember{min}{numeric_limits}% \begin{itemdecl} @@ -1324,10 +1322,6 @@ \begin{itemdescr} \pnum Measure of the maximum rounding error. -\begin{footnote} -Rounding error is described in ISO/IEC 10967-1:2012 Section 5.2.4 and -Annex C Rationale Section C.5.2.4 --- Rounding and rounding constants. -\end{footnote} \end{itemdescr} \indexlibrarymember{min_exponent}{numeric_limits}% @@ -1434,9 +1428,6 @@ \pnum \tcode{true} if the type has a representation for a quiet (non-signaling) ``Not a Number''. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all floating-point types. @@ -1456,9 +1447,6 @@ \begin{itemdescr} \pnum \tcode{true} if the type has a representation for a signaling ``Not a Number''. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all floating-point types. @@ -1478,9 +1466,6 @@ \begin{itemdescr} \pnum Representation of positive infinity, if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations for which @@ -1497,9 +1482,6 @@ \begin{itemdescr} \pnum Representation of a quiet ``Not a Number'', if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations for which @@ -1516,9 +1498,6 @@ \begin{itemdescr} \pnum Representation of a signaling ``Not a Number'', if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations for which @@ -1536,9 +1515,6 @@ \indextext{number!subnormal}% \pnum Minimum positive subnormal value, if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} Otherwise, minimum positive normalized value. \pnum @@ -1574,9 +1550,6 @@ \begin{itemdescr} \pnum \tcode{true} if the set of values representable by the type is finite. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \begin{note} All fundamental types\iref{basic.fundamental} are bounded. This member would be \tcode{false} for arbitrary precision types. @@ -1594,9 +1567,6 @@ \begin{itemdescr} \pnum \tcode{true} if the type is modulo. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} A type is modulo if, for any operation involving \tcode{+}, \tcode{-}, or \tcode{*} on values of that type whose result would fall outside the range \crange{min()}{max()}, the value returned differs from the true value by an @@ -1623,9 +1593,6 @@ \tcode{true} if, at the start of the program, there exists a value of the type that would cause an arithmetic operation using that value to trap. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations. @@ -1643,7 +1610,6 @@ \begin{footnote} Refer to \IsoFloatUndated{}. -Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1660,7 +1626,6 @@ The rounding style for the type. \begin{footnote} Equivalent to \tcode{FLT_ROUNDS}. -Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -2407,8 +2372,8 @@ constexpr void* operator new (std::size_t size, void* ptr) noexcept; constexpr void* operator new[](std::size_t size, void* ptr) noexcept; -void operator delete (void* ptr, void*) noexcept; -void operator delete[](void* ptr, void*) noexcept; +constexpr void operator delete (void* ptr, void*) noexcept; +constexpr void operator delete[](void* ptr, void*) noexcept; \end{codeblock} \rSec2[new.delete]{Storage allocation and deallocation} @@ -2978,7 +2943,7 @@ \indexlibrarymember{delete}{operator}% \begin{itemdecl} -void operator delete(void* ptr, void*) noexcept; +constexpr void operator delete(void* ptr, void*) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2996,7 +2961,7 @@ \indexlibrarymember{delete}{operator}% \begin{itemdecl} -void operator delete[](void* ptr, void*) noexcept; +constexpr void operator delete[](void* ptr, void*) noexcept; \end{itemdecl} \begin{itemdescr} @@ -3181,9 +3146,12 @@ \pnum \expects \tcode{p} represents the address \placeholder{A} of a byte in memory. -An object \placeholder{X} that is within its lifetime\iref{basic.life} -and whose type is similar\iref{conv.qual} to \tcode{T} -is located at the address \placeholder{A}. +An object \placeholder{X} +whose type is similar\iref{conv.qual} to \tcode{T} +is located at the address \placeholder{A}, and +is either within its lifetime\iref{basic.life} or +is an array element subobject +whose containing array object is within its lifetime. All bytes of storage that would be reachable through\iref{basic.compound} the result are reachable through \tcode{p}. @@ -5703,7 +5671,7 @@ \pnum There is an \impldef{total ordering of all types} total ordering of all types. For any (possibly incomplete) types \tcode{X} and \tcode{Y}, -the expression \tcode{\exposid{TYPE-ORDER}(X, Y)} is a constant expression\iref{expr.const} +the expression \tcode{\exposid{TYPE-ORDER}(X, Y)} is a constant expression\iref{expr.const.const} of type \tcode{strong_ordering}\iref{cmp.strongord}. Its value is \tcode{strong_ordering::less} if \tcode{X} precedes \tcode{Y} in this implementation-defined total order, @@ -5832,8 +5800,7 @@ \begin{codeblock} namespace std { template<> - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.con}, construct/reset constexpr coroutine_handle() noexcept; constexpr coroutine_handle(nullptr_t) noexcept; @@ -5857,8 +5824,7 @@ }; template - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.con}, construct/reset constexpr coroutine_handle() noexcept; constexpr coroutine_handle(nullptr_t) noexcept; @@ -6170,8 +6136,7 @@ \begin{codeblock} namespace std { template<> - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.noop.conv}, conversion constexpr operator coroutine_handle<>() const noexcept; diff --git a/source/templates.tex b/source/templates.tex index 6cf798ea56..e13dd204ad 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -193,7 +193,8 @@ \begin{itemize} \item a template, \item an entity defined\iref{basic.def} or created\iref{class.temporary} - within the \grammarterm{compound-statement} + within the + \grammarterm{for-range-declaration} or \grammarterm{compound-statement} of an \grammarterm{expansion-statement}\iref{stmt.expand}, \item an entity defined or created in a templated entity, \item a member of a templated entity, @@ -248,7 +249,7 @@ shall be reachable from the end of every definition domain\iref{basic.def.odr} in which it is implicitly instantiated\iref{temp.inst} unless the corresponding specialization is explicitly instantiated\iref{temp.explicit} -in some translation unit; no diagnostic is required. +in some translation unit; no diagnostic is required\ifndrdef{temp.pre.reach.def}. \rSec1[temp.param]{Template parameters} @@ -531,6 +532,8 @@ There can be template parameter objects of array type\iref{meta.define.static}, but such an object is never denoted by an \grammarterm{id-expression} that names a constant template parameter. +Such an object can have an address that +is not unique among all other in-lifetime objects\iref{intro.object}. \end{note} \begin{note} If an \grammarterm{id-expression} names @@ -1137,7 +1140,7 @@ template void f(); void g() { - f(); // \tcode{int()} is a type-id: call the first \tcode{f()} + f(); // \tcode{int()} is a \grammarterm{type-id}: call the first \tcode{f()} } \end{codeblock} \end{example} @@ -1320,7 +1323,7 @@ is determined from its template argument $A$ as follows. If \tcode{T} is not a class type and $A$ is not a \grammarterm{braced-init-list}, -$A$ shall be a converted constant expression\iref{expr.const} +$A$ shall be a converted constant expression\iref{expr.const.const} of type \tcode{T}; the value of $P$ is $A$ (as converted). \pnum @@ -1349,7 +1352,7 @@ \item the full-expression of an invented \grammarterm{init-declarator} for the initialization would not be a constant expression -when interpreted as a \grammarterm{constant-expression}\iref{expr.const}, or +when interpreted as a \grammarterm{constant-expression}\iref{expr.const.const}, or \item the initialization would cause $P$ to not be template-argument-equivalent\iref{temp.type} to \tcode{v}, \end{itemize} @@ -1511,7 +1514,7 @@ specialization based on the template template parameter is instantiated. If a specialization is not reachable from the point of instantiation, and it would have been selected had it been reachable, the program is ill-formed, -no diagnostic required. +no diagnostic required\ifndrdef{temp.arg.template.sat.constraints}. \begin{example} \begin{codeblock} template class A { // primary template @@ -1868,7 +1871,7 @@ if the validity or meaning of the program depends on whether two constructs are equivalent, and they are functionally equivalent but not equivalent, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.constr.atomic.equiv.but.not.equiv}. \begin{example} \begin{codeblock} template void f2() @@ -1899,7 +1902,7 @@ results in \tcode{true}. If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.constr.atomic.sat.result.diff}. \begin{example} \begin{codeblock} template concept C = @@ -2193,7 +2196,7 @@ in the normal form \tcode{N} of \tcode{CE}, appearances of \tcode{C}{'s} template parameters in the parameter mappings of the atomic constraints in \tcode{N} -with their respective arguments from \tcode{C}. +with their respective arguments from \tcode{CI}. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required. \end{itemize} @@ -2252,7 +2255,7 @@ after substituting in \tcode{E$_i$} the respective $i^\text{th}$ concept argument of each \tcode{P$_k$}. If any such substitution results in an invalid type or expression, - the program is ill-formed; no diagnostic is required. + the program is ill-formed; no diagnostic is required\ifndrdef{temp.constr.normal.invalid}. \item Otherwise, the normal form of \tcode{F} is @@ -2573,7 +2576,9 @@ they are of reference type and they refer to the same object or function, or \item -they are of array type and their corresponding elements are template-argument-equivalent, +they are of array type and their corresponding elements are either +both within their lifetimes and template-argument-equivalent or +both not within their lifetimes, \begin{footnote} An array as a \grammarterm{template-parameter} decays to a pointer. \end{footnote} @@ -2677,31 +2682,30 @@ which shall be a class or variable template. \pnum +A \defnadj{separately instantiated}{construct} +of a templated function \tcode{F} is a +\begin{itemize} +\item default argument, +\item \grammarterm{noexcept-specifier}, or +\item \grammarterm{function-contract-specifier} +\end{itemize} +of \tcode{F}. For purposes of name lookup and instantiation, -default arguments, -\grammarterm{type-constraint}{s}, -\grammarterm{requires-clause}{s}\iref{temp.pre}, -and -\grammarterm{noexcept-specifier}{s} -of function templates -and -of member functions of class templates +separately instantiated constructs, +\grammarterm{type-constraint}{s}, and +\grammarterm{requires-clause}{s}\iref{temp.pre} are considered definitions; each -default argument, -\grammarterm{type-constraint}, -\grammarterm{requires-clause}, -or -\grammarterm{noexcept-specifier} +separately instantiated construct, +\grammarterm{type-constraint}, or +\grammarterm{requires-clause} is a separate definition which is unrelated to the templated function definition or to any other -default arguments, -\grammarterm{type-constraint}{s}, -\grammarterm{requires-clause}{s}, -or -\grammarterm{noexcept-specifier}{s}. +separately instantiated constructs, +\grammarterm{type-constraint}{s}, or +\grammarterm{requires-clause}{s}. For the purpose of instantiation, the substatements of a constexpr if statement\iref{stmt.if} are considered definitions. For the purpose of name lookup and instantiation, @@ -3735,7 +3739,7 @@ that template. A partial specialization shall be reachable from any use of a template specialization that would make use of the partial specialization as the result of -an implicit or explicit instantiation; no diagnostic is required. +an implicit or explicit instantiation; no diagnostic is required\ifndrdef{temp.spec.partial.general.partial.reachable}. \pnum Two partial specialization declarations declare the same entity @@ -4288,7 +4292,7 @@ \end{codeblock} \end{example} \indextext{expression!functionally equivalent|see{functionally equivalent, expressions}}% -Two potentially-evaluated expressions involving template parameters that are not equivalent are +Two potentially evaluated expressions involving template parameters that are not equivalent are \defnx{functionally equivalent}{functionally equivalent!expressions} if, for any given set of template arguments, the evaluation of the expression results in the same value. @@ -4345,7 +4349,7 @@ If the validity or meaning of the program depends on whether two constructs are equivalent, and they are functionally equivalent but not equivalent, the program is ill-formed, -no diagnostic required. +no diagnostic required\ifndrdef{temp.over.link.equiv.not.equiv}. Furthermore, if two declarations $A$ and $B$ of function templates \begin{itemize} \item @@ -4404,10 +4408,10 @@ \item when the address of a function template specialization is taken; \item -when a placement operator delete that is a +when a placement deallocation function that is a function template specialization -is selected to match a placement operator new\iref{basic.stc.dynamic.deallocation,expr.new}; +is selected to match a placement allocation function\iref{basic.stc.dynamic.deallocation,expr.new}; \item when a friend function declaration\iref{temp.friend}, an explicit instantiation\iref{temp.explicit} or an explicit specialization\iref{temp.expl.spec} refers to @@ -4911,7 +4915,7 @@ introduced in a declaration that is reachable from the point of instantiation of a specialization\iref{temp.point} but is not found by lookup for the specialization, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.res.general.default.but.not.found}. \begin{bnf} \nontermdef{typename-specifier}\br @@ -5130,7 +5134,7 @@ \item an instantiation uses a default argument or default template argument that had not been defined at the point at which the template was defined, or -\item constant expression evaluation\iref{expr.const} within the template +\item constant expression evaluation\iref{expr.const.core} within the template instantiation uses \begin{itemize} \item the value of a const object of integral or unscoped enumeration type or @@ -5361,7 +5365,7 @@ \defnx{type-dependent}{expression!type-dependent} (that is, its type may depend on a template parameter) or \defnx{value-dependent}{expression!value-dependent} -(that is, its value when evaluated as a constant expression\iref{expr.const} +(that is, its value when evaluated as a constant expression\iref{expr.const.const} may depend on a template parameter) as described below. @@ -5557,7 +5561,7 @@ its lookup context, if it is a qualified name, is the current instantiation, and \item -lookup for it finds any member of a class that is the current instantiation +lookup for it finds any member of a class that is the current instantiation. \end{itemize} \begin{example} \begin{codeblock} @@ -5660,7 +5664,9 @@ is dependent if \begin{itemize} \item -it has a dependent initializer, or +it has a dependent initializer, +\item +it refers to a type template template parameter, or \item it refers to an alias template that is a member of the current instantiation and @@ -5953,7 +5959,7 @@ it names a static member function that is a dependent member of the current instantiation, or \item -it names a potentially-constant variable\iref{expr.const} +it names a potentially-constant variable\iref{expr.const.init} that is initialized with an expression that is value-dependent. \end{itemize} @@ -6022,7 +6028,7 @@ instantiation is value-dependent. An expression of the form \tcode{\&}\grammarterm{cast-expression} is also value-dependent if evaluating \grammarterm{cast-expression} -as a core constant expression\iref{expr.const} succeeds and +as a core constant expression\iref{expr.const.core} succeeds and the result of the evaluation refers to a templated entity that is an object with static or thread storage duration or a member function. @@ -6031,12 +6037,13 @@ \begin{itemize} \item it is of the form \tcode{\caret\caret \grammarterm{reflection-name}} and -the \grammarterm{reflection-name} +either lookup for the \grammarterm{reflection-name} finds a declaration that +inhabits a scope corresponding to a templated entity or +the \grammarterm{reflection-name} is \begin{itemize} -\item is a dependent qualified name, -\item is a dependent \grammarterm{namespace-name}, -\item is the name of a template parameter, or -\item names a dependent member of the current instantiation\iref{temp.dep.type}, +\item a dependent qualified name, +\item a dependent \grammarterm{namespace-name}, or +\item the name of a template parameter, \end{itemize} \item it is of the form \tcode{\caret\caret \grammarterm{type-id}} and @@ -6165,11 +6172,13 @@ For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, -if the specialization is implicitly instantiated because it is referenced -from within another template specialization and -the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation -of the enclosing specialization. +of the enclosing specialization if +\begin{itemize} +\item the specialization is implicitly instantiated +because it is referenced from within another template specialization and +\item the context from which it is referenced depends on a template parameter. +\end{itemize} Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization. @@ -6183,12 +6192,16 @@ \pnum For a \grammarterm{noexcept-specifier} of a function template -specialization or specialization of a member function of a class template, if -the \grammarterm{noexcept-specifier} is implicitly instantiated because -it is needed by another template specialization and the context that requires -it depends on a template parameter, the point of instantiation of the +specialization or specialization of a member function of a class template, +the point of instantiation of the \grammarterm{noexcept-specifier} is the point of instantiation of the -specialization that requires it. Otherwise, the point of instantiation for such +specialization that requires it if +\begin{itemize} +\item the \grammarterm{noexcept-specifier} is implicitly instantiated +because it is needed by another template specialization and +\item the context that requires it depends on a template parameter. +\end{itemize} +Otherwise, the point of instantiation for such a \grammarterm{noexcept-specifier} immediately follows the namespace scope declaration or definition that requires the \grammarterm{noexcept-specifier}. @@ -6196,14 +6209,16 @@ \pnum For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, -if the specialization is implicitly instantiated because it is referenced -from within another template specialization, -if the context from which the specialization is referenced depends on a -template parameter, -and if the specialization is not instantiated previous to the instantiation of -the enclosing template, the point of instantiation is immediately before the point of instantiation of -the enclosing template. +the enclosing template if +\begin{itemize} +\item the specialization is implicitly instantiated +because it is referenced from within another template specialization, +\item the context from which the specialization is referenced +depends on a template parameter, and +\item the specialization is not instantiated +previous to the instantiation of the enclosing template. +\end{itemize} Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization. @@ -6246,7 +6261,7 @@ translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule\iref{basic.def.odr}, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.point.diff.pt.diff.meaning}. \pnum For the \grammarterm{compound-statement} @@ -6266,7 +6281,7 @@ introduced in the associated namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts\iref{basic.lookup.argdep}, -then the program is ill-formed, no diagnostic required. +then the program is ill-formed, no diagnostic required\ifndrdef{temp.dep.candidate.different.lookup.different}. \pnum \begin{example} @@ -6585,7 +6600,7 @@ declared with a type deduced from its initializer or return value\iref{dcl.spec.auto}, \item -a potentially-constant variable\iref{expr.const}, or +a potentially-constant variable\iref{expr.const.init}, or \item a specialization of a templated class. \end{itemize} @@ -6635,19 +6650,6 @@ X ch; // error: incomplete type \tcode{X} \end{codeblock} \end{example} -\begin{note} -Within a template declaration, -a local class\iref{class.local} or enumeration and the members of -a local class are never considered to be entities that can be separately -instantiated (this includes their default arguments, -\grammarterm{noexcept-specifier}{s}, and non-static data member -initializers, if any, -but not their \grammarterm{type-constraint}{s} or \grammarterm{requires-clause}{s}). -As a result, the dependent names are looked up, the -semantic constraints are checked, and any templates used are instantiated as -part of the instantiation of the entity within which the local class or -enumeration is declared. -\end{note} \pnum The implicit instantiation of a class template specialization causes @@ -6667,10 +6669,6 @@ unscoped member enumerations, and member anonymous unions. \end{itemize} -The implicit instantiation of a class template specialization -does not cause the implicit instantiation of -default arguments or \grammarterm{noexcept-specifier}{s} -of the class member functions. \begin{example} \begin{codeblock} template @@ -6734,11 +6732,6 @@ implicitly instantiated when it is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. -Unless a call is to a function template explicit specialization or -to a member function of an explicitly specialized class template, -a default argument for a function template or a member function of a -class template is implicitly instantiated when the function is -called in a context that requires the value of the default argument. \begin{note} An inline function that is the subject of an explicit instantiation declaration @@ -6795,7 +6788,7 @@ The existence of a definition of a variable or function is considered to affect the semantics of the program if the variable or function -is needed for constant evaluation by an expression\iref{expr.const}, +is needed for constant evaluation by an expression\iref{expr.const.defns}, even if constant evaluation of the expression is not required or if constant expression evaluation does not use the definition. @@ -6869,7 +6862,25 @@ causes specializations in the default member initializer to be instantiated. \pnum -If a templated function +The separately instantiated constructs\iref{temp.decls.general} +of a templated function \tcode{F} that is either +\begin{itemize} +\item +a member of a local class or +\item +the function call operator of the closure type +of a non-generic lambda-expression +\end{itemize} +are instantiated when the declaration of \tcode{F} is instantiated. +\begin{note} +For the purposes of instantiation, +these constructs are still considered separately +from the function to which they belong. +\end{note} + +\pnum +Other than as specified above, +when a templated function \tcode{f} is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, @@ -6888,7 +6899,9 @@ \tcode{f}. \pnum +\begin{note} Each default argument is instantiated independently. +\end{note} \begin{example} \begin{codeblock} template void f(T x, T y = ydef(T()), T z = zdef(T())); @@ -6906,16 +6919,16 @@ \end{example} \pnum -The \grammarterm{noexcept-specifier} and \grammarterm{function-contract-specifier}s -of a function template specialization -are not instantiated along with the function declaration; -they are instantiated -when needed\iref{except.spec,dcl.contract.func}. If such a -specifier is needed but has not yet been -instantiated, the dependent names are looked up, the semantics constraints are -checked, and the instantiation of any template used in the -specifier is done as if it were being done as part -of instantiating the declaration of the specialization at that point. +Other than as specified above, +the separately instantiated constructs +of a specialization of a templated function +are instantiated only when needed\iref{except.spec,dcl.contract.func}. +When such a construct is instantiated, +the dependent names are looked up, +the semantics constraints are checked, and +the instantiation of any template used in the construct +is done as if it were being done as part of instantiating the declaration +of the specialization at that point. \pnum \begin{note} @@ -6926,7 +6939,7 @@ There is an \impldef{maximum depth of recursive template instantiations} quantity that specifies the limit on the total depth of recursive instantiations\iref{implimits}, which could involve more than one template. -The result of an infinite recursion in instantiation is undefined. +The result of an infinite recursion in instantiation is undefined\ubdef{temp.inst.inf.recursion}. \begin{example} \begin{codeblock} template class X { @@ -7155,7 +7168,7 @@ in a way that would otherwise cause an implicit instantiation\iref{temp.inst} in the translation unit shall be the subject of an explicit instantiation definition somewhere in the -program; otherwise the program is ill-formed, no diagnostic required. +program; otherwise the program is ill-formed, no diagnostic requiredi\ifndrdef{temp.explicit.decl.implicit.inst}. \begin{note} This rule does apply to inline functions even though an explicit instantiation declaration of such an entity has no other normative @@ -7357,11 +7370,11 @@ every use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; -no diagnostic is required. +no diagnostic is required\ifndrdef{temp.expl.spec.unreachable.declaration}. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.expl.spec.missing.definition}. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. \begin{example} @@ -7726,7 +7739,7 @@ int j = f(5.6); // error: \tcode{X} cannot be deduced f(f); // \tcode{Y} for outer \tcode{f} deduced as \tcode{int (*)(bool)} f(f); // error: \tcode{f} does not denote a single function template specialization - int k = g(5.6); // \tcode{Y} deduced as double; \tcode{Z} deduced as an empty sequence + int k = g(5.6); // \tcode{Y} deduced as \tcode{double}; \tcode{Z} deduced as an empty sequence f(g); // \tcode{Y} for outer \tcode{f} deduced as \tcode{int (*)(bool)}, // \tcode{Z} deduced as an empty sequence } @@ -7998,7 +8011,7 @@ a condition that causes deduction to fail is encountered. If substitution into different declarations of the same function template would cause template instantiations to occur in a different order or not at all, -the program is ill-formed; no diagnostic required. +the program is ill-formed; no diagnostic required\ifndrdef{temp.deduct.general.diff.order}. \begin{note} The equivalent substitution in exception specifications\iref{except.spec} @@ -8039,20 +8052,40 @@ \end{note} Invalid types and expressions can result in a deduction failure only in the immediate context of the deduction substitution loci. +The \defnadj{immediate}{context} of a deduction substitution locus +is that deduction substitution locus, +excluding bodies of \grammarterm{lambda-expression}s and separately instantiated constructs. +\begin{example} +\begin{codeblock} +template +T* fun(T&& v); // \#1: the deduction substitution locus is the function type + // ``function of (rvalue reference to \tcode{T}) returning pointer to \tcode{T}'' + +void fun(...); // \#2 + +void test() +{ + int i; + fun(i); // selects \#2 (forming the type ``pointer to reference to \tcode{int}'' fails in \#1) +} +\end{codeblock} +\end{example} +\begin{note} +Separately instantiated constructs are excluded from the immediate contexts +even if they are instantiated at the same time. +\end{note} \begin{note} The substitution into types and expressions can result -in effects such as the instantiation of class template specializations and/or -function template specializations, the generation of implicitly-defined functions, -etc. Such effects are not in the ``immediate context'' and can result in the -program being ill-formed. +in effects such as the instantiation of template specializations, +the generation of implicitly-defined functions, etc. +Such effects are not in the immediate context +and can result in the program being ill-formed. \end{note} \pnum -When substituting into a \grammarterm{lambda-expression}, -substitution into its body is not in the immediate context. \begin{note} -The intent is to avoid requiring implementations to deal with -substitution failure involving arbitrary statements. +No \grammarterm{statement} is ever in the immediate context +of a deduction substitution locus. \begin{example} \begin{codeblock} template @@ -8772,18 +8805,16 @@ \end{itemize} \pnum -Using the resulting types -\tcode{P} -and -\tcode{A}, +If \tcode{A} was transformed from a function parameter pack and +\tcode{P} is not a parameter pack, +type deduction fails. +Otherwise, using the resulting types \tcode{P} and \tcode{A}, the deduction is then done as described in~\ref{temp.deduct.type}. If \tcode{P} is a function parameter pack, the type \tcode{A} of each remaining parameter type of the argument template is compared with the type \tcode{P} of the \grammarterm{declarator-id} of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. -Similarly, if \tcode{A} was transformed from a function parameter pack, -it is compared with each remaining parameter type of the parameter template. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template. @@ -9631,12 +9662,12 @@ for explicit instantiations\iref{temp.explicit}, explicit specializations\iref{temp.expl.spec}, and certain friend declarations\iref{temp.friend}. This is also done to determine whether a deallocation function template specialization matches a placement -\tcode{operator new}\iref{basic.stc.dynamic.deallocation,expr.new}. +allocation function\iref{basic.stc.dynamic.deallocation,expr.new}. In all these cases, \tcode{P} is the type of the function template being considered as a potential match and \tcode{A} is either the function type from the declaration or the type of the deallocation function that would match the placement -\tcode{operator new} as described in~\ref{expr.new}. The +allocation function as described in~\ref{expr.new}. The deduction is done as described in~\ref{temp.deduct.type}. \pnum diff --git a/source/text.tex b/source/text.tex index b89eaa3ea4..473255ae52 100644 --- a/source/text.tex +++ b/source/text.tex @@ -1305,7 +1305,7 @@ \pnum The \tcode{put()} members make no provision for error reporting. -(Any failures of the OutputIterator argument can be extracted from +(Any failures of the \tcode{OutputIterator} argument can be extracted from the returned iterator.) The \tcode{get()} members take an \tcode{ios_base::iostate\&} argument whose value they ignore, @@ -5698,7 +5698,7 @@ The \tcode{text_encoding::id} enumeration contains an enumerator for each known registered character encoding. For each encoding, the corresponding enumerator is derived from -the alias beginning with ``\tcode{cs}'', as follows +the alias beginning with ``\tcode{cs}'', as follows: \begin{itemize} \item \tcode{csUnicode} is mapped to \tcode{text_encoding::id::UCS2}, @@ -6394,19 +6394,31 @@ \item For integral types, the locale-specific form causes the context's locale to be used -to insert the appropriate digit group separator characters. +to insert the appropriate digit group separator characters +as if obtained with +\tcode{numpunct::grouping} and +\tcode{numpunct::thousands_sep}. \item For floating-point types, the locale-specific form causes the context's locale to be used -to insert the appropriate digit group and radix separator characters. +to insert the appropriate digit group and radix separator characters +as if obtained with +\tcode{numpunct::grouping}, +\tcode{numpunct::thousands_sep}, and +\tcode{numpunct::decimal_point}. \item For the textual representation of \tcode{bool}, the locale-specific form causes the context's locale to be used to insert the appropriate string as if obtained -with \tcode{numpunct::truename} or \tcode{numpunct::falsename}. +with \tcode{numpunct::truename} or \tcode{numpunct::\brk{}falsename}. \end{itemize} +If the string literal encoding is a Unicode encoding form and +the locale is among an implementation-defined set of locales, +each replacement that depends on the locale is performed as if +the replacement character sequence is converted to +the string literal encoding. \pnum The \fmtgrammarterm{type} determines how the data should be presented. @@ -6434,7 +6446,9 @@ let \range{first}{last} be a range large enough to hold the \tcode{to_chars} output and \tcode{value} be the formatting argument value. -Formatting is done as if by calling \tcode{to_chars} as specified +Formatting is done as if by calling \tcode{to_chars} as specified, +transcoding the \tcode{to_chars} output to the wide literal encoding if +\tcode{charT} is \tcode{wchar_t}, and copying the output through the output iterator of the format context. \begin{note} Additional padding and adjustments are performed @@ -6700,7 +6714,7 @@ \pnum \remarks -A call to this function is not a core constant expression\iref{expr.const} +A call to this function is not a core constant expression\iref{expr.const.core} unless there exist \tcode{args} of types \tcode{Args} such that \exposid{str} is a format string for \tcode{args}. \end{itemdescr} @@ -6722,7 +6736,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - string format(format_string fmt, Args&&... args); + constexpr string format(format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6737,7 +6751,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - wstring format(wformat_string fmt, Args&&... args); + constexpr wstring format(wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6781,8 +6795,8 @@ \indexlibraryglobal{vformat}% \begin{itemdecl} -string vformat(string_view fmt, format_args args); -wstring vformat(wstring_view fmt, wformat_args args); +constexpr string vformat(string_view fmt, format_args args); +constexpr wstring vformat(wstring_view fmt, wformat_args args); string vformat(const locale& loc, string_view fmt, format_args args); wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); \end{itemdecl} @@ -6803,7 +6817,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, format_string fmt, Args&&... args); + constexpr Out format_to(Out out, format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6818,7 +6832,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, wformat_string fmt, Args&&... args); + constexpr Out format_to(Out out, wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6863,9 +6877,9 @@ \indexlibraryglobal{vformat_to}% \begin{itemdecl} template - Out vformat_to(Out out, string_view fmt, format_args args); + constexpr Out vformat_to(Out out, string_view fmt, format_args args); template - Out vformat_to(Out out, wstring_view fmt, wformat_args args); + constexpr Out vformat_to(Out out, wstring_view fmt, wformat_args args); template Out vformat_to(Out out, const locale& loc, string_view fmt, format_args args); template @@ -6905,11 +6919,13 @@ \indexlibraryglobal{format_to_n}% \begin{itemdecl} template - format_to_n_result format_to_n(Out out, iter_difference_t n, - format_string fmt, Args&&... args); + constexpr format_to_n_result format_to_n(Out out, iter_difference_t n, + format_string fmt, + Args&&... args); template - format_to_n_result format_to_n(Out out, iter_difference_t n, - wformat_string fmt, Args&&... args); + constexpr format_to_n_result format_to_n(Out out, iter_difference_t n, + wformat_string fmt, + Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, format_string fmt, @@ -6962,9 +6978,9 @@ \indexlibraryglobal{formatted_size}% \begin{itemdecl} template - size_t formatted_size(format_string fmt, Args&&... args); + constexpr size_t formatted_size(format_string fmt, Args&&... args); template - size_t formatted_size(wformat_string fmt, Args&&... args); + constexpr size_t formatted_size(wformat_string fmt, Args&&... args); template size_t formatted_size(const locale& loc, format_string fmt, Args&&... args); template @@ -7107,7 +7123,7 @@ Pursuant to \ref{namespace.std}, users may specialize \tcode{enable_nonlocking_formatter_optimization} for cv-unqualified program-defined types. -Such specializations shall be usable in constant expressions\iref{expr.const} +Such specializations shall be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \end{itemdescr} @@ -7606,7 +7622,7 @@ \remarks Let \tcode{\placeholder{cur-arg-id}} be the value of \tcode{next_arg_id_} prior to this call. Call expressions where \tcode{\placeholder{cur-arg-id} >= num_args_} is \tcode{true} -are not core constant expressions\iref{expr.const}. +are not core constant expressions\iref{expr.const.core}. \end{itemdescr} \indexlibrarymember{check_arg_id}{basic_format_parse_context}% @@ -7633,7 +7649,7 @@ \pnum \remarks -A call to this function is a core constant expression\iref{expr.const} only if +A call to this function is a core constant expression\iref{expr.const.core} only if \tcode{id < num_args_} is \tcode{true}. \end{itemdescr} @@ -7761,7 +7777,7 @@ \recommended For a given type \tcode{charT}, implementations should provide -a single instantiation of \tcode{basic_format_context} +a single specialization of \tcode{basic_format_context} for appending to \tcode{basic_string}, \tcode{vector}, @@ -7771,7 +7787,7 @@ \indexlibrarymember{arg}{basic_format_context}% \begin{itemdecl} -basic_format_arg arg(size_t id) const noexcept; +constexpr basic_format_arg arg(size_t id) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -7795,7 +7811,7 @@ \indexlibrarymember{out}{basic_format_context}% \begin{itemdecl} -iterator out(); +constexpr iterator out(); \end{itemdecl} \begin{itemdescr} @@ -7806,7 +7822,7 @@ \indexlibrarymember{advance_to}{basic_format_context}% \begin{itemdecl} -void advance_to(iterator it); +constexpr void advance_to(iterator it); \end{itemdecl} \begin{itemdescr} @@ -7912,7 +7928,7 @@ Pursuant to \ref{namespace.std}, users may specialize \tcode{format_kind} for cv-unqualified program-defined types that model \tcode{ranges::\libconcept{input_range}}. -Such specializations shall be usable in constant expressions\iref{expr.const} +Such specializations shall be usable in constant expressions\iref{expr.const.init} and have type \tcode{const range_format}. \end{itemdescr} @@ -8114,7 +8130,7 @@ template requires @\libconcept{formattable}@, charT> && @\libconcept{same_as}@>, T> - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(R&& r, FormatContext& ctx) const; \end{itemdecl} @@ -8222,7 +8238,7 @@ \indexlibrarymemberexpos{format}{range-default-formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-r}@& elems, FormatContext& ctx) const; \end{itemdecl} @@ -8302,7 +8318,7 @@ \indexlibrarymemberexpos{format}{range-default-formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-map}@& r, FormatContext& ctx) const; \end{itemdecl} @@ -8368,7 +8384,7 @@ \indexlibrarymemberexpos{format}{range-default-formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-set}@& r, FormatContext& ctx) const; \end{itemdecl} @@ -8492,7 +8508,7 @@ \indexlibrary{\idxcode{basic_format_arg}!constructor|(}% \begin{itemdecl} -basic_format_arg() noexcept; +constexpr basic_format_arg() noexcept; \end{itemdecl} \begin{itemdescr} @@ -8502,7 +8518,7 @@ \end{itemdescr} \begin{itemdecl} -template explicit basic_format_arg(T& v) noexcept; +template constexpr explicit basic_format_arg(T& v) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8574,7 +8590,7 @@ \indexlibrarymember{operator bool}{basic_format_arg}% \begin{itemdecl} -explicit operator bool() const noexcept; +constexpr explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -8586,7 +8602,7 @@ \indexlibrarymember{visit}{basic_format_arg}% \begin{itemdecl} template - decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); + constexpr decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); \end{itemdecl} \begin{itemdescr} @@ -8598,7 +8614,7 @@ \indexlibrarymember{visit}{basic_format_arg}% \begin{itemdecl} template - R visit(this basic_format_arg arg, Visitor&& vis); + constexpr R visit(this basic_format_arg arg, Visitor&& vis); \end{itemdecl} \begin{itemdescr} @@ -8630,7 +8646,7 @@ \indexlibraryctor{basic_format_arg::handle}% \begin{itemdecl} -template explicit handle(T& val) noexcept; +template constexpr explicit handle(T& val) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8667,7 +8683,7 @@ \indexlibrarymember{format}{basic_format_arg::handle}% \begin{itemdecl} -void format(basic_format_parse_context& parse_ctx, Context& format_ctx) const; +constexpr void format(basic_format_parse_context& parse_ctx, Context& format_ctx) const; \end{itemdecl} \begin{itemdescr} @@ -8693,7 +8709,8 @@ \indexlibraryglobal{make_format_args}% \begin{itemdecl} template - @\exposid{format-arg-store}@ make_format_args(Args&... fmt_args); + constexpr @\exposid{format-arg-store}@ + make_format_args(Args&... fmt_args); \end{itemdecl} \begin{itemdescr} @@ -8714,7 +8731,8 @@ \indexlibraryglobal{make_wformat_args}% \begin{itemdecl} template - @\exposid{format-arg-store}@ make_wformat_args(Args&... args); + constexpr @\exposid{format-arg-store}@ + make_wformat_args(Args&... args); \end{itemdecl} \begin{itemdescr} @@ -8762,7 +8780,7 @@ \indexlibraryctor{basic_format_args}% \begin{itemdecl} template - basic_format_args(const @\exposid{format-arg-store}@& store) noexcept; + constexpr basic_format_args(const @\exposid{format-arg-store}@& store) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8775,7 +8793,7 @@ \indexlibrarymember{get}{basic_format_args}% \begin{itemdecl} -basic_format_arg get(size_t i) const noexcept; +constexpr basic_format_arg get(size_t i) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -8945,7 +8963,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\seebelow@& elems, FormatContext& ctx) const; \end{itemdecl} diff --git a/source/threads.tex b/source/threads.tex index 359af7dcd0..5762bd5817 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -293,9 +293,9 @@ \pnum A type \tcode{L} meets the \defnoldconcept{TimedLockable} requirements if it meets the \oldconcept{Lockable} requirements and the following expressions are well-formed and have the specified semantics -(\tcode{m} denotes a value of type \tcode{L}, \tcode{rel_time} denotes a value of an -instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes a value -of an instantiation of \tcode{time_point}\iref{time.point}). +(\tcode{m} denotes a value of type \tcode{L}, \tcode{rel_time} denotes a value of a +specialization of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes a value +of a specialization of \tcode{time_point}\iref{time.point}). \begin{itemdecl} m.try_lock_for(rel_time) @@ -631,7 +631,6 @@ If the callback invocation was added to stop state's list of callbacks, \tcode{scb} shall be associated with the stop state. \end{itemize} -\item \begin{note} If \tcode{t.stop_possible()} is \tcode{false}, there is no requirement @@ -3160,6 +3159,7 @@ bool is_lock_free() const noexcept; constexpr explicit atomic_ref(T&); + explicit atomic_ref(T&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -3238,6 +3238,9 @@ \pnum The alignment required for an object to be referenced by an atomic reference, which is at least \tcode{alignof(T)}. +For any type \tcode{U} similar to \tcode{T}, +the value of \tcode{required_alignment} +is the same as \tcode{atomic_ref>::required_alignment}. \pnum \begin{note} @@ -3261,6 +3264,9 @@ The static data member \tcode{is_always_lock_free} is \tcode{true} if the \tcode{atomic_ref} type's operations are always lock-free, and \tcode{false} otherwise. +For any type \tcode{U} similar to \tcode{T}, +the value of \tcode{is_always_lock_free} +is the same as \tcode{atomic_ref>::is_always_lock_free}. \end{itemdescr} \indexlibrarymember{is_lock_free}{atomic_ref}% @@ -3459,16 +3465,16 @@ \indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} constexpr bool compare_exchange_weak(value_type& expected, value_type desired, - memory_order success, memory_order failure) const noexcept; + memory_order success, memory_order failure) const noexcept; constexpr bool compare_exchange_strong(value_type& expected, value_type desired, - memory_order success, memory_order failure) const noexcept; + memory_order success, memory_order failure) const noexcept; constexpr bool compare_exchange_weak(value_type& expected, value_type desired, - memory_order order = memory_order::seq_cst) const noexcept; + memory_order order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_strong(value_type& expected, value_type desired, - memory_order order = memory_order::seq_cst) const noexcept; + memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -3657,6 +3663,7 @@ bool is_lock_free() const noexcept; constexpr explicit atomic_ref(@\placeholder{integral-type}@&); + explicit atomic_ref(@\placeholder{integral-type}@&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -3881,6 +3888,7 @@ bool is_lock_free() const noexcept; constexpr explicit atomic_ref(@\placeholder{floating-point-type}@&); + explicit atomic_ref(@\placeholder{floating-point-type}@&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -4175,6 +4183,7 @@ bool is_lock_free() const noexcept; constexpr explicit atomic_ref(@\placeholder{pointer-type}@&); + explicit atomic_ref(@\placeholder{pointer-type}@&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -4748,19 +4757,19 @@ bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; constexpr bool compare_exchange_weak(T& expected, T desired, - memory_order success, memory_order failure) noexcept; + memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; constexpr bool compare_exchange_strong(T& expected, T desired, - memory_order success, memory_order failure) noexcept; + memory_order success, memory_order failure) noexcept; bool compare_exchange_weak(T& expected, T desired, memory_order order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(T& expected, T desired, - memory_order order = memory_order::seq_cst) noexcept; + memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(T& expected, T desired, - memory_order order = memory_order::seq_cst) noexcept; + memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} @@ -5745,11 +5754,11 @@ bool compare_exchange_weak(T*&, T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(T*&, T*, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(T*&, T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(T*&, T*, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; @@ -7088,6 +7097,7 @@ #define @\libmacro{ATOMIC_BOOL_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_CHAR_LOCK_FREE}@ @\seebelow@ +#define @\libmacro{ATOMIC_CHAR8_T_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_CHAR16_T_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_CHAR32_T_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_WCHAR_T_LOCK_FREE}@ @\seebelow@ @@ -7329,7 +7339,7 @@ The implementation provides lock and unlock operations, as described below. For purposes of determining the existence of a data race, these behave as atomic operations\iref{intro.multithread}. The lock and unlock operations on -a single mutex appears to occur in a single total order. +a single mutex appear to occur in a single total order. \begin{note} This can be viewed as the modification order\iref{intro.multithread} of the @@ -7576,10 +7586,10 @@ \tcode{recursive_timed_mutex}, and \tcode{shared_timed_mutex}. They meet the requirements set out below. In this description, \tcode{m} denotes an object of a mutex type, -\tcode{rel_time} denotes an object of an -instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an -object of an -instantiation of \tcode{time_point}\iref{time.point}. +\tcode{rel_time} denotes an object of a +specialization of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an +object of a +specialization of \tcode{time_point}\iref{time.point}. \begin{note} The timed mutex types meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. @@ -7970,9 +7980,9 @@ shared mutex types\iref{thread.sharedmutex.requirements}, and additionally meet the requirements set out below. In this description, \tcode{m} denotes an object of a shared timed mutex type, -\tcode{rel_time} denotes an object of an instantiation of +\tcode{rel_time} denotes an object of a specialization of \tcode{duration}\iref{time.duration}, and -\tcode{abs_time} denotes an object of an instantiation of +\tcode{abs_time} denotes an object of a specialization of \tcode{time_point}\iref{time.point}. \begin{note} The shared timed mutex types meet the \oldconcept{SharedTimedLockable} @@ -8152,9 +8162,9 @@ struct adopt_lock_t { }; // assume the calling thread has already // obtained mutex ownership and manage it - inline constexpr defer_lock_t defer_lock { }; - inline constexpr try_to_lock_t try_to_lock { }; - inline constexpr adopt_lock_t adopt_lock { }; + inline constexpr defer_lock_t defer_lock { }; + inline constexpr try_to_lock_t try_to_lock { }; + inline constexpr adopt_lock_t adopt_lock { }; } \end{codeblock} @@ -9491,6 +9501,16 @@ \pnum Condition variable construction and destruction need not be synchronized. +\pnum +The definitions in \ref{thread.condition} +make use of the following exposition-only function: +\begin{codeblock} +template + chrono::steady_clock::time_point @\exposid{rel-to-abs}@(const Dur& rel_time) { + return chrono::steady_clock::now() + chrono::ceil(rel_time); + } +\end{codeblock} + \rSec2[condition.variable.syn]{Header \tcode{} synopsis} \indexheader{condition_variable}% @@ -9837,7 +9857,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time)); \end{codeblock} \pnum @@ -9947,7 +9967,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time), std::move(pred)); \end{codeblock} \pnum @@ -10221,7 +10241,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time)); \end{codeblock} \pnum @@ -10289,7 +10309,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time), std::move(pred)); \end{codeblock} \end{itemdescr} @@ -10408,8 +10428,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, std::move(stoken), chrono::steady_clock::now() + rel_time, - std::move(pred)); +return wait_until(lock, std::move(stoken), @\exposid{rel-to-abs}@(rel_time), std::move(pred)); \end{codeblock} \end{itemdescr} @@ -13217,7 +13236,7 @@ \indexlibraryglobal{rcu_retire}% \begin{itemdecl} template> -void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); + void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); \end{itemdecl} \begin{itemdescr} diff --git a/source/time.tex b/source/time.tex index 023b13bf6b..a29b08edf7 100644 --- a/source/time.tex +++ b/source/time.tex @@ -160,19 +160,19 @@ minutes* offset = nullptr); // convenience typedefs - using nanoseconds = duration<@\term{signed integer type of at least 64 bits}@, nano>; - using microseconds = duration<@\term{signed integer type of at least 55 bits}@, micro>; - using milliseconds = duration<@\term{signed integer type of at least 45 bits}@, milli>; - using seconds = duration<@\term{signed integer type of at least 35 bits}@>; - using minutes = duration<@\term{signed integer type of at least 29 bits}@, ratio< 60>>; - using hours = duration<@\term{signed integer type of at least 23 bits}@, ratio<3600>>; - using days = duration<@\term{signed integer type of at least 25 bits}@, + using nanoseconds = duration<@\placeholder{signed integer type of at least 64 bits}@, nano>; + using microseconds = duration<@\placeholder{signed integer type of at least 55 bits}@, micro>; + using milliseconds = duration<@\placeholder{signed integer type of at least 45 bits}@, milli>; + using seconds = duration<@\placeholder{signed integer type of at least 35 bits}@>; + using minutes = duration<@\placeholder{signed integer type of at least 29 bits}@, ratio< 60>>; + using hours = duration<@\placeholder{signed integer type of at least 23 bits}@, ratio<3600>>; + using days = duration<@\placeholder{signed integer type of at least 25 bits}@, ratio_multiply, hours::period>>; - using weeks = duration<@\term{signed integer type of at least 22 bits}@, + using weeks = duration<@\placeholder{signed integer type of at least 22 bits}@, ratio_multiply, days::period>>; - using years = duration<@\term{signed integer type of at least 17 bits}@, + using years = duration<@\placeholder{signed integer type of at least 17 bits}@, ratio_multiply, days::period>>; - using months = duration<@\term{signed integer type of at least 20 bits}@, + using months = duration<@\placeholder{signed integer type of at least 20 bits}@, ratio_divide>>; // \ref{time.point.nonmember}, \tcode{time_point} arithmetic @@ -1287,7 +1287,10 @@ \pnum \tcode{Rep} shall be an arithmetic type or a class emulating an arithmetic type. -If \tcode{duration} is instantiated with a \tcode{duration} type as the argument for the template +If a specialization of \tcode{duration} +is instantiated with +a cv-qualified type or a specialization of \tcode{duration} +as the argument for the template parameter \tcode{Rep}, the program is ill-formed. \pnum @@ -9251,11 +9254,11 @@ \begin{codeblock} namespace std::chrono { struct sys_info { - sys_seconds begin; - sys_seconds end; - seconds offset; - minutes save; - string abbrev; + sys_seconds begin; + sys_seconds end; + seconds offset; + minutes save; + string abbrev; }; } \end{codeblock} @@ -10788,11 +10791,17 @@ the locale's alternate time representation. \\ \rowsep \tcode{\%y} & -The last two decimal digits of the year. +The last two decimal digits of the year, +regardless of the sign of the year. If the result is a single digit, it is prefixed by \tcode{0}. The modified command \tcode{\%Oy} produces the locale's alternative representation. The modified command \tcode{\%Ey} produces the locale's alternative representation of offset from \tcode{\%EC} (year only). +\begin{tailexample} +\begin{codeblock} +cout << format("{:%C %y}", -1976y); // prints \tcode{-20 76} +\end{codeblock} +\end{tailexample} \\ \rowsep \tcode{\%Y} & The year as a decimal number. @@ -11465,7 +11474,8 @@ The modified command \tcode{\%EX} interprets the locale's alternate time representation. \\ \rowsep \tcode{\%y} & -The last two decimal digits of the year. +The last two decimal digits of the year, +regardless of the sign of the year. If the century is not otherwise specified (e.g., with \tcode{\%C}), values in the range \crange{69}{99} @@ -11478,6 +11488,12 @@ Leading zeroes are permitted but not required. The modified commands \tcode{\%Ey} and \tcode{\%Oy} interpret the locale's alternative representation. +\begin{tailexample} +\begin{codeblock} +year y; +istringstream{"-20 76"} >> parse("%3C %y", y); // \tcode{y == -1976y} is \tcode{true} +\end{codeblock} +\end{tailexample} \\ \rowsep \tcode{\%Y} & The year as a decimal number. diff --git a/source/ub.tex b/source/ub.tex new file mode 100644 index 0000000000..10fe4ce995 --- /dev/null +++ b/source/ub.tex @@ -0,0 +1,2069 @@ +%!TEX root = std.tex +\infannex{ub}{Enumeration of Core Undefined Behavior} + +\rSec1[ub.general]{General} + +This Annex documents undefined behavior explicitly called out in the main standard text using the +following phrases: the behavior of the program is undefined, has undefined behavior, results in +undefined behavior, the behavior is undefined, have undefined behavior, is undefined, result has +undefined behavior. Undefined behavior that is implicit is not covered by this annex. Each entry contains +a title, a numeric cross reference to the main standard text, a summary of the issue and a code example +demonstrating the issue. The code examples are there to clarify the undefined behavior and will not +exhaustively cover all possible ways of invoking that case. + +\rSec1[ub.basic]{\ref{basic}: Basics} + +\rSec2[ub.intro.object]{Implicitly creating object and undefined behavior} + +\pnum +\ubxref{intro.object.implicit.create} +For each +operation that is specified as implicitly creating objects, that operation implicitly creates and starts the +lifetime of zero or more objects of implicit-lifetime types\iref{basic.types} in its specified region of storage if doing so +would result in the program having defined behavior. If no such set of objects would give the program defined +behavior, the behavior of the program is undefined. + +\pnum +\begin{example} +\begin{codeblock} +void f() +{ + void *p = malloc(sizeof(int) + sizeof(float)); + *reinterpret_cast(p) = 0; + *reinterpret_cast(p) = 0.0f; // undefined behavior, cannot create + // both \tcode{int} and \tcode{float} in same place +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{intro.object.implicit.pointer} +After implicitly creating objects within a specified region of storage, +some operations are described as producing a pointer to a +suitable created object\iref{basic.types}. +These operations select one of the implicitly-created objects +whose address is the address of the start of the region of storage, +and produce a pointer value that points to that object, +if that value would result in the program having defined behavior. +If no such pointer value would give the program defined behavior, +the behavior of the program is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include +struct X { + int a, b; + ~X() = delete; // deleted destructor makes \tcode{X} a non-implicit-lifetime class +}; + +X* make_x() { + // The call to \tcode{std::malloc} can not implicitly create an object of type \tcode{X} + // because \tcode{X} is not an implicit-lifetime class. + X* p = (X*)std::malloc(sizeof(struct X)); + p->a = 1; // undefined behavior, no set of objects give us defined behavior + return p; +} +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +#include + +struct X { + int a; +}; + +struct Y { + int x; +}; + +*make_y() { + X* p1 = (X*)std::malloc(sizeof(struct X)); + p1->a = 1; + Y* p2 = (Y*)p1; + p2->x = 2; // undefined behavior, lifetime of \tcode{p1} was started but not + // ended and lifetime of \tcode{p2} was not started. + return p2; +} +\end{codeblock} +\end{example} + +%TODO: SY: These comments feel too loose. +%Shouldn't we be saying something along the lines of p1 points to an +%object of type X whose lifetime was started but not ended .... p2 +%points to an object of type Y but its lifetime was not started ..." + +\rSec2[ub.basic.align]{Object alignment} + +\pnum +\ubxref{basic.align.object.alignment} +All instances of a type must be created in storage that meets the alignment +requirement of that type. + +\pnum +\begin{example} +\begin{codeblock} +struct alignas(4) S {}; + +void make_misaligned() +{ + alignas(S) char s[sizeof(S) + 1]; + new (&s+1) S(); // undefined behavior, \tcode{\&s+1} will yield a pointer to + // a \tcode{char} which is $1$ byte away from an address with + // an alignment of $4$ and so cannot have an alignment of $4$. +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.life]{Object lifetime} + +\pnum +\ubxref{lifetime.outside.pointer.delete} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the object will be or was of a class type with a non-trivial destructor +and the pointer is used as the operand of a \grammarterm{delete-expression}. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + float f = 0; + ~S() {} +}; + +void f() { + S* p = new S; + p->~S(); + delete p; // undefined behavior, operand of delete, lifetime has ended and \tcode{S} + // has a non-trivial destructor +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.pointer.member} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the pointer is used to access a non-static data member or call a +non-static member function of the object. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + float f = 0; +}; + +float f() { + S s; + S* p = &s; + s.~S(); + return p->f; // undefined behavior, accessing non-static data member after + // end of lifetime +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.pointer.virtual} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the pointer is implicitly converted\iref{conv.ptr} to a pointer +to a virtual base class (or base class of a virtual base class). + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : virtual B {}; +void f() { + D d; + D* p = &d; + d.~D(); + B* b = p; // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.pointer.dynamic.cast} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the pointer is used as the operand of a +\tcode{dynamic_cast}\iref{expr.dynamic.cast}. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B() = default; }; +struct D : B {}; +void f() +{ + D d; + B* bp = &d; + d.~D(); + D* dp = dynamic_cast(bp); // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.access} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is used to access the object. + +\pnum +\begin{example} +\begin{codeblock} +void f() { + int x = int{10}; + using T = int; + x.~T(); + int y = x; // undefined behavior, glvalue used to access the + // object after the lifetime has ended +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.member} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is used to call a non-static member function of the object. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + void f() {} +}; + +void f() { + A a; + a.~A(); + a.f(); // undefined behavior, glvalue used to access a + // non-static member function after the lifetime has ended +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.virtual} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is bound to a reference to a virtual base class. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : virtual B { +}; + +void f() { + D d; + d.~D(); + B& b = d; // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.dynamic.cast} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is used as the operand of a +\keyword{dynamic_cast} or as the operand of \keyword{typeid}. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B(); }; +struct D : virtual B {}; + +void f() { + D d; + B& br = d; + d.~D(); + D& dr = dynamic_cast(br); // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{original.type.implicit.destructor} +The behavior is undefined if +a non-trivial implicit destructor call +occurs when the type of the object inhabiting the associated storage +is not the original type associated with that storage. + +\pnum +\begin{example} +\begin{codeblock} +class T {}; + +struct B { + ~B(); +}; + +void h() { + B b; + new (&b) T; +} // undefined behavior at block exit +\end{codeblock} +\end{example} + + +\pnum +\ubxref{creating.within.const.complete.obj} +Creating a new object within the storage that a const complete object with static, thread, or automatic +storage duration occupies, or within the storage that such a const object used to occupy before its lifetime +ended, results in undefined behavior + +\pnum +\begin{example} +\begin{codeblock} +struct B { + B(); + ~B(); +}; + +const B b; + +void h() { + b.~B(); + new (const_cast(&b)) const B; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.indet]{Indeterminate and erroneous values} + +\pnum +\ubxref{basic.indet.value} +When the result of an evaluation is +an indeterminate value +(but not just an erroneous value) +the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +void g() { + int x [[ indeterminate ]]; + int y = x; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.stc.dynamic]{Dynamic storage Duration} + +\pnum +\ubxref{basic.stc.alloc.dealloc.constraint} +If the behavior of an allocation or deallocation function does not satisfy the semantic constraints +specified +in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}. +the behavior is undefined. + + +\pnum +\begin{example} +\begin{codeblock} +#include +void* operator new(std::size_t sz) { + if (sz == 0) + return nullptr; // undefined behavior, should return non-null pointer + + return std::malloc(1); // undefined behavior, if successful should return allocation with + // length in bytes is at least as large as the requested size +} +void operator delete(void* ptr) noexcept { + throw 0; // undefined behavior, terminates by throwing an exception +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{basic.stc.alloc.dealloc.throw} +If a call to a deallocation function +terminates by throwing an exception +the behavior is undefined. +\pnum +\begin{example} +\begin{codeblock} +struct X { + void operator delete(void*) { throw "oops"; } +}; +void f() +{ + X* x = new X(); + delete x; // undefined behavior +} +\end{codeblock} +\end{example} + + + +\rSec2[ub.basic.stc.alloc.zero.dereference]{Zero-sized allocation dereference} + +\pnum +\ubxref{basic.stc.alloc.zero.dereference} +The pointer returned when invoking an allocation function with a size of zero +cannot be dereferenced. + +\pnum +\begin{example} +\begin{codeblock} +void test() +{ + char* c = static_cast(operator new(0z)); + c[0] = 'X'; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.compound]{Compound types} + +\pnum +\ubxref{basic.compound.invalid.pointer} +Indirection or +the invocation of a deallocation function +with a pointer value referencing storage +that has been freed +has undefined behavior. +(Most other uses of such a pointer have +implemention-defined behavior.) + +\pnum +\begin{example} +\begin{codeblock} +void f() +{ + int *x = new int{5}; + delete x; + int y = *x; // undefined behavior + delete x; // undefined behavior +} +\end{codeblock} +\end{example} + + +\rSec2[ub.intro.execution]{Sequential execution} + +\pnum +\ubxref{intro.execution.unsequenced.modification} +If a side effect on a +memory location\iref{intro.memory} is unsequenced relative to either another side effect on the same memory location or +a value computation using the value of any object in the same memory location, and they are not potentially +concurrent\iref{intro.multithread}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +void g(int i) { + i = 7, i++, i++; // i becomes 9 + + i = i++ + 1; // the value of i is incremented + i = i++ + i; // undefined behavior + i = i + 1; // the value of i is incremented +} +\end{codeblock} +\end{example} + +\rSec2[ub.intro.races]{Data races} + +\pnum +\ubxref{intro.races.data} +The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, +at least one of which is not atomic, and neither happens before the other, except for the special case for +signal handlers described in~\ref{intro.races}. Any such data race results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int count = 0; +auto f = [&] { count++; }; +std::thread t1{f}, t2{f}, t3{f}; +// undefined behavior t1, t2 and t3 have a data race on access of variable count +\end{codeblock} +\end{example} + +\rSec2[ub.intro.progress]{Forward progress} + +\pnum +\ubxref{intro.progress.stops} +The behavior is undefined if a thread of execution that has not terminated stops +making execution steps. + +\pnum +\begin{example} +\begin{codeblock} +bool stop() { return false; } + +void busy_wait_thread() { + while (!stop()); // undefined behavior, thread makes no progress but the loop +} // is not trivial because `stop()` is not a constant expression + +int main() { + std::thread t(busy_wait_thread); + t.join(); +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.start.main]{main function} + +\pnum +\ubxref{basic.start.main.exit.during.destruction} +If \tcode{std::exit} is called to +end a program during the destruction of an object with static or thread storage duration, the program has +undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +struct Exiter { + ~Exiter() { std::exit(0); } +}; + +Exiter ex; + +int main() {} +// undefined behavior when destructor of static variable \tcode{ex} is called it will call \tcode{std::exit} +\end{codeblock} +\end{example} + + +\rSec2[ub.basic.start.term]{Termination} + +\pnum +\ubxref{basic.start.term.use.after.destruction} +If a function contains a block-scope object of static or thread storage duration that has been destroyed and the +function is called during the destruction of an object with static or thread storage duration, the program has +undefined behavior if the flow of control passes through the definition of the previously destroyed block-scope +object. Likewise, the behavior is undefined if the block-scope object is used indirectly (i.e., through a pointer) +after its destruction. + +\pnum +\begin{example} +\begin{codeblock} +struct A {}; +void f() { + static A a; +} + +struct B { + B() { f(); } +}; +struct C { + ~C() { f(); } +}; + +C c; +B b; // call to `f()` in constructor begins lifetime of \tcode{a} + +int main() {} +// undefined behavior, static objects are destructed in reverse order, in this case \tcode{a} then \tcode{b} and +// finally \tcode{c}. When the destructor of \tcode{c} is called, it calls \tcode{f()} which passes through the definition of +// previously destroyed block-scope object +\end{codeblock} +\end{example} + + +\pnum +\ubxref{basic.start.term.signal.handler} +If there is a use of a standard library object or function not permitted within signal handlers\iref{support.runtime} that +does not happen before\iref{intro.multithread} completion of destruction of objects with static storage duration and execution +of std::atexit registered functions\iref{support.start.term}, the program has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB/TD: This is really a general precondition imposed on the Standard +%Library, not a piece of core language undefined behavior. It is also currently +%missing an example. Should we retain this UB? Should we have a core issue +%to move this wording into the library section somewhere? +%TODO: SY: If we keep this, we should have an example. + +\rSec1[ub.expr]{\ref{expr}: Expressions} +\rSec2[ub.expr.eval]{Result of Expression not Mathematically Defined/out of Range} + +\pnum +\ubxref{expr.expr.eval} +If during the evaluation of an expression, the result is not mathematically defined or not in the range of +representable values for its type, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include +int main() { + // Assuming 32-bit int the range of values are: $-2,147,483,648$ to $2,147,483,647$ + int x1 = std::numeric_limits::max() + 1; + // undefined behavior, $2,147,483,647 + 1$ is not representable as an int + int x2 = std::numeric_limits::min() / -1; + // undefined behavior, $-2,147,483,648 / -1$ is not representable as an int +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.lval]{Value category} + +\pnum +\ubxref{expr.basic.lvalue.strict.aliasing.violation} +If a program attempts to access\iref{defns.access} the stored value of an object +whose dynamic type is $T$ through a glvalue whose type is not +similar\iref{conv.rval} to $T$ (or its corresponding signed or unsigned types) +the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int foo(float* f, int* i) { + *i = 1; + *f = 0.f; // undefined behavior, glvalue is not similar to \tcode{int} + + return *i; +} + +int main() { + int x = 0; + + x = foo(reinterpret_cast(&x), &x); +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.basic.lvalue.union.initialization} +If a program invokes a defaulted copy/move constructor or +defaulted copy/move assignment +operator of a union with an argument that is not an object of a similar type +within its lifetime, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +union U { int x; }; +void f() +{ + char u[sizeof(U)]; + U o = reinterpret_cast(u); // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.type]{Type} + +\pnum +\ubxref{expr.type.reference.lifetime} +Evaluating a reference when an equivalent use of a pointer denoting the same object +would be invalid has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +void g() +{ + int* ip = new int(5); + int& i = *ip; + delete ip; + i; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.conv.lval]{Lvalue-to-rvalue conversion} + +\pnum +\ubxref{conv.lval.valid.representation} +Performing an +lvalue-to-rvalue conversion +on an object whose +value representation +is not valid for its type +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +bool f() { + bool b = true; + char c = 42; + memcpy(&b, &c, 1); + return b; // undefined behavior if \tcode{42} is not a valid value representation for \keyword{bool} +} +\end{codeblock} +\end{example} + + +\rSec2[ub.conv.double]{Floating-point conversions} + +\pnum +\ubxref{conv.double.out.of.range} +Converting a floating point value to a type that cannot represent the value is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +int main() { + // Assuming 32-bit int, 32-bit float and 64-bit double + double d2 = std::numeric_limits::max(); + float f = d2; // undefined behavior on systems where the range of + // representable values of float is [-max,+max] on system where + // representable values are [-inf,+inf] this would not be UB + int i = d2; // undefined behavior, the max value of double is not representable as int +} +\end{codeblock} +\end{example} + + +\rSec2[ub.conv.fpint]{Floating-integral conversions} + +\pnum +\ubxref{conv.fpint.int.not.represented} +When converting a floating-point value to an integer type and vice versa if +the value is not representable in the destination type it is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +int main() { + // Assuming 32-bit int the range of values are: $-2,147,483,648$ to + // $2,147,483,647$ Assuming 32-bit float and 64-bit double + double d = (double)std::numeric_limits::max() + 1; + int x1 = d; // undefined behavior $2,147,483,647 + 1$ is not representable as int +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{conv.fpint.float.not.represented} +When converting a value of integer or unscoped enumeration type to a +floating-point type, if the value is not representable in the destination type +it is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int main() { + __uint128_t x2 = -1; + float f = x2; // undefined behavior on systems where the range of + // representable values of float is [-max,+max] on system where + // represetable values are [-inf,+inf] this would not be UB +} +\end{codeblock} +\end{example} + +\rSec2[ub.conv.ptr]{Pointer conversions} + +\pnum +\ubxref{conv.ptr.virtual.base} +Converting +a pointer to a derived class \tcode{D} +to +a pointer to a virtual base class \tcode{B} +that does not point to +a valid object +within its lifetime +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : virtual B {}; +void f() +{ + D ds[1]; + B* b = &ds[1]; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.conv.mem]{Pointer-to-member conversions} + +\pnum +\ubxref{conv.member.missing.member} +The conversion of +a pointer to a member of a base class +to a pointer to member of a derived class +that could not contain that member +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D1 : B { int d1; }; +struct D2 : B {}; +void f() +{ + int (D1::*pd1) = &D1::d1; + int (B::*pb) = static_cast(pd1); + int (D2::*pd2) = pb; // undefined behavior +} +\end{codeblock} +\end{example} + + + +\rSec2[ub.expr.call]{Function call} + +\pnum +\ubxref{expr.call.different.type} +Calling a function through an expression whose +function type is not call-compatible with +the function type of the called +function's definition results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +using f_float = int (*)(float); +using f_int = int (*)(int); + +int f1(float) { return 10; } + +int f2(int) { return 20; } + +int main() { + return reinterpret_cast(f1)(20); // undefined behavior, the function type of the expression + // is different from the called functions definition +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.ref]{Class member access} + +\pnum +\ubxref{expr.ref.member.not.similar} +If \tcode{E2} is a non-static member and the result of \tcode{E1} is an object whose type +is not similar\iref{conv.qual} to the type of \tcode{E1}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct A { int i; }; +struct B { int j; }; +struct D : A, B {}; +void f() { + D d; + reinterpret_cast(d).j; // undefined behavior +} +\end{codeblock} +\end{example} + +%TODO: SY: The wording is not great, I don't have a good suggestion but we should +%get some opinions + +\rSec2[ub.expr.dynamic.cast]{Dynamic cast} + + +\pnum +\ubxref{expr.dynamic.cast.pointer.lifetime} +Evaluating a \keyword{dynamic_cast} on a non-null pointer that points to +an object (of polymorphic type) of the wrong type or to an object +not within its lifetime has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B(); }; +void f() { + B bs[1]; + B* dp = dynamic_cast(bs+1); // undefined behavior +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.dynamic.cast.glvalue.lifetime} +Evaluating a \keyword{dynamic_cast} on a reference that +denotes an object (of polymorphic type) of the wrong type or an object +not within its lifetime has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B(); }; +void f() { + B bs[1]; + B& dr = dynamic_cast(bs[1]); // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.static.cast]{Static cast} + +\pnum +\ubxref{expr.static.cast.base.class} +We can cast a base class B to a reference to derived class D (with certain restrictions wrt to cv qualifiers) +as long B is a base class subobject of type D, otherwise the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D1 : B {}; +struct D2 : B {}; + +void f() { + D1 d; + B &b = d; + static_cast(b); // undefined behavior, base class object of type \tcode{D1} not \tcode{D2} +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.enum.outside.range} +If the enumeration type does not have a fixed underlying +type, the value is unchanged if the original value is within the range of the enumeration values\iref{dcl.enum}, and +otherwise, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +enum A { e1 = 1, e2 }; + +void f() { + enum A a = static_cast(4); // undefined behavior, 4 is not with the range of enumeration values +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.fp.outside.range} +An explicit conversion of a +floating-point value that is outside the range of the +target type has undefined behavior. + +\pnum +\begin{example} +If \tcode{float} does not adhere to \IsoFloatUndated{} +and cannot represent positive infinty, +a sufficiently large \tcode{double} value will be +outside the (finite) range of \tcode{float}. +\begin{codeblock} +void f() { + double d = FLT_MAX; + d *= 16; + float f = static_cast(d); // undefined behavior. +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.static.cast.downcast.wrong.derived.type} +Casting from a pointer to a base class to a pointer to a derived class +when there is no enclosing object of that derived class at the +specified location has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D1 : B {}; +struct D2 : B {}; + +void f() { + B *bp = new D1; + static_cast(bp); // undefined behavior, base class object of type \tcode{D1} not \tcode{D2} +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.does.not.contain.orignal.member} +A +pointer to member of derived class D +can be cast to +a pointer to member of base class B +(with certain restrictions on cv qualifiers) +as long as B contains the original member, +or is a base or derived class of the class +containing the original member; +otherwise the behavior is undefined. + + +\pnum +\begin{example} +\begin{codeblock} +struct A { + char c; +}; + +struct B { + int i; +}; + +struct D : A, B {}; + +int main() { + char D::*p1 = &D::c; + char B::*p2 = static_cast(p1); // undefined behavior, \tcode{B} does not contain the original member \tcode{c} +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.unary.op]{Unary operators} + +\pnum +\ubxref{expr.unary.dereference} +Dereferencing a pointer that does not point to an object or function +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int f() +{ + int *p = nullptr; + return *p; // undefined behavior +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.new]{New} + +\pnum +\ubxref{expr.new.non.allocating.null} +If the allocation +function is a non-allocating form\iref{new.delete.placement} that returns null, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include +[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept { + return nullptr; // undefined behavior, should return non-null pointer +} +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +#include + +struct A { + int x; +}; + +int main() { + char *p = nullptr; + A *a = new (p) A; // undefined behavior, non-allocting new returning nullptr +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.delete]{Delete} + +\pnum +\ubxref{expr.delete.mismatch} +Using array delete on the result of a single object new expression is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int* x = new int; +delete[] x; // undefined behavior, allocated using single object new expression +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.delete.array.mismatch} +Using single object delete on the result of an array new expression is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int* x = new int[10]; +delete x; // undefined behavior, allocated using array new expression +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.delete.dynamic.type.differ} +If the static type of the object to be deleted is different from its dynamic +type and the selected deallocation function is not a destroying operator delete, the static type +shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual +destructor or the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B { + int a; +}; + +struct D : public B { + int b; +}; + +void f() { + B* b = new D; + delete b; // undefined behavior, no virtual destructor +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.delete.dynamic.array.dynamic.type.differ} +In an array delete expression, if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B { + virtual ~B(); + void operator delete[](void*, std::size_t); +}; + +struct D : B { + void operator delete[](void*, std::size_t); +}; + +void f(int i) { + D* dp = new D[i]; + delete[] dp; // uses \tcode{D::operator delete[](void*, std::size_t)} + B* bp = new D[i]; + delete[] bp; // undefined behavior +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.mptr.oper]{Pointer-to-member operators} + +\pnum +\ubxref{expr.mptr.oper.not.contain.member} +Abbreviating \grammarterm{pm-expression}.*\grammarterm{cast-expression} as \tcode{E1.*E2}, \tcode{E1} is called the object expression. If the dynamic type +of \tcode{E1} does not contain the member to which \tcode{E2} refers, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : B { + int x; +}; + +void f() { + B *b = new B; + D *d = static_cast(b); + int D::*p = &D::x; + (*d).*p = 1; // undefined behavior, dynamic type \tcode{B} does not contain \tcode{x} +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.mptr.oper.member.func.null} +If the second operand in a \tcode{.*} expression is the null +member pointer value\iref{conv.mem}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + int f(); +}; + +void f() { + S cs; + int (S::*pm)() = nullptr; + (cs.*pm)(); // undefined behavior, the second operand is null +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.mul]{Multiplicative operators} + +\pnum +\ubxref{expr.mul.div.by.zero} +Division by zero is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int main() { + int x = 1 / 0; // undefined behavior, division by zero + double d = 1.0 / 0.0; // undefined behavior on systems where the range of + // representable values of float is [-max,+max] on system where + // represetable values are [-inf,+inf] this would not be UB +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.mul.representable.type.result} +If the +quotient a/b is representable in the type of the result, (a/b)*b + a\%b is equal to a; otherwise, the behavior +of both a/b and a\%b is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include + +int main() { + int x = std::numeric_limits::min() / -1; + // Assuming LP64 $-2,147,483,648$ which when divided by $-1$ + // gives us $2,147,483,648$ which is not representable by int +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.add]{Additive operators} + +\pnum +\ubxref{expr.add.out.of.bounds} +Creating an out of bounds pointer is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +static const int arrs[10]{}; + +int main() { + const int *y = arrs + 11; // undefined behavior, creating an out of bounds pointer +} +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +static const int arrs[10][10]{}; + +int main() { + const int(*y)[10] = arrs + 11; // undefined behavior, creating an out of bounds pointer. + // We can't treat arrs as-if it was a pointer to 100 int, +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.add.sub.diff.pointers} +Subtracting pointers that are not part of the same array is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include +void f() { + int x[2]; + int y[2]; + int* p1 = x; + int* p2 = y; + std::ptrdiff_t off = p1 - p2; // undefined behavior, \tcode{p1} and \tcode{p2} point to different arrays +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.add.not.similar} +For addition or subtraction of two expressions P and Q, +if P or Q have type ``pointer to cv T'', where T and the array +element type are not similar\iref{conv.rval}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + int i; +}; + +struct T : S { + double d; +}; + +void f(const S* s, std::size_t count) { + for (const S* end = s + count; s != end; ++s) { + ... + } +} + +int main() { + T test[5]; + f(test, 5); +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.shift]{Shift operators} + +\pnum +\ubxref{expr.shift.neg.and.width} +Shifting by a negative amount or equal or greater than the bit-width of a type is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int y = 1 << -1; // undefined behavior, shift is negative + +static_assert(sizeof(int) == 4 && CHAR_BIT == 8); +int y1 = 1 << 32; // undefined behavior, shift is equal to the bit width of int +int y2 = 1 >> 32; // undefined behavior, shift is equal to the bit width of int +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.assign]{Assignment and compound assignment operators} + +\pnum +\ubxref{expr.assign.overlap} +Overlap in the storage between the source and destination may result in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int x = 1; +char* c = reinterpret_cast(&x); +x = *c; // undefined behavior, source overlaps storage of destination +\end{codeblock} +\end{example} + +\rSec1[ub.stmt.stmt]{\ref{stmt}: Statements} + +\rSec2[ub.stmt.return]{The return statement} + +\pnum +\ubxref{stmt.return.flow.off} +Flowing off the end of a function other +than main or a coroutine results in undefined behavior if the return type +is not \cv{}~\keyword{void}. + +\pnum +\begin{example} +\begin{codeblock} +int f(int x) { + if (x) + return 1; + // undefined behavior if \tcode{x} is \tcode{0} +} + +void b() { + int x = f(0); // undefined behavior, using 0 as an argument will cause f(...) to flow off the end + // with a return statement +} +\end{codeblock} +\end{example} + +\rSec2[ub.return.coroutine]{The co_return statement} + +\pnum +\ubxref{stmt.return.coroutine.flow.off} +Flowing off the end of a coroutine function body +that does not return void +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include +#include +#include +#include + +class resumable { + public: + struct promise_type; + using coro_handle = std::coroutine_handle; + resumable(coro_handle handle) : handle_(handle) { assert(handle); } + resumable(resumable&) = delete; + resumable(resumable&&) = delete; + bool resume() { + if (not handle_.done()) + handle_.resume(); + return not handle_.done(); + } + ~resumable() { handle_.destroy(); } + const char* return_val(); + + private: + coro_handle handle_; +}; + +struct resumable::promise_type { + using coro_handle = std::experimental::coroutine_handle; + const char* string_; + auto get_return_object() { return coro_handle::from_promise(*this); } + auto initial_suspend() { return std::experimental::suspend_always(); } + auto final_suspend() noexcept { return std::experimental::suspend_always(); } + void unhandled_exception() { std::terminate(); } + void return_value(const char* string) { string_ = string; } +}; + +const char* resumable::return_val() { + return handle_.promise().string_; +} + +resumable foo() { + std::cout << "Hello" << std::endl; + co_await std::experimental::suspend_always(); + // undefined behavior, falling off the end of coroutine that does not return void +} + +int main() { + resumable res = foo(); + while (res.resume()) + ; + std::cout << res.return_val() << std::endl; +} +\end{codeblock} +\end{example} + +\rSec2[ub.stmt.dcl]{Declaration statement} + +\pnum +\ubxref{stmt.dcl.local.static.init.recursive} +If control re-enters the declaration recursively while the +variable is being initialized, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int foo(int i) { + static int s = foo(2 * i); // recursive call - undefined + return i + 1; +} +\end{codeblock} +\end{example} + + + + +\rSec1[ub.dcl.dcl]{\ref{dcl}: Declarations} + +\rSec2[ub.dcl.type.cv]{The cv-qualifiers} + +\pnum +\ubxref{dcl.type.cv.modify.const.obj} +Any attempt to modify a const object during its lifetime results in +undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +const int* ciq = new const int(3); // initialized as required +int* iq = const_cast(ciq); // cast required +*iq = 4; // undefined: modifies a const object +\end{codeblock} +\end{example} + + +\pnum +\ubxref{dcl.type.cv.access.volatile} +If an attempt is made to +access an object defined with a volatile-qualified type through the use of a non-volatile glvalue, the behavior +is undefined + +\pnum +\begin{example} +\begin{codeblock} +volatile int x = 0; +int& y = const_cast(x); +std::cout << y; // undefined behavior, accessing volatile through non-volatile glvalue +\end{codeblock} +\end{example} + +\rSec2[ub.dcl.ref]{References} + +\pnum +\ubxref{dcl.ref.incompatible.function} +Initializing a reference to a function +with a value that is a function +that is not call-compatible\iref{expr.call} +with the type of the reference +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +void f(float x); +void (&g)(int) = reinterpret_cast(f); // undefined behavior +\end{codeblock} +\end{example} + +\pnum +\ubxref{dcl.ref.incompatible.type} +Initializing a reference to an object +with a value that is not +type-accessible\iref{basic.lval} through +the type of the reference +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +float g; +int& i = reinterpret_cast(g); // undefined behavior +\end{codeblock} +\end{example} + +\pnum +\ubxref{dcl.ref.uninitialized.reference} +Evaluating a reference +prior to initializing that +reference has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +extern int &ir1; +int i2 = ir1; // undefined behavior, \tcode{ir1} not yet initialized +int i3 = 17; +int &ir1 = i3; +\end{codeblock} +\end{example} + + + + +\rSec2[ub.dcl.fct.def.coroutine]{Coroutine definitions} + +\pnum +\ubxref{dcl.fct.def.coroutine.resume.not.suspended} +Invoking a resumption member function for a coroutine that is not suspended results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +using namespace std::experimental; + +struct minig { + struct promise_type { + int val; + minig get_return_object() { return {*this}; } + constexpr suspend_always initial_suspend() noexcept { return {}; } + constexpr suspend_always final_suspend() noexcept { return {}; } + constexpr void return_void() noexcept {} + [[noreturn]] void unhandled_exception() noexcept { throw; } + suspend_always yield_value(int v) noexcept { + val = v; + return {}; + } + }; + using HDL = coroutine_handle; + HDL coro; + minig(promise_type& p) : coro(HDL::from_promise(p)) {} + ~minig() { coro.destroy(); } + bool move_next() { + coro.resume(); + return !coro.done(); + } + int current_value() { return coro.promise().val; } +}; + +static minig f(int n) { + for (int i = 0; i < n; ++i) + co_yield i; +} + +int main() { + auto g = f(10); + int sum = 0; + while (g.move_next()) + sum += g.current_value(); +#if 0 + // undefined behavior to call move_next(), because coro.resume() is + // UB after final_suspend returns, even when it returns + // suspend_always + g.move_next(); +#endif + return sum; +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{dcl.fct.def.coroutine.destroy.not.suspended} +Invoking destroy() on a coroutine that is not suspended is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +using namespace std::experimental; + +struct minig { + struct promise_type { + int val; + minig get_return_object() { return {*this}; } + constexpr suspend_always initial_suspend() noexcept { return {}; } + constexpr suspend_always final_suspend() noexcept { return {}; } + constexpr void return_void() noexcept {} + [[noreturn]] void unhandled_exception() { throw; } + suspend_always yield_value(int v) noexcept { + val = v; + return {}; + } + }; + using HDL = coroutine_handle; + HDL coro; + minig(promise_type& p) : coro(HDL::from_promise(p)) {} + ~minig() { coro.destroy(); } + bool move_next() { + coro.resume(); + return !coro.done(); + } + int current_value() { + // this coroutine is not suspended therefore a call to destroy is undefined + // behaviour + coro.destroy(); + return coro.promise().val; + } +}; + +static minig f(int n) { + for (int i = 0; i < n; ++i) + co_yield i; +} + +int main() { + auto g = f(10); + int sum = 0; + while (g.move_next()) + sum += g.current_value(); + + return sum; +} +\end{codeblock} +\end{example} + +\rSec2[ub.dcl.attr.assume]{Assumption attribute} + +\pnum +\ubxref{dcl.attr.assume.false} +If an assumption expression would not evaluate to true at the point where it +appears the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int g(int x) { + [[assume(x >= 0)]]; + return x/32; +} + +int f() { + return g(-10); // undefined behavior, assumption in \tcode{g} is \tcode{false} +} +\end{codeblock} +\end{example} + + +\rSec2[ub.dcl.attr.noreturn]{Noreturn attribute} + +\pnum +\ubxref{dcl.attr.noreturn.eventually.returns} +If a function f is called where f was previously declared with the \tcode{noreturn} attribute and f eventually returns, +the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +[[noreturn]] void f(int i) { + if (i > 0) + throw "positive"; +} + +int main() { + f(0); // undefined behavior, returns from a [[noreturn]] function +} +\end{codeblock} +\end{example} + + +\rSec1[ub.class]{\ref{class}: Classes} + +\rSec2[ub.class.dtor]{Destructors} + +\pnum +\ubxref{class.dtor.no.longer.exists} +Once a destructor is invoked for an object, +the object's lifetime has ended; +the behavior is undefined if the +destructor is invoked for an object whose lifetime has ended. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + ~A() {} +}; + +int main() { + A a; + a.~A(); +} // undefined behavior, lifetime of \tcode{a} already ended before implicit destructor +\end{codeblock} +\end{example} + + +\rSec2[ub.class.abstract]{Abstract classes} + +\pnum +\ubxref{class.abstract.pure.virtual} +Calling a pure virtual function from a constructor or destructor in an abstract class is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B { + virtual void f() = 0; + B() { + f(); // undefined behavior, \tcode{f} is pure virtual and we are calling from the constructor + } +}; + +struct D : B { + void f() override; +}; +\end{codeblock} +\end{example} + + +\rSec2[ub.class.base.init]{Initializing bases and members} + +\pnum +\ubxref{class.base.init.mem.fun} +It is undefined behavior to call a member function before all the \grammarterm{mem-initializer}s for base classes have completed. + +\pnum +\begin{example} +\begin{codeblock} +class A { +public: + A(int); +}; + +class B : public A { + int j; + +public: + int f(); + B() + : A(f()), // undefined: calls member function but base A not yet initialized + j(f()) {} // well-defined: bases are all initialized +}; + +class C { +public: + C(int); +}; + +class D : public B, C { + int i; + +public: + D() + : C(f()), // undefined: calls member function but base \tcode{C} not yet initialized + i(f()) {} // well-defined: bases are all initialized +}; +\end{codeblock} +\end{example} + + +\rSec2[ub.class.cdtor]{Construction and destruction} + +\pnum +\ubxref{class.cdtor.before.ctor} +For an object with a non-trivial constructor, referring to any non-static member or base class of the object +before the constructor begins execution results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct X { + int i; +}; +struct Y : X { + Y(); +}; // non-trivial +struct A { + int a; +}; +struct B : public A { + int j; + Y y; +}; // non-trivial + +extern B bobj; +B *pb = &bobj; // OK +int *p1 = &bobj.a; // undefined, refers to base class member +int *p2 = &bobj.y.i; // undefined, refers to member's member + +A *pa = &bobj; // undefined, upcast to a base class type +B bobj; // definition of \tcode{bobj} + +extern X xobj; +int *p3 = &xobj.i; // OK, \tcode{X} is a trivial class +X xobj; + +struct W { + int j; +}; +struct X : public virtual W {}; +struct Y { + int *p; + X x; + Y() : p(&x.j) { // undefined, \tcode{x} is not yet constructed + } +}; +\end{codeblock} +\end{example} + +%TODO: CM: Can this example be shortened? + + +\pnum +\ubxref{class.cdtor.after.dtor} +For an object with a non-trivial destructor, +referring to any non-static member or base class of the object +after the destructor finishes execution +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct X { + int i; + ~X(); // non-trivial +}; +X& g() +{ + static X x; + return x; +} +void f() +{ + X* px = &g(); + px->~X(); + int j = px->i; // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.cdtor.convert.pointer} +When converting a pointer to a base class of an object, +construction must have started and destruction must not have finished otherwise +this is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct A { }; +struct B : virtual A { }; +struct C : B { }; +struct D : virtual A { D(A*); }; +struct X { X(A*); }; + +struct E : C, D, X { + E() : D(this), // undefined behavior: upcast from \tcode{E*} to \tcode{A*} might use path \tcode{E*} $\rightarrow$ \tcode{D*} $\rightarrow$ \tcode{A*} + // but \tcode{D} is not constructed + + // ``\tcode{D((C*)this)}\!'' would be defined: \tcode{E*} $\rightarrow$ \tcode{C*} is defined because \tcode{E()} has started, + // and \tcode{C*} $\rightarrow$ \tcode{A*} is defined because \tcode{C} is fully constructed + + X(this) {} // defined: upon construction of \tcode{X}, \tcode{C/B/D/A} sublattice is fully constructed +}; +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.cdtor.form.pointer} +When forming a pointer to +a direct non-static member of a class, +construction must have started +and destruction must not have finished +otherwise the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + int i = 0; +}; +struct B { + int *p; + A a; + B() : p(&a.i) {} // undefined behavior +}; +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.cdtor.virtual.not.x} +When a virtual function is called directly or indirectly from a constructor or from a destructor, +including during the construction or destruction of the class's non-static data members, and the object to +which the call applies is the object (call it \tcode{x}) under construction or destruction, the function called is the +final overrider in the constructor's or destructor's class and not one overriding it in a more-derived class. +If the virtual function call uses an explicit class member access\iref{expr.ref} and the object expression refers +to the complete object of \tcode{x} or one of that object's base class subobjects but not \tcode{x} or one of its base class +subobjects, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct V { + virtual void f(); + virtual void g(); +}; + +struct A : virtual V { + virtual void f(); +}; + +struct B : virtual V { + virtual void g(); + B(V *, A *); +}; + +struct D : A, B { + virtual void f(); + virtual void g(); + D() : B((A *)this, this) {} +}; + +B::B(V *v, A *a) { + f(); // calls \tcode{V::f}, not \tcode{A::f} + g(); // calls \tcode{B::g}, not \tcode{D::g} + v->g(); // \tcode{v} is base of \tcode{B}, the call is well-defined, calls \tcode{B::g} + a->f(); // undefined behavior, \tcode{a}'s type not a base of \tcode{B} +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{class.cdtor.typeid} +If the operand of \tcode{typeid} refers to +the object under construction or destruction and the static type of the operand is neither the constructor or +destructor's class nor one of its bases, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct V { + virtual void f(); +}; + +struct A : virtual V {}; +struct B : virtual V { + B(V *, A *); +}; + +struct D : A, B { + D() : B((A *)this, this) {} +}; + +B::B(V *v, A *a) { + typeid(*this); // \tcode{std::type_info} for \tcode{B} + typeid(*v); // well-defined: \tcode{*v} has type \tcode{V}, a base of \tcode{B} yields \tcode{std::type_info} for \tcode{B} + typeid(*a); // undefined behavior: type \tcode{A} not a base of \tcode{B} +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{class.cdtor.dynamic.cast} +If the operand of the +\tcode{dynamic_cast} refers to the object under construction or destruction and the static type of the operand is +not a pointer to or object of the constructor or destructor's own class or one of its bases, the \tcode{dynamic_cast} +results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct V { + virtual void f(); +}; + +struct A : virtual V {}; +struct B : virtual V { + B(V *, A *); +}; + +struct D : A, B { + D() : B((A *)this, this) {} +}; + +B::B(V *v, A *a) { + dynamic_cast(v); // well-defined: \tcode{v} of type \tcode{V*}, \tcode{V} base of \tcode{B} results in \tcode{B*} + dynamic_cast(a); // undefined behavior: \tcode{a} has type \tcode{A*}, \tcode{A} not a base of \tcode{B} +} +\end{codeblock} +\end{example} + + +\rSec1[ub.temp]{\ref{temp}: Templates} +\rSec2[ub.temp.inst]{Implicit instantiation} + +\pnum +\ubxref{temp.inst.inf.recursion} +The result of an infinite recursion in template instantiation is undefined. + +\pnum +\begin{example} +\begin{codeblock} +template +class X { + X *p; // OK + X a; // implicit instantiation of \tcode{X} requires + // the implicit instantiation of \tcode{X} which requires + // the implicit instantiation of \tcode{X} which \ldots +}; + +int main() { + X x; // undefined behavior, instantiation will kick off infinite recursion +} +\end{codeblock} +\end{example} + + +\rSec1[ub.except]{\ref{except}: Exception handling} + +\rSec2[ub.except.handle]{Handling an exception} + +\pnum +\ubxref{except.handle.handler.ctor.dtor} +Referring to any non-static member or base class of an object in the handler for a \grammarterm{function-try-block} of a +constructor or destructor for that object results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +struct A { + A() try : x(0 ? 1 : throw 1) { + } catch (int) { + std::cout << "y: " << y << std::endl; // undefined behavior, referring to non-static member y in + // the handler of function-try-block + } + int x; + int y = 42; +}; +\end{codeblock} +\end{example} diff --git a/source/utilities.tex b/source/utilities.tex index d714c1f2ef..7b5fe5d565 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -376,19 +376,19 @@ }; void g() { - shared_ptr sp1 = factory(2, 1.414); // error: 2 will not bind to \tcode{int\&} + shared_ptr sp1 = factory(2, 1.414); // error: \tcode{2} will not bind to \tcode{int\&} int i = 2; shared_ptr sp2 = factory(i, 1.414); // OK } \end{codeblock} In the first call to \tcode{factory}, -\tcode{A1} is deduced as \tcode{int}, so 2 is forwarded +\tcode{A1} is deduced as \tcode{int}, so \tcode{2} is forwarded to \tcode{A}'s constructor as an rvalue. In the second call to \tcode{factory}, \tcode{A1} is deduced as \tcode{int\&}, so \tcode{i} is forwarded to \tcode{A}'s constructor as an lvalue. In both cases, \tcode{A2} is deduced as \tcode{double}, so -1.414 is forwarded to \tcode{A}'s constructor as an rvalue. +\tcode{1.414} is forwarded to \tcode{A}'s constructor as an rvalue. \end{example} \end{itemdescr} @@ -660,7 +660,7 @@ \begin{itemdescr} \pnum \mandates -Each of \tcode{T} and \tcode{U} is +Each of \tcode{T} and \tcode{R} is a signed or unsigned integer type\iref{basic.fundamental}. \pnum @@ -1524,8 +1524,8 @@ the class template \tcode{tuple} that can be instantiated with any number of arguments. Each template argument specifies the type of an element in the \tcode{tuple}. Consequently, tuples are -heterogeneous, fixed-size collections of values. An instantiation of \tcode{tuple} with -two arguments is similar to an instantiation of \tcode{pair} with the same two arguments. +heterogeneous, fixed-size collections of values. A specialization of \tcode{tuple} with +two arguments behaves similarly to a specialization of \tcode{pair} with the same two arguments. See~\ref{pairs}. \pnum @@ -3966,7 +3966,7 @@ \begin{itemdescr} \pnum -\mandates +\constraints \tcode{is_constructible_v} is \tcode{true}. \pnum @@ -5925,7 +5925,8 @@ \pnum \throws -Any exception thrown by direct-initializing any $\tcode{T}_i$ for all $i$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -5956,7 +5957,8 @@ \pnum \throws -Any exception thrown by move-constructing any $\tcode{T}_i$ for all $i$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6024,7 +6026,8 @@ \pnum \throws -Any exception thrown by the initialization of the selected alternative $\tcode{T}_j$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6058,7 +6061,8 @@ \pnum \throws -Any exception thrown by calling the selected constructor of \tcode{T}. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6091,7 +6095,8 @@ \pnum \throws -Any exception thrown by calling the selected constructor of \tcode{T}. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6125,7 +6130,8 @@ \pnum \throws -Any exception thrown by calling the selected constructor of $\tcode{T}_I$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6158,6 +6164,11 @@ \ensures \tcode{index()} is \tcode{I}. +\pnum +\throws +Any exception thrown by +the initialization of the contained value. + \pnum \remarks If $\tcode{T}_I$'s selected constructor is a constexpr constructor, this @@ -9545,7 +9556,7 @@ \pnum \returns -If \tcode{x.has_value()} is \tcode{true}, +If \tcode{!x.has_value()} is \tcode{true}, \tcode{x.error() == e.error()}; otherwise \tcode{false}. \end{itemdescr} @@ -10542,7 +10553,7 @@ constexpr reference& operator=(const reference& x) noexcept; // for \tcode{b[i] = b[j];} constexpr const reference& operator=(bool x) const noexcept; constexpr operator bool() const noexcept; // for \tcode{x = b[i];} - constexpr bool operator~() const noexcept; // flips the bit + constexpr bool operator~() const noexcept; constexpr reference& flip() noexcept; // for \tcode{b[i].flip();} friend constexpr void swap(reference x, reference y) noexcept; @@ -10687,6 +10698,29 @@ \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator bool}{bitset::reference}% +\begin{itemdecl} +constexpr reference::operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if the value of the bit referred to by \tcode{*this} is one, +\tcode{false} otherwise. +\end{itemdescr} + +\indexlibrarymember{operator~}{bitset::reference}% +\begin{itemdecl} +constexpr bool reference::operator~() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!bool(*this)}. +\end{itemdescr} + \indexlibrarymember{swap}{bitset::reference}% \begin{itemdecl} constexpr void swap(reference x, reference y) noexcept; @@ -15943,15 +15977,8 @@ \pnum \constantwhen -\tcode{To}, \tcode{From}, and the types of all subobjects -of \tcode{To} and \tcode{From} are types \tcode{T} such that: -\begin{itemize} -\item \tcode{is_union_v} is \tcode{false}; -\item \tcode{is_pointer_v} is \tcode{false}; -\item \tcode{is_member_pointer_v} is \tcode{false}; -\item \tcode{is_volatile_v} is \tcode{false}; and -\item \tcode{T} has no non-static data members of reference type. -\end{itemize} +Neither \tcode{To} nor \tcode{From} +has constexpr-unknown representation\iref{expr.const}. \pnum \returns @@ -16067,7 +16094,7 @@ \remarks A function call expression that violates the precondition in the \expects element -is not a core constant expression\iref{expr.const}. +is not a core constant expression\iref{expr.const.core}. \end{itemdescr} \indexlibraryglobal{bit_floor}% diff --git a/tools/check-output.sh b/tools/check-output.sh index a28d236e0c..280fc1d423 100755 --- a/tools/check-output.sh +++ b/tools/check-output.sh @@ -36,34 +36,34 @@ rm -f tmp.txt # Find bad labels grep newlabel `ls *.aux | grep -v std.aux` | awk -F '{' '{ print $2 }' | - sed 's/}//g' | sed 's/^tab://;s/fig://;s/eq://;s/idx.*\..//' | + sed 's/}//g' | sed 's/^tab://;s/fig://;s/eq://;s/ub://;s/ubx://;s/ifndr://;s/ifndrx://;s/idx.*\..//' | grep -v '^[a-z.0-9]*$' | sed 's/^\(.*\)$/bad label \1/' | fail || failed=1 # Find grammar index entries missing a definition cat std-grammarindex.ind | - awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyperindexformat/ { def=1 }' | + awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyper(x{0,1})indexformat/ { def=1 }' | grep -v -- '-keyword$' | # xxx-keyword is special sed 's/^\(.*\)$/grammar non-terminal \1 has no definition/' | fail || failed=1 # Find header index entries missing a definition cat std-headerindex.ind | - awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } i=NF; while (i > 0 && $i !~ "<[a-z_.]*>") { --i; } item=$i; def=0; next } /hyperindexformat/ { def=1 }' | + awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } i=NF; while (i > 0 && $i !~ "<[a-z_.]*>") { --i; } item=$i; def=0; next } /hyper(x{0,1})indexformat/ { def=1 }' | sed 's/^\(.*\)$/header \1 has no definition/' | fail || failed=1 # Find concept index entries missing a definition cat std-conceptindex.ind | - sed 's/.hyperindexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/g' | + sed 's/.hyper\(x\{0,1\}\)indexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/g' | awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyperindexformat/ { def=1 }' | sed 's/^\(.*\)$/concept \1 has no definition/' | fail || failed=1 # Find undecorated concept names in code blocks patt="`cat std-conceptindex.ind | - sed 's/.hyperindexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/' | + sed 's/.hyper\(x\{0,1\}\)indexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/' | sed -n 's/^ .item.*{\([-a-z_]*\)}.*$/\1/p;s/^ .item.*frenchspacing \([a-z_]*\)}.*$/\1/p'`" patt="`echo $patt | sed 's/ /\\\\|/g'`" diff --git a/tools/check-source.sh b/tools/check-source.sh index ffd7c94d47..b473511598 100755 --- a/tools/check-source.sh +++ b/tools/check-source.sh @@ -242,7 +242,7 @@ done | fail 'hanging paragraph' || failed=1 # Subclauses without siblings -for f in $texfiles; do +for f in `ls $texfiles | grep -v ub.tex | grep -v ifndr.tex`; do sed -n '/^\\rSec/{=;p;}' $f | # prefix output with filename and line sed '/^[0-9]\+$/{N;s/\n/:/;}' | sed "s/.*/$f:&/" |