From 73caa2f64f011bdd00b1fdfd3381bbbb18d719ff Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:59:11 +0100 Subject: [PATCH 001/258] [class.temporary] Add \tcode for 1 and x in comment (#8699) --- source/basic.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index 266580c8bc..7c2324d17b 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -4891,7 +4891,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} From 56839539fc24a0db9573f0b0b2fbb79c3e72c8eb Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:39:23 +0100 Subject: [PATCH 002/258] [expr.pre] Add \tcode for the integer literal 5 (#8700) --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index 869c3de36a..f520442548 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -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 From b0f24d2b167a48ef035b87f9f27933e327d74869 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 10 Jan 2026 14:39:29 +0100 Subject: [PATCH 003/258] [time.zone.info.sys] Remove superfluous whitespace (#8701) --- source/time.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/time.tex b/source/time.tex index 023b13bf6b..cdd91bb116 100644 --- a/source/time.tex +++ b/source/time.tex @@ -9251,11 +9251,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} From b0d6ba91397baa666980c9d4e238cd1a7c813c38 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 10 Jan 2026 14:39:55 +0100 Subject: [PATCH 004/258] [ostringstream.general] Fix indentation (#8702) --- source/iostreams.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index d5d867ad11..cbaebfd5a4 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -9328,7 +9328,7 @@ template void str(const T& t); - private: + private: basic_stringbuf @\exposid{sb}@; // \expos }; } From 5d765ae69e949c29740beae0df179a7c4ecf50b6 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sun, 11 Jan 2026 09:54:50 +0100 Subject: [PATCH 005/258] [expr.prim.lambda.capture] Avoid automatic linebreak in comment (#8704) --- source/expressions.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index f520442548..92490e1783 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -2800,7 +2800,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++; }; From 626b8e67f9bee52e528474e419e10e17ae07f4ca Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 12 Jan 2026 10:08:48 +0100 Subject: [PATCH 006/258] [expr.prim.req.type] Add \tcode for void in comment (#8705) --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index 92490e1783..c628349682 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -3390,7 +3390,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 }; From 8ae8a31c168a9a246a8175ef506496921e7c9bc1 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 12 Jan 2026 20:54:33 +0100 Subject: [PATCH 007/258] [expr.reflect] Add \grammarterm for type-id in comment (#8706) --- source/expressions.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index c628349682..d113667e6d 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -6703,13 +6703,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{<} From d12392d9726d49158b45a0a5d5b6125818be2b8e Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 13 Jan 2026 21:37:45 +0100 Subject: [PATCH 008/258] [stmt.ambig] Add \grammarterm for type-name in comment (#8707) --- source/statements.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/statements.tex b/source/statements.tex index 8b9e733dc0..6521688f0e 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -1464,7 +1464,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} From 9c5257c03a98f6238f3b19d75f14dbf6faff6e0a Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:05:12 +0100 Subject: [PATCH 009/258] [dcl.inline] Add \keyword for inline (#8708) --- source/declarations.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/declarations.tex b/source/declarations.tex index 510def3e41..f55e86e8a6 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -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 From ba9d399e36e65277f9b1447169f2746d897763a7 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 16 Jan 2026 20:52:13 +0100 Subject: [PATCH 010/258] [dcl.ambig.res] Add \grammarterm for type-id in comment (#8709) --- source/declarations.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/declarations.tex b/source/declarations.tex index f55e86e8a6..098a0e7b16 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -2713,19 +2713,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; From c6b8e99e75bb6b4f60f533947423134df9976138 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 17 Jan 2026 10:00:16 +0100 Subject: [PATCH 011/258] [thread.lock.general] Remove superfluous whitespace (#8710) --- source/threads.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index 359af7dcd0..2793e02c59 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -8152,9 +8152,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} From 20e80e274d3fd47b24fafea3bcb1cf1694f9b4c6 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 17 Jan 2026 10:00:48 +0100 Subject: [PATCH 012/258] [atomics.ref.ops] Fix indentation (#8711) --- source/threads.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index 2793e02c59..86a06656f4 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -3459,16 +3459,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} From f4d39f7f37818334803afaa29fb5d8a5609dba04 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:17:26 +0100 Subject: [PATCH 013/258] [module.reach] Add $P$ for point P (#8713) --- source/modules.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/modules.tex b/source/modules.tex index 551e1ecc62..9d42164923 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -1064,7 +1064,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} From 099afac8c58693a18bbe81312b4bfc5654563c66 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:18:11 +0100 Subject: [PATCH 014/258] [module.interface] Add \tcode for the variable b in comment (#8712) --- source/modules.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/modules.tex b/source/modules.tex index 9d42164923..aeeb757edf 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -254,7 +254,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 From 7c8a960f3f06d5c565b0976402ce534848926181 Mon Sep 17 00:00:00 2001 From: Hewill Kang Date: Sat, 24 Jan 2026 00:52:07 +0800 Subject: [PATCH 015/258] [forward.list.overview] Add missing constexpr (#8717) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 771e3f1a06..f19ff73d25 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); From c2f05e242fa557c8e912f6ae3dd11a4d9aa55153 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 23 Jan 2026 23:59:47 +0100 Subject: [PATCH 016/258] [alg.transform] Fix indentation (#8718) --- source/algorithms.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 6f0001c5ca..b97b5fdd2e 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -7005,9 +7005,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 +7032,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, From e06fc0d2b99c8eb2e2d6a504c49ac77b07595e14 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:50:41 +0100 Subject: [PATCH 017/258] [class.expl.init] Add \tcode for literals (#8720) --- source/classes.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index c6bb8eb3f1..bbad2eca06 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -5359,9 +5359,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}. From 69a28b7b142a8ae53cfd120c814c755f1b9cc692 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:03:32 +0100 Subject: [PATCH 018/258] [basic.align] Add \grammarterm for alignment-specifier (#8721) --- source/basic.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index 7c2324d17b..22bce76c0c 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3766,7 +3766,7 @@ 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. From f3b76296f598bc5266e649f8fb0a2c5ef19ae0c3 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:52:54 +0100 Subject: [PATCH 019/258] [temp.dep.type] Add period to end of sentence (#8723) --- source/templates.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index 6cf798ea56..ece3280cc3 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -5557,7 +5557,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} From b518b58580612811a06f199d404627d44d1af126 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:54:59 +0100 Subject: [PATCH 020/258] [temp.arg.general] Add \grammarterm for type-id in comment (#8722) --- source/templates.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index ece3280cc3..49e20f1b48 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -1137,7 +1137,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} From e876fae3fc31ce25001501514b8e15db515faa8f Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:22:20 +0100 Subject: [PATCH 021/258] [temp.arg.explicit] Add \tcode for double in comment (#8724) --- source/templates.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index 49e20f1b48..9713148d19 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -7726,7 +7726,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 } From 6704d82cd336baaa4f6fe45013c390453991ee86 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 30 Jan 2026 21:57:16 +0100 Subject: [PATCH 022/258] [except.handle] Add commas (#8727) --- source/exceptions.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/exceptions.tex b/source/exceptions.tex index 2a4d6d7bd5..97159ae3f4 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -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 From c44f7ff10bda31f7f556f08dc1b293291fa3a231 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 30 Jan 2026 21:57:58 +0100 Subject: [PATCH 023/258] [flat.multimap.cons.alloc] Fix indentation (#8728) --- source/containers.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index f19ff73d25..c9599cfae5 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -18774,11 +18774,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} From 42aa7314e9897fedd08e4ab4acee2be70edd827e Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 30 Jan 2026 21:59:00 +0100 Subject: [PATCH 024/258] [except.pre] Add \grammarterm for ctor-initializer in comment (#8726) --- source/exceptions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exceptions.tex b/source/exceptions.tex index 97159ae3f4..bdff147766 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} From 16f4265888fd30e59512a21a5391327d6b525de1 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 31 Jan 2026 19:28:43 +0100 Subject: [PATCH 025/258] [value.error.codes] Fix indefinite article (#8730) --- source/lib-intro.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lib-intro.tex b/source/lib-intro.tex index c0b53ee3ad..24ca37c96e 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -3977,7 +3977,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 From 91156093a76177329a990dfdf38f19dad3531688 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 3 Feb 2026 23:19:25 +0100 Subject: [PATCH 026/258] [concept.comparisoncommontype] Add period to end of sentence (#8731) --- source/concepts.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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}} From 90c04ae6a082468f20629b2b2df4fa99419d1eef Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 6 Feb 2026 08:32:24 +0100 Subject: [PATCH 027/258] [util.smartptr.shared.create] Add \tcode for double[2] in comment --- source/memory.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/memory.tex b/source/memory.tex index efbf7fee28..4ab41e8b88 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -4401,7 +4401,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} From de8b220b5356fcdd8267df2924b34625bfe8b4c9 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:08:33 +0100 Subject: [PATCH 028/258] [alg.replace] Fix indentation (#8733) --- source/algorithms.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index b97b5fdd2e..549330a441 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -7178,8 +7178,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 +7299,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, From 3186be76a5b9a0e6fbf455edb3f2b8eb102ac866 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 9 Feb 2026 08:23:48 +0100 Subject: [PATCH 029/258] [fs.op.last.write.time] Fix indentation (#8735) --- source/iostreams.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index cbaebfd5a4..d41f2ed6b6 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -18276,7 +18276,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} From e29080317233042d6565544e6ed64cdd4ed72343 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Thu, 12 Feb 2026 21:20:23 +0100 Subject: [PATCH 030/258] [hive.operations] Fix \ref to \iref (#8741) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index c9599cfae5..0238fcc59b 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -8931,7 +8931,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} From 09ceac82aa3f7af6ada41d8b061e043d7b71a3bb Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Thu, 12 Feb 2026 21:33:25 +0100 Subject: [PATCH 031/258] [list.cons] Add \tcode for list --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 0238fcc59b..aaaacac3ba 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -9235,7 +9235,7 @@ \begin{itemdescr} \pnum \effects -Constructs an empty list, using the specified allocator. +Constructs an empty \tcode{list}, using the specified allocator. \pnum \complexity From 73ea1c6edba2b093c00b1c8d0e27ae2b291624df Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:31:55 +0100 Subject: [PATCH 032/258] [list.overview] Fix \ref to \iref (#8742) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index aaaacac3ba..84bfe597b2 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -9074,7 +9074,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 { From a07940921e50586b6cbbb38f862c8a49a421e95b Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 13 Feb 2026 23:24:40 +0100 Subject: [PATCH 033/258] [flat.map.cons.alloc] Remove superfluous \linebreak (#8745) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 84bfe597b2..3d88461657 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -17619,7 +17619,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}. From 0233f33c60e5841b93ce8c6b3d866687076cc7c8 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:44:11 +0100 Subject: [PATCH 034/258] [mdspan.layout.leftpad.overview] Add \tcode for submdspan in comment (#8747) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 3d88461657..68620a7286 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -23272,7 +23272,7 @@ // \ref{mdspan.layout.leftpad.expo}, exposition-only members index_type @\exposid{stride-1}@ = @\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@; From cec0cec3ea65de1c612b8ee721b44337149e5ea4 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:44:54 +0100 Subject: [PATCH 035/258] [mdspan.layout.rightpad.overview] Add \tcode for submdspan in comment (#8748) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 68620a7286..563f54019e 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -23907,7 +23907,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@; From 17ab8c63738af24b907495c4b79d8e64ac34a014 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:51:54 +0100 Subject: [PATCH 036/258] [mdspan.sub.extents] Add $k$ for slices...[k] (#8749) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 563f54019e..3942fa789f 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -25917,7 +25917,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 From 9c4be84f078b1646254bb93c527aaa7cc4ecfff5 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:53:12 +0100 Subject: [PATCH 037/258] [alg.remove] Fix indentation (#8746) --- source/algorithms.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 549330a441..d825e2af40 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -7577,7 +7577,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 = {}); @@ -7701,7 +7701,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 = {}); From beb4ec8ade36aa4828dc83cc099dcda8053559da Mon Sep 17 00:00:00 2001 From: Jay Ghiron <55773281+Halalaluyafail3@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:53:43 -0500 Subject: [PATCH 038/258] [cpp.predefined] Add \tcode for integer literal (#8750) --- source/preprocessor.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index b9809ae664..f4cfe56686 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -2446,7 +2446,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} From e4d2633e730ca392322b183a0dec418f412768b1 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:05:21 +0100 Subject: [PATCH 039/258] [mdspan.sub.map.sliceable] Add \tcode for SMR, submdspan_mapping_result, and SM (#8752) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 3942fa789f..c33cc3aa19 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26034,7 +26034,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}, From 1df2d72a6b81bb277147af326f5997981e349d32 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:25:18 +0100 Subject: [PATCH 040/258] [mdspan.sub.map.right] Add $p$ for SliceSpecifiers...[p] (#8754) --- source/containers.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index c33cc3aa19..59c70e77aa 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26279,7 +26279,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 +26288,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; From bdfa4e1ff03b2de112054e4d7da81581b043f44a Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:26:30 +0100 Subject: [PATCH 041/258] [mdspan.sub.map.rightpad] Add $p$ for value p (#8755) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 59c70e77aa..d89458d46d 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26449,7 +26449,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} From 0c0733f9132cd70e91a7e87cb569a42890a246f0 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:05:19 +0100 Subject: [PATCH 042/258] [mdspan.sub.map.sliceable] Add $i$ for valid_slices...[i] (#8751) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index d89458d46d..414b15cf24 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -25997,7 +25997,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 From 5d731abbbd1afecc4fc16a363822a474a373872e Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:06:25 +0100 Subject: [PATCH 043/258] [mdspan.sub.map.left] Add $p$ for SliceSpecifiers...[p] (#8753) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 414b15cf24..00162914bc 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26202,7 +26202,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 From 0d9484b2551d5ff5aa54c5186e41d45ee290079e Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:35:48 +0100 Subject: [PATCH 044/258] [fs.op.create.hard.lk] Fix indentation (#8756) --- source/iostreams.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index d41f2ed6b6..57d6b304b9 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -17685,7 +17685,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} From f81fe2b6c4983cd1d5f231ea74d3288dcc4cb0fa Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:36:18 +0100 Subject: [PATCH 045/258] [fs.op.create.symlink] Fix indentation (#8757) --- source/iostreams.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index 57d6b304b9..88a3e67932 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -17720,7 +17720,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} From 15fc5a2f7106963d8e7904eee03bebe2aaf7a81b Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sun, 22 Feb 2026 20:45:53 +0100 Subject: [PATCH 046/258] [alg.remove] Use E(i) for predicate on iterator i (#8760) The `E` in the code is actually meant to be a function on an iterator `i`; amend both usages to `E(i)`. This was already done everywhere else (for instance in copy_if or unique_copy). --- source/algorithms.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index d825e2af40..96c8fad1c6 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -7604,7 +7604,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 +7621,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 From 5b07f42565be7972f2b5d729a740da12c5e6b202 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 24 Feb 2026 10:35:57 +0000 Subject: [PATCH 047/258] [thread.mutex.requirements.mutex.general] Fix grammar (#8765) --- source/threads.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/threads.tex b/source/threads.tex index 86a06656f4..b30a257a6e 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -7329,7 +7329,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 From 4ce955bd576f6a9d68da494e8b560ca8b9375005 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 24 Feb 2026 10:38:03 +0000 Subject: [PATCH 048/258] [exec.snd.expos] Fix order of make_obj_using_allocator arguments (#8766) --- source/exec.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index ddc8be2be3..514398b425 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -2117,11 +2117,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} From 3f6372b97bcdee30b8591077c8479a56bb50fc67 Mon Sep 17 00:00:00 2001 From: timsong-cpp Date: Wed, 25 Feb 2026 15:35:49 -0600 Subject: [PATCH 049/258] [const.wrap.class] Add missing this to compound assignment operators (#8758) This corrects a misapplication of LWG4383 in commit bdcfe2c9a54ca350e9bfc59227bb0285a59c635d. --- source/meta.tex | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index 76ba9b3dbd..48510a4e39 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -822,34 +822,34 @@ -> constant_wrapper { 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 {}; } }; From 9d68c490fc5a16f438817047e6cf4d38c109e926 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 25 Feb 2026 22:44:10 +0100 Subject: [PATCH 050/258] [partial.sort.copy] Fix indentation (#8769) --- source/algorithms.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 96c8fad1c6..ce84e9fdc7 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -9076,7 +9076,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 = {}, From d6fcada8eb25f82d0bec2431e209035b4a939d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Thu, 5 Mar 2026 17:18:30 +0000 Subject: [PATCH 051/258] [utility.arg.requirements] Remove \enlargethispage command. Not only was the value of that commmand questionable, but it also seems to be outright broken in recent LaTeX versions. --- source/lib-intro.tex | 1 - 1 file changed, 1 deletion(-) diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 24ca37c96e..d574273929 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -1850,7 +1850,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 From de532c5a8652bb86afff212c4da6683bffd69fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Thu, 5 Mar 2026 18:30:49 +0000 Subject: [PATCH 052/258] [macros] Create \tref and \fref commands if they doesn't exist yet. The existence of \tref and \fref seems to have changed as package versions have been evolving. --- source/macros.tex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/macros.tex b/source/macros.tex index ae5591106e..f47b65301b 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -406,8 +406,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. From ce032eb2d8481e01b1e08b24ec48426c38f5a87b Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Mon, 2 Mar 2026 08:52:44 +0100 Subject: [PATCH 053/258] [locale.categories.general] Add \tcode for OutputIterator --- source/text.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/text.tex b/source/text.tex index b89eaa3ea4..30bcb19151 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, From 8338b7caa5a38ef79e5c2f8316078f6f74d1b8ad Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:58:29 +0100 Subject: [PATCH 054/258] [text.encoding.id] Add colon after "as follows" (#8776) --- source/text.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/text.tex b/source/text.tex index 30bcb19151..d5bed79236 100644 --- a/source/text.tex +++ b/source/text.tex @@ -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}, From eba89bc9b32d230168571737d6aa86c06329502b Mon Sep 17 00:00:00 2001 From: Alisdair Meredith Date: Mon, 22 Dec 2025 17:59:19 -0500 Subject: [PATCH 055/258] [lex.phases] Make note on the notion of file more prominent The notion that when the standard refers to files does not necessarily imply a file in a traditional filing system is more fundamental than its late appearance in the middle of phase 7 of translation. Move that note right to the top of [lex] where we first talk of storing the program text in source files, where is will be understood even before the phases of translation. --- source/lex.tex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/lex.tex b/source/lex.tex index 80f2e8c1e6..a62b1e28bb 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, From 8db862830705655106372a295093e12afa79eec8 Mon Sep 17 00:00:00 2001 From: timsong-cpp Date: Thu, 5 Mar 2026 19:22:52 -0600 Subject: [PATCH 056/258] [mdspan.layout.leftpad.cons] Add missing \tcode --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 00162914bc..8afc9820b5 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -23424,7 +23424,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))}. From 7dadfcf4583f098a4a65780b5beea1add6be7874 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Mon, 16 Mar 2026 16:18:35 +0100 Subject: [PATCH 057/258] [check] Make check-output.sh tolerate new memoir version --- tools/check-output.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/check-output.sh b/tools/check-output.sh index a28d236e0c..8b23f65141 100755 --- a/tools/check-output.sh +++ b/tools/check-output.sh @@ -43,27 +43,27 @@ grep newlabel `ls *.aux | grep -v std.aux` | awk -F '{' '{ print $2 }' | # 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'`" From 13cad628c5c3883c8fb8dcb4256199b21c13be1d Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Thu, 12 Mar 2026 08:08:56 +0100 Subject: [PATCH 058/258] [istream.unformatted] Add right parenthesis --- source/iostreams.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index 88a3e67932..03e07d529a 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -5651,7 +5651,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. From 7da83561204c53aafaf71b06fb7e9207a7a3a9a7 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:10:21 +0100 Subject: [PATCH 059/258] [linalg.algs.blas2.rank2] Add whitespace after comma --- source/numerics.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/numerics.tex b/source/numerics.tex index b2d2e2ca07..95ada2c24b 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -15163,7 +15163,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 From 981d32246c951b18dc816cecfdb3ffbb5d72ad54 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:04:34 +0100 Subject: [PATCH 060/258] [stoptoken.concepts] Remove superfluous \item (#8790) --- source/threads.tex | 1 - 1 file changed, 1 deletion(-) diff --git a/source/threads.tex b/source/threads.tex index b30a257a6e..22f25a2413 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -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 From 1acf0f7668123ba6dd7f5bd0072c51a0d5af30bd Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:05:07 +0100 Subject: [PATCH 061/258] [linalg.syn] Add \tcode for layout_blas_packed (#8781) --- source/numerics.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/numerics.tex b/source/numerics.tex index 95ada2c24b..c09dd4c0fe 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -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; From 9a11bef2d8a8fc0d18d017435e866096423d8e14 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:05:22 +0100 Subject: [PATCH 062/258] [atomics.types.pointer] Fix indentation (#8779) --- source/threads.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index 22f25a2413..0685a8748f 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -5744,11 +5744,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; From a28498a3ecbe8f664f32d69aa4ec81b779638180 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:22:28 +0100 Subject: [PATCH 063/258] [exec.adapt.obj] Add \tcode for arg (#8796) --- source/exec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exec.tex b/source/exec.tex index 514398b425..c45c516cf0 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -3099,7 +3099,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} From 4ac5960c8765ae53f36bff29a2cdd2eb0756ae0f Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 19 Mar 2026 17:06:02 -0700 Subject: [PATCH 064/258] [exec.as.awaitable] Fix formatting of exposition-only member (#8798) --- source/exec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exec.tex b/source/exec.tex index c45c516cf0..e8d168a005 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -6735,7 +6735,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} From 92b3a22228ffb3db219debace0e5fbe82c592354 Mon Sep 17 00:00:00 2001 From: Can Date: Fri, 20 Mar 2026 10:32:30 +0300 Subject: [PATCH 065/258] [utility.intcmp] Fix name of type parameter (#8770) Introduced by commit 93914a36c1945d330a7c7d5c4488e1d10e5bbe75 . --- source/utilities.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/utilities.tex b/source/utilities.tex index d714c1f2ef..1c94dd43dd 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -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 From 11106fc54b79e1ee21805ea77596908ca4f3a8f3 Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Fri, 20 Mar 2026 10:56:06 -0700 Subject: [PATCH 066/258] [mdspan.sub.map.common,mdspan.sub.map.left] Fix S(p)liceSpecifiers typos (#8799) --- source/containers.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 8afc9820b5..49498c4221 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26105,7 +26105,7 @@ \pnum \constraints -\tcode{sizeof...(SpliceSpecifiers)} equals \tcode{extents_type::rank()}. +\tcode{sizeof...(SliceSpecifiers)} equals \tcode{extents_type::rank()}. \pnum \mandates @@ -26184,14 +26184,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 From 74c5dcc8f1d5964e6c1b92d6fa059507c9b94f13 Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Fri, 20 Mar 2026 10:56:28 -0700 Subject: [PATCH 067/258] [polymorphic.ctor] Fix wrong \indexlibraryctor (#8800) --- source/memory.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/memory.tex b/source/memory.tex index 4ab41e8b88..de7072f538 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -6796,7 +6796,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} From 36ce9cbe82d472997ca9b978e69e64d6ddd99dcd Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Fri, 20 Mar 2026 10:56:49 -0700 Subject: [PATCH 068/258] [linalg.algs.blas3.rank2k] Add missing \pnum and \effects (#8801) --- source/numerics.tex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/numerics.tex b/source/numerics.tex index c09dd4c0fe..a5711be9fd 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16038,6 +16038,8 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\effects Computes $C = E + A B^T + B A^T$. \end{itemdescr} From 7831080768f697c0b879298ff229148b6d8d6c6b Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Fri, 20 Mar 2026 10:57:06 -0700 Subject: [PATCH 069/258] [linalg.algs.blas3.rank2k] Add missing \exposid for multipliable (#8802) --- source/numerics.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/numerics.tex b/source/numerics.tex index a5711be9fd..4946194763 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -15973,7 +15973,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. From 8eced2a9075aef2f9cc008dc129fbf23ff1d8dff Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 21 Mar 2026 10:34:36 +0100 Subject: [PATCH 070/258] [is.sorted] Fix indentation (#8804) --- source/algorithms.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index ce84e9fdc7..f5adcd0dd3 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -9281,7 +9281,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 From cda7c18d2b83b354bae6001cdf7cb7d3f9203f32 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 21 Mar 2026 17:36:47 +0800 Subject: [PATCH 071/258] [lib] Replace bad uses of "instantiation" with "specialization" (#8379) Affected sections: - [allocator.requirements.general] - [namespace.std] - [pointer.traits.types] - [allocator.traits.types] - [tuple.general] - [format.context] - [numeric.requirements] - [rand.util.canonical] - [thread.req.lockable.timed] - [thread.sharedtimedmutex.requirements.general] - In [tuple.general], change "is similar to" to "behaves similarly to" to avoid confusing with "similar types" in the core specification. --- source/lib-intro.tex | 8 ++++---- source/memory.tex | 4 ++-- source/numerics.tex | 4 ++-- source/text.tex | 2 +- source/threads.tex | 18 +++++++++--------- source/utilities.tex | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/source/lib-intro.tex b/source/lib-intro.tex index d574273929..abe4ecf3b7 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -2346,12 +2346,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 @@ -3073,7 +3073,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}, @@ -3095,7 +3095,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 diff --git a/source/memory.tex b/source/memory.tex index de7072f538..a7f16411e8 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -837,7 +837,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} @@ -1710,7 +1710,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} diff --git a/source/numerics.tex b/source/numerics.tex index 4946194763..9e4db2e194 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 diff --git a/source/text.tex b/source/text.tex index d5bed79236..0bab2fec0f 100644 --- a/source/text.tex +++ b/source/text.tex @@ -7761,7 +7761,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}, diff --git a/source/threads.tex b/source/threads.tex index 0685a8748f..545aecdb63 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) @@ -7575,10 +7575,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}. @@ -7969,9 +7969,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} diff --git a/source/utilities.tex b/source/utilities.tex index 1c94dd43dd..804573eb30 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -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 From dc5928bdac7e3301d78c8fae5f4cae655a9a06fb Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 22 Mar 2026 14:14:40 +0800 Subject: [PATCH 072/258] [vector.bool.fmt][container.adaptors.format] Add missing `constexpr` and other missed edits (#8768) Fixes edits from P3391R2 missed by commit cc63c64cba30089a366b024ffc8cc0532b4fb508 . --- source/containers.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 49498c4221..19643dbff3 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -10735,7 +10735,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(const T& ref, FormatContext& ctx) const; }; } @@ -10756,7 +10756,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(const T& ref, FormatContext& ctx) const; \end{itemdecl} @@ -20308,7 +20308,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 +20330,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; }; } @@ -20352,7 +20352,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} From c6fecf491063eef95384e54813812f6c6aaeab6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Mon, 23 Mar 2026 11:40:36 +0000 Subject: [PATCH 073/258] [expected.object.eq] Add missing negation (misapplied wording). The negation was accidentally omitted in the application of P3905R0, approved in Kona 2025 (265b4774c754b36e50bec7a528cbbc87676b0c85). --- source/utilities.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/utilities.tex b/source/utilities.tex index 804573eb30..9ec1772423 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -9545,7 +9545,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} From 6913287752040f7adecdac5af60c90e2701a04e0 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 25 Feb 2026 15:04:34 +0800 Subject: [PATCH 074/258] [format] Consistently add `constexpr` to function descriptions P3391R2 only added `constexpr` to synopses but not descriptions for some formatting functions. This PR consistently adds `constexpr` to the descriptions. --- source/text.tex | 70 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/source/text.tex b/source/text.tex index 0bab2fec0f..bbd53b9f2c 100644 --- a/source/text.tex +++ b/source/text.tex @@ -6722,7 +6722,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 +6737,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 +6781,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 +6803,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 +6818,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 +6863,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 +6905,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 +6964,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 @@ -7771,7 +7773,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 +7797,7 @@ \indexlibrarymember{out}{basic_format_context}% \begin{itemdecl} -iterator out(); +constexpr iterator out(); \end{itemdecl} \begin{itemdescr} @@ -7806,7 +7808,7 @@ \indexlibrarymember{advance_to}{basic_format_context}% \begin{itemdecl} -void advance_to(iterator it); +constexpr void advance_to(iterator it); \end{itemdecl} \begin{itemdescr} @@ -8114,7 +8116,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 +8224,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 +8304,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 +8370,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 +8494,7 @@ \indexlibrary{\idxcode{basic_format_arg}!constructor|(}% \begin{itemdecl} -basic_format_arg() noexcept; +constexpr basic_format_arg() noexcept; \end{itemdecl} \begin{itemdescr} @@ -8502,7 +8504,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 +8576,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 +8588,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 +8600,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 +8632,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 +8669,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 +8695,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 +8717,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 +8766,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 +8779,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 +8949,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\seebelow@& elems, FormatContext& ctx) const; \end{itemdecl} From 863a970f0ba45e937faf4f4b52c22f7876339a69 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 25 Mar 2026 16:10:48 +0800 Subject: [PATCH 075/258] [lib] Fix indexing for certain operators (#8810) Some operator functions were not properly indexed previously due to missing LaTeX escaping. --- source/exec.tex | 2 +- source/numerics.tex | 24 ++++++++++++------------ source/ranges.tex | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index e8d168a005..d5e90772a1 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -3071,7 +3071,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}. diff --git a/source/numerics.tex b/source/numerics.tex index 9e4db2e194..6985c1f5b3 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -17591,7 +17591,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); @@ -18388,7 +18388,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} @@ -18404,7 +18404,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} @@ -18461,7 +18461,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} @@ -18525,7 +18525,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} @@ -18585,7 +18585,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} @@ -20619,10 +20619,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; @@ -20713,9 +20713,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 @@ -20744,7 +20744,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& @@ -20772,7 +20772,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/ranges.tex b/source/ranges.tex index 6d8022e929..efc1087f4a 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -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 From c7f267942684eefee32b6e914698763ea2b54b62 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:53:49 +0100 Subject: [PATCH 076/258] [alg.partitions] Fix indentation (#8812) --- source/algorithms.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index f5adcd0dd3..e9773214ea 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -9892,7 +9892,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, From 45c820b6a9d87b18f3ad5c445c5e61e2ee806a6d Mon Sep 17 00:00:00 2001 From: Hubert Tong Date: Tue, 16 Dec 2025 23:52:12 -0500 Subject: [PATCH 077/258] [diff.basic] Use enum example instead of example outdated since C99 C99 subclause 6.2.7, "Compatible type and composite type", had this sentence: > If one is declared with a tag, the other shall be declared with the > same tag. --- source/compatibility.tex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/compatibility.tex b/source/compatibility.tex index a0ae25da56..32a7cf5368 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -2916,11 +2916,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 From 3e53098c0ef22b62ab2dd393411141fceeda03bd Mon Sep 17 00:00:00 2001 From: Hubert Tong Date: Tue, 16 Dec 2025 23:57:14 -0500 Subject: [PATCH 078/258] [diff.basic] Stop claiming, as harmless, type-based aliasing violations --- source/compatibility.tex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/compatibility.tex b/source/compatibility.tex index 32a7cf5368..edbd9196d1 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -2927,9 +2927,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 From c40c5f03a02c7e0f2564de46aea4ceebb1c799e4 Mon Sep 17 00:00:00 2001 From: Jan Schultke Date: Fri, 13 Feb 2026 12:21:45 +0100 Subject: [PATCH 079/258] [intro.compliance.general] Mark documentation encouragement as recommended practice --- source/intro.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/source/intro.tex b/source/intro.tex index 5cb98d2101..5179e1e580 100644 --- a/source/intro.tex +++ b/source/intro.tex @@ -860,6 +860,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. From d8ff3c08615932a207f956a61ebd6e5805f9a9bd Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Sun, 14 Dec 2025 17:15:48 +0000 Subject: [PATCH 080/258] [basic.stc.dynamic] Spell out compound type names --- source/basic.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 22bce76c0c..a97152a54c 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -4483,7 +4483,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 @@ -4604,9 +4604,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 From e70a19ba60ccf3eeed62bf82e4b33584272a1c86 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Thu, 26 Feb 2026 08:30:31 +0100 Subject: [PATCH 081/258] [lex.key] Emphasize that keywords are created in phase 6 This was overlooked in CWG3094, applied with commit 94055b39a90285d8ae15f8f864a39a328f42a359. --- source/lex.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lex.tex b/source/lex.tex index a62b1e28bb..7547b4aa69 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -1021,7 +1021,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. From 0807a339b8bcae60a9d2285f0a08aab61aeece0d Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Thu, 29 Jan 2026 07:59:28 -0600 Subject: [PATCH 082/258] Clarify pack-index-specifier rules --- source/declarations.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/declarations.tex b/source/declarations.tex index 098a0e7b16..ee13005979 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1537,7 +1537,7 @@ \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 From f55d63dcef1640f292451a3efe98f56d4afa2383 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Sun, 14 Dec 2025 17:56:03 +0000 Subject: [PATCH 083/258] [basic.fundamental] Strike explanatory sentence; touch up note --- source/basic.tex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index a97152a54c..72fb4d8b42 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -5635,13 +5635,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}, From f4d8ecb2aa29122d63e5f56119a83dd4bb2ad3ca Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Sun, 14 Dec 2025 18:23:18 +0000 Subject: [PATCH 084/258] [basic.extended.fp] Replace "typedef-name" with "type alias" --- source/basic.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 72fb4d8b42..377e72ddc9 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -5770,7 +5770,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} @@ -5780,7 +5780,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. @@ -5789,7 +5789,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. @@ -5798,7 +5798,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. @@ -5811,7 +5811,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. From 2efe693eb09f8c6d364c757a82b640e2ced9f107 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Wed, 17 Dec 2025 14:32:48 +0100 Subject: [PATCH 085/258] [intro.refs], [numeric.limits] Remove all references to ISO/IEC 10967-1:2012 --- source/back.tex | 4 ---- source/support.tex | 38 -------------------------------------- 2 files changed, 42 deletions(-) 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/support.tex b/source/support.tex index f4f632944b..5f028cddc2 100644 --- a/source/support.tex +++ b/source/support.tex @@ -1110,11 +1110,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 +1319,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 +1425,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 +1444,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 +1463,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 +1479,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 +1495,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 +1512,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 +1547,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 +1564,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 +1590,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 +1607,6 @@ \begin{footnote} Refer to \IsoFloatUndated{}. -Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1660,7 +1623,6 @@ The rounding style for the type. \begin{footnote} Equivalent to \tcode{FLT_ROUNDS}. -Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum From b54449db95dcdfa8ae4d8221ef55f7fca0f358d9 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Sun, 14 Dec 2025 23:06:53 +0000 Subject: [PATCH 086/258] [basic.start.static] Improve readability of example --- source/basic.tex | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 377e72ddc9..527c22615c 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -7348,16 +7348,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} From cd15f7a88e6390fb31aa766196205e722779d240 Mon Sep 17 00:00:00 2001 From: Hubert Tong Date: Thu, 18 Dec 2025 19:41:46 -0500 Subject: [PATCH 087/258] [stmt.pre] Streamline decl-specifier restrictions on conditions, etc. Avoid an abrupt shift from a mathematical introduction to the specification of additional normative requirements. Expresses universal quantification more directly. --- source/statements.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/statements.tex b/source/statements.tex index 6521688f0e..2b3d55ac32 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -147,11 +147,11 @@ 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}% From d3f57042d283c06cdb066eab1fc61661df0fc4de Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sun, 23 Jul 2023 14:23:21 +0200 Subject: [PATCH 088/258] [temp.point] Itemize long conditionals in three paragraphs --- source/templates.tex | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/source/templates.tex b/source/templates.tex index 9713148d19..6ed2dfd3e5 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -6165,11 +6165,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 +6185,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 +6202,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. From ecc669c503bb875b65cbd4de3d231a8ac9e4bb70 Mon Sep 17 00:00:00 2001 From: Hewill Kang Date: Tue, 10 Mar 2026 15:07:57 +0800 Subject: [PATCH 089/258] [meta.syn] Add function parameter names These two seem to be the only ones where the function parameter names are omitted in the declaration. Add names to ensure consistency. --- source/meta.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index 48510a4e39..608ec79972 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -3089,7 +3089,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 +3113,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); From 98a668efc2ab0bea86dcf9a2d8bf583dddc35e32 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Thu, 26 Mar 2026 21:57:48 +0100 Subject: [PATCH 090/258] [expr.const] Introduce subclauses --- source/expressions.tex | 696 +++++++++++++++++++++-------------------- 1 file changed, 360 insertions(+), 336 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index d113667e6d..888f8c0627 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -8280,12 +8280,19 @@ \end{example} \end{note} -\rSec1[expr.const]{Constant expressions}% +\rSec1[expr.const]{Constant evaluation}% \indextext{expression!constant} +\rSec2[expr.const.general]{General} + +\begin{bnf} +\nontermdef{constant-expression}\br + conditional-expression +\end{bnf} + \pnum Certain contexts require expressions that satisfy additional -requirements as detailed in this subclause; other contexts have different +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, @@ -8295,188 +8302,30 @@ during translation. \end{note} -\begin{bnf} -\nontermdef{constant-expression}\br - conditional-expression -\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} +\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} -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. -\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}. +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. - -\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 -\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} -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.core]{Core constant expressions} \pnum An expression $E$ is a \defnadj{core constant}{expression} @@ -8927,112 +8776,30 @@ \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$. -\end{itemize} - -\pnum -An \defnadj{integral constant}{expression} -is an expression of integral or -unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. -\begin{note} -Such expressions can be -used as bit-field lengths\iref{class.bit}, as enumerator -initializers if the underlying type is not fixed\iref{dcl.enum}, -and as alignments\iref{dcl.align}. -\end{note} - -\pnum -If an expression of literal class type is used in a context where an -integral constant expression is required, then that expression is -contextually implicitly converted\iref{conv} to an integral or unscoped -enumeration type -and the selected conversion function shall be \keyword{constexpr}. +$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 A { - constexpr A(int i) : val(i) { } - constexpr operator int() const { return val; } - constexpr operator long() const { return 42; } -private: - int val; -}; -constexpr A a = alignof(int); -alignas(a) int n; // error: ambiguous conversion -struct B { int n : a; }; // error: ambiguous conversion -\end{codeblock} -\end{example} - -\pnum -A \defnadj{converted constant}{expression} -of type \tcode{T} is an -expression, implicitly converted to type \tcode{T}, where -the converted expression is a constant expression and the -implicit conversion sequence contains only -\begin{itemize} -\item user-defined conversions, -\item lvalue-to-rvalue conversions\iref{conv.lval}, -\item array-to-pointer conversions\iref{conv.array}, -\item function-to-pointer conversions\iref{conv.func}, -\item qualification conversions\iref{conv.qual}, -\item integral promotions\iref{conv.prom}, -\item integral conversions\iref{conv.integral} other than narrowing conversions\iref{dcl.init.list}, -\item floating-point promotions\iref{conv.fpprom}, -\item floating-point conversions\iref{conv.double} where - the source value can be represented exactly in the destination type, -\item null pointer conversions\iref{conv.ptr} from \tcode{std::nullptr_t}, -\item null member pointer conversions\iref{conv.mem} from \tcode{std::nullptr_t}, and -\item function pointer conversions\iref{conv.fctptr}, -\end{itemize} -and where the reference binding (if any) binds directly. -\begin{note} -Such expressions can be used in \keyword{new} -expressions\iref{expr.new}, as case expressions\iref{stmt.switch}, -as enumerator initializers if the underlying type is -fixed\iref{dcl.enum}, as array bounds\iref{dcl.array}, -as constant template arguments\iref{temp.arg}, -and as the constant expression of a \grammarterm{splice-specifier}\iref{basic.splice}. -\end{note} -\indextext{contextually converted constant expression of type \tcode{bool}|see{conversion, contextual}}% -\indextext{conversion!contextual to constant expression of type \tcode{bool}}% -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. - -\pnum -A \defnadj{constant}{expression} is either -\begin{itemize} -\item -a glvalue core constant expression $E$ for which -\begin{itemize} -\item -$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. +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} @@ -9090,27 +8857,261 @@ \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 \defnadj{integral constant}{expression} +is an expression of integral or +unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. \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. +Such expressions can be +used as bit-field lengths\iref{class.bit}, as enumerator +initializers if the underlying type is not fixed\iref{dcl.enum}, +and as alignments\iref{dcl.align}. +\end{note} + +\pnum +If an expression of literal class type is used in a context where an +integral constant expression is required, then that expression is +contextually implicitly converted\iref{conv} to an integral or unscoped +enumeration type +and the selected conversion function shall be \keyword{constexpr}. \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; +struct A { + constexpr A(int i) : val(i) { } + constexpr operator int() const { return val; } + constexpr operator long() const { return 42; } +private: + int val; +}; +constexpr A a = alignof(int); +alignas(a) int n; // error: ambiguous conversion +struct B { int n : a; }; // error: ambiguous conversion +\end{codeblock} +\end{example} + +\pnum +A \defnadj{converted constant}{expression} +of type \tcode{T} is an +expression, implicitly converted to type \tcode{T}, where +the converted expression is a constant expression and the +implicit conversion sequence contains only +\begin{itemize} +\item user-defined conversions, +\item lvalue-to-rvalue conversions\iref{conv.lval}, +\item array-to-pointer conversions\iref{conv.array}, +\item function-to-pointer conversions\iref{conv.func}, +\item qualification conversions\iref{conv.qual}, +\item integral promotions\iref{conv.prom}, +\item integral conversions\iref{conv.integral} other than narrowing conversions\iref{dcl.init.list}, +\item floating-point promotions\iref{conv.fpprom}, +\item floating-point conversions\iref{conv.double} where + the source value can be represented exactly in the destination type, +\item null pointer conversions\iref{conv.ptr} from \tcode{std::nullptr_t}, +\item null member pointer conversions\iref{conv.mem} from \tcode{std::nullptr_t}, and +\item function pointer conversions\iref{conv.fctptr}, +\end{itemize} +and where the reference binding (if any) binds directly. +\begin{note} +Such expressions can be used in \keyword{new} +expressions\iref{expr.new}, as case expressions\iref{stmt.switch}, +as enumerator initializers if the underlying type is +fixed\iref{dcl.enum}, as array bounds\iref{dcl.array}, +as constant template arguments\iref{temp.arg}, +and as the constant expression of a \grammarterm{splice-specifier}\iref{basic.splice}. +\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 +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} -It is unspecified whether the value of \tcode{f()} will be \tcode{true} or \tcode{false}. \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} +\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. \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} +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} +\end{example} + +\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} @@ -9193,6 +9194,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; } @@ -9259,52 +9262,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 @@ -9352,6 +9310,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 { @@ -9447,6 +9407,55 @@ any evaluation sequenced before $X$\iref{intro.execution}. \end{itemize} +\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 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} + \pnum \indextext{expression!potentially constant evaluated}% An expression or conversion is \defn{potentially constant evaluated} @@ -9490,4 +9499,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|)} From a2933d5fd4e592bcd8669a51a359c5a850b32de2 Mon Sep 17 00:00:00 2001 From: Davis Herring Date: Thu, 26 Mar 2026 21:00:20 +0000 Subject: [PATCH 091/258] Refine cross references into [expr.const] --- source/algorithms.tex | 2 +- source/basic.tex | 28 ++++++++++++++-------------- source/classes.tex | 8 ++++---- source/containers.tex | 6 +++--- source/declarations.tex | 34 +++++++++++++++++----------------- source/exceptions.tex | 2 +- source/exec.tex | 2 +- source/expressions.tex | 12 ++++++------ source/intro.tex | 12 ++++++------ source/iterators.tex | 4 ++-- source/limits.tex | 2 +- source/meta.tex | 12 ++++++------ source/modules.tex | 2 +- source/numerics.tex | 2 +- source/preprocessor.tex | 2 +- source/ranges.tex | 6 +++--- source/statements.tex | 10 +++++----- source/support.tex | 2 +- source/templates.tex | 16 ++++++++-------- source/text.tex | 10 +++++----- source/utilities.tex | 2 +- 21 files changed, 88 insertions(+), 88 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index e9773214ea..20e520ab63 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -13510,7 +13510,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/basic.tex b/source/basic.tex index 527c22615c..f0107f05f7 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -498,7 +498,7 @@ \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} @@ -739,7 +739,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 +781,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} @@ -2834,7 +2834,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 @@ -3171,7 +3171,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} @@ -5351,7 +5351,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} @@ -6367,9 +6367,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 @@ -6436,7 +6436,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}, @@ -6616,7 +6616,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 @@ -7310,7 +7310,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 @@ -7563,7 +7563,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 @@ -7802,7 +7802,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} @@ -7823,7 +7823,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. diff --git a/source/classes.tex b/source/classes.tex index bbad2eca06..058a317666 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -717,7 +717,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 @@ -2750,7 +2750,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}. @@ -6341,7 +6341,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 +6377,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/containers.tex b/source/containers.tex index 19643dbff3..4aba72d02d 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -22032,7 +22032,7 @@ \begin{itemdescr} \pnum \result -A constant expression\iref{expr.const} of type \tcode{bool}. +A constant expression\iref{expr.const.const} of type \tcode{bool}. \pnum \returns @@ -22052,7 +22052,7 @@ \begin{itemdescr} \pnum \result -A constant expression\iref{expr.const} of type \tcode{bool}. +A constant expression\iref{expr.const.const} of type \tcode{bool}. \pnum \returns @@ -22072,7 +22072,7 @@ \begin{itemdescr} \pnum \result -A constant expression\iref{expr.const} of type \tcode{bool}. +A constant expression\iref{expr.const.const} of type \tcode{bool}. \pnum \returns diff --git a/source/declarations.tex b/source/declarations.tex index ee13005979..0fbdda48b3 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} @@ -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. @@ -1274,7 +1274,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. @@ -1541,7 +1541,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$)}$. @@ -1755,7 +1755,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. @@ -3470,7 +3470,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; @@ -4381,7 +4381,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 @@ -5412,7 +5412,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 +7092,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. @@ -7969,7 +7969,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 +7979,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. diff --git a/source/exceptions.tex b/source/exceptions.tex index bdff147766..29d4357749 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -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 diff --git a/source/exec.tex b/source/exec.tex index d5e90772a1..04c9e1b5d0 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -2226,7 +2226,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 diff --git a/source/expressions.tex b/source/expressions.tex index 888f8c0627..36176de723 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -2034,7 +2034,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$)}$. @@ -5719,7 +5719,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} @@ -5738,7 +5738,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} @@ -5772,7 +5772,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|)} @@ -5916,7 +5916,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}, @@ -6097,7 +6097,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 diff --git a/source/intro.tex b/source/intro.tex index 5179e1e580..b04be9ab9d 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} @@ -525,7 +525,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 +670,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 +782,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 +805,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} diff --git a/source/iterators.tex b/source/iterators.tex index 7a8c8b6ff7..9e972f19ae 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -1752,7 +1752,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 +6591,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/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/meta.tex b/source/meta.tex index 608ec79972..0be41407e1 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -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. @@ -3352,7 +3352,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 @@ -4085,7 +4085,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. @@ -5986,7 +5986,7 @@ \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 +some 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}, @@ -6679,7 +6679,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 +6690,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 aeeb757edf..4db5625672 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -921,7 +921,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}. diff --git a/source/numerics.tex b/source/numerics.tex index 6985c1f5b3..c8e28ff9ae 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -20145,7 +20145,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} diff --git a/source/preprocessor.tex b/source/preprocessor.tex index f4cfe56686..f8bd97288f 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -574,7 +574,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 diff --git a/source/ranges.tex b/source/ranges.tex index efc1087f4a..58f2ef0c01 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} diff --git a/source/statements.tex b/source/statements.tex index 2b3d55ac32..9163c1916a 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -320,7 +320,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 +405,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 +461,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 +584,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}; @@ -902,7 +902,7 @@ \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}. +is not a constant expression\iref{expr.const.const}. \end{note} \item diff --git a/source/support.tex b/source/support.tex index 5f028cddc2..6d83f3e90c 100644 --- a/source/support.tex +++ b/source/support.tex @@ -5665,7 +5665,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, diff --git a/source/templates.tex b/source/templates.tex index 6ed2dfd3e5..d9f95f8ae0 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -1320,7 +1320,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 +1349,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} @@ -5130,7 +5130,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 +5361,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. @@ -5953,7 +5953,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 +6022,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. @@ -6593,7 +6593,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} @@ -6803,7 +6803,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. diff --git a/source/text.tex b/source/text.tex index bbd53b9f2c..df0dc1baea 100644 --- a/source/text.tex +++ b/source/text.tex @@ -6700,7 +6700,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} @@ -7109,7 +7109,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} @@ -7608,7 +7608,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}% @@ -7635,7 +7635,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} @@ -7914,7 +7914,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} diff --git a/source/utilities.tex b/source/utilities.tex index 9ec1772423..7a2380591a 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -16067,7 +16067,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}% From 153012fa2e6beb03505d48e1649507a84d6c7ef7 Mon Sep 17 00:00:00 2001 From: Matthias Wippich Date: Thu, 26 Mar 2026 21:33:08 +0000 Subject: [PATCH 092/258] [expr.const.defns] Fix comment alignment (#8814) --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index 36176de723..2be0acf7b3 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -9442,7 +9442,7 @@ 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] + char arr[n] = {}; // \tcode{char[13]} return m + sizeof(arr); } int p = f(); // \tcode{m} is 13; initialized to 26 From 13906dcab8cfb87f880ea444336cbcc37165cd67 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:14:32 +0000 Subject: [PATCH 093/258] [basic.lookup.unqual] Rephrase to avoid incorrect use of term --- source/basic.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index f0107f05f7..83759b8d23 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -2065,7 +2065,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$. From 469571690f762c2775540c9cda0aa55817db5434 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 4 Jan 2026 16:15:47 +0800 Subject: [PATCH 094/258] [time.syn] Use `\placeholder` instead of `\term` "Signed integer type of at least N bits" are not terms defined in [time.syn], so perhaps we should use `\placeholder` instead. --- source/time.tex | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/time.tex b/source/time.tex index cdd91bb116..fa46de5bfb 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 From 7fdc20bfe74ede180b85c8dbdfed7b83b6e34042 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Thu, 26 Mar 2026 22:00:23 +0000 Subject: [PATCH 095/258] [class.qual] Formatting placeholder consistently as maths (#8610) --- source/basic.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 83759b8d23..b9f9c7eb7c 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -2558,13 +2558,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}. From ad94af979e8dfac9ca9af4aa22c66beec7935cfd Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 25 Mar 2026 21:05:15 +0800 Subject: [PATCH 096/258] [iostream.forward.overview] Add missing mentions of spanbuf and spanstreams A follows up to P0448R4. --- source/iostreams.tex | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index 03e07d529a..67a0ae72ee 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} From 6a31f94c5ef15fdb592c558cd63b2bd02bd18c8a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 25 Mar 2026 21:05:37 +0800 Subject: [PATCH 097/258] [iostream.forward.overview] Say "designate specialization". This replaces the imprecise and informal phrase "define instances of class templates". --- source/iostreams.tex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index 67a0ae72ee..2ec4c6445e 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -408,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} From 731cda191b915555c6816912361e431c82e7e2f6 Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Tue, 4 Nov 2025 05:17:01 -1000 Subject: [PATCH 098/258] [simd.permute.*] Change M back to V since the wording refers to V This was changed editorially by b6e501026e14600fed911183336266c0ebdf5728 as part of "2025-06 LWG Motion 13: P3691R1 Reconsider naming of the namespace for std::simd", but turned out not to be a helpful change, because it makes other wording more complex. Fixes NB US 180-295 (C++26 CD). --- source/numerics.tex | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/source/numerics.tex b/source/numerics.tex index c8e28ff9ae..b82cc52b62 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16968,33 +16968,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, + template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector, const typename M::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 @@ -19102,8 +19102,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} @@ -19161,8 +19161,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} @@ -19183,8 +19183,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} @@ -19216,8 +19216,8 @@ 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, +template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector, const typename M::value_type& fill_value); \end{itemdecl} @@ -19245,8 +19245,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} From 7f3b7c64a18610948bfc5479a90764f4992731bd Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Sun, 14 Dec 2025 22:00:24 +0000 Subject: [PATCH 099/258] [intro.races] Fix typo --- source/basic.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index b9f9c7eb7c..36ca7eeac8 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -6806,7 +6806,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} From e1ee86a3c373c53db7b5d6289457eed620862c76 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Fri, 27 Mar 2026 13:17:33 +0100 Subject: [PATCH 100/258] [simd.syn,simd.permute.mask] Change M::value_type& to V::value_type& --- source/numerics.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/numerics.tex b/source/numerics.tex index b82cc52b62..31a2e217d6 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16987,7 +16987,7 @@ const typename V::value_type& fill_value); template<@\exposconcept{simd-mask-type}@ V> constexpr V compress(const V& v, const type_identity_t& selector, - const typename M::value_type& fill_value); + 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, @@ -19218,7 +19218,7 @@ const typename V::value_type& fill_value); template<@\exposconcept{simd-mask-type}@ V> constexpr V compress(const V& v, const type_identity_t& selector, - const typename M::value_type& fill_value); + const typename V::value_type& fill_value); \end{itemdecl} \begin{itemdescr} From 8cef46b15b21d4ab1b96dce04c0d37e511d1ddc2 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Mon, 6 Oct 2025 00:24:35 +0200 Subject: [PATCH 101/258] [exec.snd.expos] Reorder specification immediately after declaration Fixes NB US 213-353 (C++26 CD). --- source/exec.tex | 182 +++++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 79 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 04c9e1b5d0..5a16e37bd9 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -1738,20 +1738,6 @@ 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 +1765,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 +1817,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 +1856,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 +1890,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 +1995,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 From 6fc165022194a0dd3b78287b087e7872c6c88f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Fri, 27 Mar 2026 11:58:32 +0000 Subject: [PATCH 102/258] [exec.get.compl.sched] Rename completion-tag to completion-fn-tag and reorder text. The renaming avoids a clash with the concept "completion-tag" defined in [exec.snd.expos]. The reordering makes it so that names are defined before they are referenced. --- source/exec.tex | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 5a16e37bd9..8f6f76629c 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -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}} From 525141d453d209f40f0acd5e829a0af0162e25be Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 28 Mar 2026 08:21:59 +0100 Subject: [PATCH 103/258] [saferecl.rcu.domain.func] Fix indentation --- source/threads.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/threads.tex b/source/threads.tex index 545aecdb63..3ee6804cb1 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -13216,7 +13216,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} From bb04052a5b5f1bb170437541cbdd5d0c3ffe4cfc Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 28 Mar 2026 08:35:38 +0100 Subject: [PATCH 104/258] [execution.syn] Fix comment alignment --- source/exec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exec.tex b/source/exec.tex index 8f6f76629c..64e51d380f 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@; From 1ac538fe492bd1536636313a23d10904336449cf Mon Sep 17 00:00:00 2001 From: timsong-cpp Date: Mon, 23 Feb 2026 08:22:05 -0600 Subject: [PATCH 105/258] [meta.reflection.queries] Use math font consistently --- source/meta.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/meta.tex b/source/meta.tex index 0be41407e1..c76fa23ee5 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -4348,7 +4348,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} From 792d4203d340ad6cf490cb0b52d3aa82f69e86c9 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sun, 8 Feb 2026 19:53:25 +0100 Subject: [PATCH 106/258] [forward] Add \tcode for literals --- source/utilities.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/utilities.tex b/source/utilities.tex index 7a2380591a..09be66f705 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} From deb2a9b40a46062dd76a1bbc968ff5039cb02aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Sat, 28 Mar 2026 08:56:40 +0000 Subject: [PATCH 107/258] [exec.snd.expos] Delete unused expos-only concept "completion-tag". Also insert a missing \pnum before the now-split codeblock (see 8cef46b15b21d4ab1b96dce04c0d37e511d1ddc2). --- source/exec.tex | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 64e51d380f..4455a1c991 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -1736,12 +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}@; - template // \expos using @\exposid{state-type}@ = decay_t<@\exposid{call-result-t}@< decltype(@\exposid{impls-for}@>::@\exposid{get-state}@), Sndr, Rcvr&>>; From fda5e3771f85dfea6d7bd8ade0577e82886addc0 Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Fri, 20 Mar 2026 02:36:07 -0700 Subject: [PATCH 108/258] [dcl.struct.bind] Fix tuple-like binding index to use SB_i instead of v_i P1061R10 introduced the SB_i notation for post-expansion structured bindings but this sentence was not updated. The rest of the section (p6, p8, and the end of this same paragraph) already uses SB_i. --- source/declarations.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/declarations.tex b/source/declarations.tex index 0fbdda48b3..42027658b5 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -7724,7 +7724,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 From 42f878f50d1356866b5aebe520a3138f707919a0 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Mon, 15 Dec 2025 00:01:35 +0000 Subject: [PATCH 109/258] [basic] Do not hyphenate "potentially evaluated" --- source/basic.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 36ca7eeac8..e9ce2c1e8e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -492,7 +492,7 @@ \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} @@ -552,10 +552,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 +563,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 @@ -4744,7 +4744,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 From 70e753882b290ea432e516b75fd924bc687076be Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Mon, 15 Dec 2025 00:03:46 +0000 Subject: [PATCH 110/258] [expr] Do not hyphenate "potentially evaluated" --- source/expressions.tex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 2be0acf7b3..10fffe4f88 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -4045,7 +4045,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}, @@ -5449,7 +5449,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 @@ -5981,7 +5981,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 @@ -6005,7 +6005,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} @@ -9128,7 +9128,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 @@ -9140,7 +9140,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} @@ -9465,7 +9465,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}, From d296b82c70dcf49a7a10a100778ecd6aed4c92c7 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Mon, 15 Dec 2025 00:04:54 +0000 Subject: [PATCH 111/258] [dcl] Do not hyphenate "potentially evaluated" --- source/declarations.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/declarations.tex b/source/declarations.tex index 42027658b5..eac2152fbf 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -4476,7 +4476,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} @@ -7144,7 +7144,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. @@ -10081,7 +10081,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. From 9ad63b74fae211473235c8fa087d19d392c04728 Mon Sep 17 00:00:00 2001 From: lprv <100177227+lprv@users.noreply.github.com> Date: Mon, 15 Dec 2025 00:05:31 +0000 Subject: [PATCH 112/258] [temp.over.link] Do not hyphenate "potentially evaluated" --- source/templates.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index d9f95f8ae0..467b190a19 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -4288,7 +4288,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. From 4f9d95253bca473369121e31f2a78014c6925442 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sun, 29 Mar 2026 08:36:23 +0200 Subject: [PATCH 113/258] [includes] Fix indentation --- source/algorithms.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 20e520ab63..baf3e4f25f 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -10340,7 +10340,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} From b536020b68adeac1e4e98cf8932a84db57d6ebb4 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sun, 29 Mar 2026 08:49:30 +0200 Subject: [PATCH 114/258] [coroutine.handle.general,coroutine.handle.noop.general] Place left curly bracket at end --- source/support.tex | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/source/support.tex b/source/support.tex index 6d83f3e90c..203a1bf45f 100644 --- a/source/support.tex +++ b/source/support.tex @@ -5794,8 +5794,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; @@ -5819,8 +5818,7 @@ }; template - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.con}, construct/reset constexpr coroutine_handle() noexcept; constexpr coroutine_handle(nullptr_t) noexcept; @@ -6132,8 +6130,7 @@ \begin{codeblock} namespace std { template<> - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.noop.conv}, conversion constexpr operator coroutine_handle<>() const noexcept; From 4d1fbb7ada2ca967586852176c4ee4472f497d8c Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Wed, 1 Apr 2026 09:16:57 +0200 Subject: [PATCH 115/258] [stacktrace.basic.nonmem] Fix indentation (#8900) --- source/diagnostics.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/diagnostics.tex b/source/diagnostics.tex index be2b863f7d..47be572caa 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -2289,8 +2289,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 +2319,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} From fb842529d536f6a2b3f9aa94423b092d8db20038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Wed, 1 Apr 2026 21:54:47 +0100 Subject: [PATCH 116/258] [macros] Add escapechar setting for "outputblock" environment. --- source/macros.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/macros.tex b/source/macros.tex index f47b65301b..397ea0f2d1 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -611,7 +611,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. From 180830c280023ea63165547b937da8265b6bd667 Mon Sep 17 00:00:00 2001 From: "S. B. Tam" Date: Fri, 3 Apr 2026 21:10:21 +0800 Subject: [PATCH 117/258] [mdspan.mdspan.cons] Fix typo (`is_nothrow_constructible` => `is_nothrow_constructible_v`) --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 4aba72d02d..89f3bca5fe 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -25124,7 +25124,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 From 6837212a31a7b3ead0bc9f3c6985e7127b778797 Mon Sep 17 00:00:00 2001 From: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> Date: Sat, 4 Apr 2026 12:06:05 +0200 Subject: [PATCH 118/258] [atomics.types.operations] Fix indentation (#8916) --- source/threads.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index 3ee6804cb1..bfd7367295 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -4747,19 +4747,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} From 5c8fc4311ab8ec82f789e9eadf4cf39f47beabf9 Mon Sep 17 00:00:00 2001 From: Jan Schultke Date: Wed, 8 Apr 2026 09:59:59 +0200 Subject: [PATCH 119/258] [conv.rank] Add missing whitespace following \IsoC --- source/basic.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index e9ce2c1e8e..de215a04d4 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -6252,7 +6252,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} From 68767eaadec53b0b4c8c6a6238c251667e0fe76f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 13:43:21 -0700 Subject: [PATCH 120/258] CWG2609 Padding in class types --- source/expressions.tex | 2 ++ source/intro.tex | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 10fffe4f88..274ccd467b 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -5675,6 +5675,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. diff --git a/source/intro.tex b/source/intro.tex index b04be9ab9d..3e24d06dce 100644 --- a/source/intro.tex +++ b/source/intro.tex @@ -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 @@ -920,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 From 5d6e9c84ce6d80b7e82c169a643fdaa65db42567 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 14:09:47 -0700 Subject: [PATCH 121/258] CWG2744 Multiple objects of the same type at the same address --- source/basic.tex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index de215a04d4..44dee484d2 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3640,7 +3640,13 @@ 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} From adcdd790be87d7563404e66718d8957cb35731d4 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 15:22:18 -0700 Subject: [PATCH 122/258] CWG2765 Address comparisons between potentially non-unique objects during constant evaluation --- source/basic.tex | 22 ++++++++++++++++++++++ source/expressions.tex | 41 +++++++++++++++++++++++++++++++++++++++++ source/utilities.tex | 11 ++--------- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 44dee484d2..d87fc3eabe 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -5985,6 +5985,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}% diff --git a/source/expressions.tex b/source/expressions.tex index 274ccd467b..89c77b0468 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -8329,6 +8329,19 @@ \rSec2[expr.const.core]{Core constant expressions} +\pnum +\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 +has a base class or a non-static member whose +type has constexpr-unknown representation. +\end{itemize} + \pnum An expression $E$ is a \defnadj{core constant}{expression} unless the evaluation of $E$, following the rules of the abstract @@ -8556,6 +8569,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 diff --git a/source/utilities.tex b/source/utilities.tex index 09be66f705..04e397bb6c 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -15943,15 +15943,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 From 5d65e7f8cd2cd93d00b5b3918be800a19a2f815d Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 15:24:16 -0700 Subject: [PATCH 123/258] CWG2799 Inheriting default constructors --- source/overloading.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/overloading.tex b/source/overloading.tex index fe6c4d0852..f6910d355b 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. From c2f1ab887cdf99b2a8f8eb9c2e2d5acc5d225b91 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 16:01:47 -0700 Subject: [PATCH 124/258] CWG2947 Limiting macro expansion in pp-module --- source/preprocessor.tex | 80 ++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index f8bd97288f..9a2d9537f2 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -1224,7 +1224,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 +1233,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 +1250,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 +1262,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}% From 7e8fea5253e4f761ca10f503da217d872d90ff2f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 16:12:50 -0700 Subject: [PATCH 125/258] CWG2966 Alignment and value representation of std::nullptr_t --- source/basic.tex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index d87fc3eabe..50fb486f7a 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -5666,7 +5666,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}. From c3fbb89a9b3c2d385c83f7cd0ab8731cecb54428 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 16:16:33 -0700 Subject: [PATCH 126/258] CWG2976 Transferring control out of a function --- source/statements.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/statements.tex b/source/statements.tex index 9163c1916a..07760a4ed4 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -1300,7 +1300,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. From 2821d9c7f8b9535b53b15eca6bca913676971122 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 16:53:58 -0700 Subject: [PATCH 127/258] CWG2983 Non-type template parameters are not variables --- source/basic.tex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 50fb486f7a..4efa1f3876 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -115,13 +115,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 From 660f75c9e8c94800d62bbe3496d76e7c02c09ef1 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 18:42:09 -0700 Subject: [PATCH 128/258] CWG2992 Labels do not have names --- source/basic.tex | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 4efa1f3876..e6a3b80d74 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 From c706a4ed4929291c60657141ae9a2b7c3aca75d1 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 19:01:46 -0700 Subject: [PATCH 129/258] CWG3010 constexpr placement-new should require transparent replaceability --- source/expressions.tex | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 89c77b0468..7efeffd09c 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -8520,10 +8520,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$; From ff3d471bb14e28a232cc05c0919343dcedd1b141 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 19:09:09 -0700 Subject: [PATCH 130/258] CWG3029 Confusing note about ordinary character types for aligned memory areas --- source/basic.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index e6a3b80d74..02dfa58a78 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3851,8 +3851,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 From e35e7c21ba605a52254e83739d982a838e302fd9 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 19:27:26 -0700 Subject: [PATCH 131/258] CWG3035 Lambda expressions in anonymous unions --- source/classes.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/classes.tex b/source/classes.tex index 058a317666..18afda563d 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -3272,7 +3272,9 @@ 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. From 13209c788f84ef3322d6f36a99fac2c5f98c1e7e Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sat, 4 Apr 2026 20:28:57 -0700 Subject: [PATCH 132/258] CWG3058 "Program point" is not defined Fixes NB US 14-029 (C++26 CD). --- source/basic.tex | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/basic.tex b/source/basic.tex index 02dfa58a78..cb6c35816c 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -1678,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$. From 6181aa62b02db946f227e1f48b766da598236b0b Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 01:21:53 -0700 Subject: [PATCH 133/258] CWG3125 Token convertibility requirement in #if --- source/preprocessor.tex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 9a2d9537f2..afcc57b78e 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} From 3dfbe43b587d28d02b482e852cf85ecd7930642c Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 01:28:12 -0700 Subject: [PATCH 134/258] CWG3126 A module import needs a header-name as a token --- source/lex.tex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/lex.tex b/source/lex.tex index 7547b4aa69..ef2687ddf1 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -585,6 +585,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 +873,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|)} From 4a2eed286208f5dc9e7504aea465b4d1af79ab77 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 02:07:17 -0700 Subject: [PATCH 135/258] CWG3128 Potentially-throwing unevaluated operands --- source/exceptions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exceptions.tex b/source/exceptions.tex index 29d4357749..377a0a8237 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -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 From 7f818adf3309fe39bf1e25fd993100a0bae1261f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 02:14:50 -0700 Subject: [PATCH 136/258] CWG3129 Clarify which floating-point-literals are valid --- source/lex.tex | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/lex.tex b/source/lex.tex index ef2687ddf1..9b607ab2ed 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -1784,6 +1784,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} From 931cad9d1575157b7262c8f3ecb6ddc4462458fa Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 02:36:28 -0700 Subject: [PATCH 137/258] CWG3130 Naming function members of anonymous unions --- source/classes.tex | 21 ++++++++++++++++----- source/expressions.tex | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index 18afda563d..376cbbe779 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -1274,7 +1274,7 @@ (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}, +\tcode{X} and \tcode{X} 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 @@ -1503,7 +1503,8 @@ \end{example} \pnum -If the class definition does not explicitly declare a copy constructor, +If the class definition does not explicitly declare a 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 @@ -1547,6 +1548,9 @@ a 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, @@ -1742,7 +1746,8 @@ \end{note} \pnum -If the class definition does not explicitly declare a copy assignment operator, +If the class definition does not explicitly declare a 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 constructor or move assignment operator, the implicitly declared copy @@ -1796,6 +1801,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 +2038,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 +2052,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 @@ -3266,6 +3276,7 @@ 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} diff --git a/source/expressions.tex b/source/expressions.tex index 7efeffd09c..e753404960 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -1436,7 +1436,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, From 29022b75083f2d5c274d4f256fb07caa4adb1061 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 02:45:44 -0700 Subject: [PATCH 138/258] CWG3132 Unclear disambiguation rule for condition --- source/statements.tex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/statements.tex b/source/statements.tex index 07760a4ed4..d0d338e930 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,7 +148,7 @@ \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 From d339a26a38cf5165e4ed5fa5c0a25ce157497349 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 02:53:43 -0700 Subject: [PATCH 139/258] CWG3133 Cv-qualified types in built-in operator candidates --- source/overloading.tex | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/overloading.tex b/source/overloading.tex index f6910d355b..0bde4a3a04 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -3899,7 +3899,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}@); @@ -3921,14 +3921,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} @@ -4005,8 +4005,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}@); @@ -4056,7 +4057,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 @@ -4080,7 +4081,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}@); From 870aab726b73f94aa22df1f4f7779cf7668a2c8f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 16:56:48 -0700 Subject: [PATCH 140/258] CWG3136 Constant expressions of type void --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index e753404960..4fe0fb52eb 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -8849,7 +8849,7 @@ \end{itemize} or \item -a prvalue core constant expression whose result object\iref{basic.lval} +a prvalue core constant expression whose result object\iref{basic.lval} (if any) satisfies the following constraints: \begin{itemize} \item From 20e988a730acccc04319dbc1520d9601585ab439 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 17:02:26 -0700 Subject: [PATCH 141/258] CWG3142 Possible expansions of __LINE__ changing over time --- source/preprocessor.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index afcc57b78e..13c2bdfb28 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -2280,7 +2280,9 @@ \item \indextext{__line__@\mname{LINE}}% \mname{LINE}\\ -An integer literal representing the presumed line number of +\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}. From c25b52ebbc4c1f788acc85b8e827cb61afa336ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Sun, 12 Apr 2026 00:24:39 +0100 Subject: [PATCH 142/258] [cpp.predefined] Insert "The integer literal" as introducer. This avoids starting a sentence with a symbol, and it is also consistent with other nearby descriptions. --- source/preprocessor.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 13c2bdfb28..03385c5022 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -2280,7 +2280,7 @@ \item \indextext{__line__@\mname{LINE}}% \mname{LINE}\\ -\tcode{0} or a decimal integer literal\iref{lex.icon}, +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. From 30b9804cc7d120fff2677ed5e2ff2fa14e87b8f7 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 21:41:59 -0700 Subject: [PATCH 143/258] CWG3148 Definition of "user-declared" special member function Editorial note: * In new wording from previous CWG3130, which added a new reference to "X" in [class.default.ctor], change "X" to "the class", since the change from CWG3148 removes the name "X". --- source/classes.tex | 30 +++++++++++++++++++++++------- source/declarations.tex | 16 ++++++++-------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index 376cbbe779..5045e9b65a 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 @@ -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} and \tcode{X} is not an anonymous union, +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 @@ -1503,7 +1508,7 @@ \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 @@ -1544,8 +1549,8 @@ \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 @@ -1605,6 +1610,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}% @@ -1746,10 +1762,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}. diff --git a/source/declarations.tex b/source/declarations.tex index eac2152fbf..64e28e5217 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -8803,14 +8803,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}. From 383e447e08e527981259472ca2c9d54d64203fd8 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 21:44:57 -0700 Subject: [PATCH 144/258] CWG3151 Closure types that are final --- source/expressions.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index 4fe0fb52eb..1f5af19f3d 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -2238,7 +2238,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 From e3b6062225d72ffa828140c59b99e59b75c10f80 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 21:54:18 -0700 Subject: [PATCH 145/258] CWG3153 Immediate-escalating defaulted comparison --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index 1f5af19f3d..eb406086c7 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -9206,7 +9206,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 From a0b9b3b67b87ddad4fed9a89701bd7504b3d4f6b Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 22:02:32 -0700 Subject: [PATCH 146/258] CWG3155 Escalation of virtual functions --- source/classes.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index 5045e9b65a..5a0c0ee597 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -4128,11 +4128,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}% From 8c7d950a812bcaa5d7ce4cdc8091b2f11982ce3a Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 22:05:16 -0700 Subject: [PATCH 147/258] CWG3156 Handling of deleted functions in unevaluated lambda-captures --- source/expressions.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index eb406086c7..4917eca901 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -3093,12 +3093,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. From 9959c52d12865f31e5b7cbf9afdc3c19982cfb80 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 22:11:41 -0700 Subject: [PATCH 148/258] CWG3157 Missing handling of operator new[] for deallocation function template matching --- source/templates.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/templates.tex b/source/templates.tex index 467b190a19..a6398e1da8 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -4404,10 +4404,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 @@ -9639,12 +9639,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 From 9b822e32e7d1ba9cb074b8cec8b55edbaede59a4 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 22:19:45 -0700 Subject: [PATCH 149/258] CWG3171 Codify the strong ownership for modules Fixes NB US 17-030, FR 003-031 (C++26 CD). --- source/basic.tex | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index cb6c35816c..1f70a842ae 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3079,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 @@ -3098,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 @@ -3112,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, From 30d255bd0aec5da27acbaaf1b3efffb07d8527fb Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 22:33:46 -0700 Subject: [PATCH 150/258] CWG3173 Remove misleading footnote about as-if rule --- source/basic.tex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 1f70a842ae..adb52f3b89 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3675,12 +3675,6 @@ \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'; From 9c53a5a637ae0874be8316ef18caa414fb3fbfbb Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 00:40:27 -0700 Subject: [PATCH 151/258] CWG3088 Clarify macro treatment of identifiers with special meaning Fixes NB US 57-105 (C++26 CD). --- source/compatibility.tex | 17 +++++++++++++++++ source/declarations.tex | 7 +++++++ source/lex.tex | 11 +++++++++++ source/preprocessor.tex | 2 +- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/source/compatibility.tex b/source/compatibility.tex index edbd9196d1..13c6ae3f9e 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} diff --git a/source/declarations.tex b/source/declarations.tex index 64e28e5217..aa964d0fbb 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -9512,6 +9512,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}. diff --git a/source/lex.tex b/source/lex.tex index 9b607ab2ed..4356188c99 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -982,6 +982,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}% @@ -1120,6 +1126,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 diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 03385c5022..0a516f3d5a 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -1580,7 +1580,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 From ad0e6e0133016ab98c7a2c7c2cbe97612e0461ca Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 00:45:21 -0700 Subject: [PATCH 152/258] CWG3119 for-range-declaration of an expansion-statement as a templated entity Fixes NB AT 2-089 (C++26 CD). --- source/templates.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index a6398e1da8..94a12abd1c 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, From 4f4467c14e2be3fc55450cfdcec042b38c498a1a Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 00:50:48 -0700 Subject: [PATCH 153/258] CWG3122 Inadequate value-dependence for reflect-expressions --- source/templates.tex | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/templates.tex b/source/templates.tex index 94a12abd1c..a75350f2f6 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -6032,12 +6032,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 From 56890e49a64c2ef960c9638261f7ed49a2b9293c Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 00:54:05 -0700 Subject: [PATCH 154/258] CWG3123 Global lookup for begin and end for expansion statements --- source/statements.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/statements.tex b/source/statements.tex index d0d338e930..4279ec4983 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -827,7 +827,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 From 665d4116cf095f37eb74089fd84d54e3e1faea38 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 01:20:06 -0700 Subject: [PATCH 155/258] CWG3124 Disallow annotations on block-scope externs and non-unique friend declarations [dcl.attr.annotation]p1 Replaced /function-declarator/ with function declarator as no such grammarterm exists. --- source/declarations.tex | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/declarations.tex b/source/declarations.tex index aa964d0fbb..a92be28e6c 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -10228,14 +10228,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 From da5f0eb4dc81b97277de2da6f9fb23666b6d1ac8 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 01:45:50 -0700 Subject: [PATCH 156/258] CWG3131 Value categories and types for the range in iterable expansion statements --- source/statements.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/statements.tex b/source/statements.tex index 4279ec4983..ce4299928f 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -874,7 +874,7 @@ \begin{codeblock} { @\grammarterm{init-statement}@ - constexpr auto&& @\exposidnc{range}@ = @\grammarterm{expansion-initializer}@; + constexpr decltype(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} From 8663ecdbb4d5061397855192267ca29c4cb99415 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 03:00:17 -0700 Subject: [PATCH 157/258] CWG3135 constexpr structured bindings with prvalues from tuples --- source/declarations.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/declarations.tex b/source/declarations.tex index a92be28e6c..b8f2816dfd 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -7741,10 +7741,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} From 0d2ab00dfd2b13d7461f01e695b7c1f20021478e Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 03:27:17 -0700 Subject: [PATCH 158/258] CWG3140 Allowing expansion over non-constant std::array --- source/basic.tex | 2 +- source/statements.tex | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index adb52f3b89..ff2b6a64d8 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -4977,7 +4977,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 diff --git a/source/statements.tex b/source/statements.tex index ce4299928f..047acc3bf4 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -874,10 +874,8 @@ \begin{codeblock} { @\grammarterm{init-statement}@ - constexpr decltype(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}$@ @@ -885,30 +883,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.const}. -\end{note} \item Otherwise, $S$ is a destructuring expansion statement and, From 3d104f6e48476bd133a48c066860f1e83c691636 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 04:08:37 -0700 Subject: [PATCH 159/258] CWG3143 Incorrect statement about enumerators for C23 --- source/compatibility.tex | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/source/compatibility.tex b/source/compatibility.tex index 13c6ae3f9e..51d2c511f8 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -3464,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} @@ -3483,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 From d650d7c705ada643abfc79ed4ac163bd07254198 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 04:18:26 -0700 Subject: [PATCH 160/258] CWG3145 Uniqueness of annotations --- source/declarations.tex | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/source/declarations.tex b/source/declarations.tex index b8f2816dfd..78cba162c3 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -10256,11 +10256,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(); @@ -10274,6 +10271,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); From 910a44014cd15049c737fb11627a60dc55508e98 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 04:27:48 -0700 Subject: [PATCH 161/258] CWG3149 Rvalues in destructuring expansion statements --- source/statements.tex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/statements.tex b/source/statements.tex index 047acc3bf4..070e12d536 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -935,10 +935,13 @@ 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} +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 declaration of $u_{0}, u_{1}, \dotsc, u_{N-1}$ if and only if \keyword{constexpr} is one of the \grammarterm{decl-specifier}s From 18d2f84bae24f177ac19487153b2e8c0a718ba60 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 16:19:08 -0700 Subject: [PATCH 162/258] CWG3162 Evaluation context of manifestly constant-evaluated expressions Also fixes CWG3127. --- source/expressions.tex | 106 +++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 26 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 4917eca901..90c438e6d6 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -9419,39 +9419,93 @@ \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 -Each synthesized point corresponding to an injected declaration produced by -any evaluation sequenced before $X$\iref{intro.execution}. +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 +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} From 56ae33f1389ba05c280d38728983d5780c692bd2 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 16:21:39 -0700 Subject: [PATCH 163/258] CWG3172 Reference to wrong placeholder --- source/templates.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index a75350f2f6..46aed8040d 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -2194,7 +2194,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} From 88d3892006e54d6219cab08a7167eed3c2411b8d Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sat, 28 Mar 2026 13:09:32 +0000 Subject: [PATCH 164/258] P3924R1 Fix inappropriate font choices for "declaration" Fixes NB US 11-400 (C++26 CD). --- source/basic.tex | 4 ++-- source/declarations.tex | 23 +++++++++++++---------- source/statements.tex | 3 +-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index ff2b6a64d8..bd79b3cfb9 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -292,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. @@ -1017,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 diff --git a/source/declarations.tex b/source/declarations.tex index 78cba162c3..d884d3337d 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -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} @@ -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. @@ -2409,8 +2410,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, @@ -2945,7 +2948,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}. diff --git a/source/statements.tex b/source/statements.tex index 070e12d536..fa6944b172 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -267,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}% @@ -942,7 +941,7 @@ 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 declaration +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} From 6933956690523fe6414edaedf803ef7bb2feadb4 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 28 Mar 2026 18:28:28 +0100 Subject: [PATCH 165/258] P4136R2 #line is not in line with existing implementation Fixes NB FR-009-108 (C++ CD). --- source/preprocessor.tex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 0a516f3d5a..f3037b19ad 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -2147,9 +2147,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 From 3474aaa0ae7249c4a3c431e0a4627a498850a44c Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 28 Mar 2026 18:42:37 +0100 Subject: [PATCH 166/258] P4004R1 Reconsider CWG 1395 "Partial ordering of variadic templates reconsidered" --- source/templates.tex | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/source/templates.tex b/source/templates.tex index 46aed8040d..1a3ab7af08 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -8782,18 +8782,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. From 9d93c9c3c241f94d410c1e0d6482f53537709561 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Mon, 30 Mar 2026 21:23:11 +0200 Subject: [PATCH 167/258] P3865R3 Class template argument deduction (CTAD) for type template template --- source/declarations.tex | 14 +++++++++++--- source/overloading.tex | 34 ++++++++++++++++++++++++++++++++++ source/templates.tex | 4 +++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/source/declarations.tex b/source/declarations.tex index d884d3337d..2cf20c3632 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1445,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 @@ -1454,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}. diff --git a/source/overloading.tex b/source/overloading.tex index 0bde4a3a04..bd3ea8d0fe 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -1432,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}. +\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 @@ -1689,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|(} diff --git a/source/templates.tex b/source/templates.tex index 1a3ab7af08..87c4bb0434 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -5661,7 +5661,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 From 8b803440c351ab1c8d347058447deb3d1e8eb22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Sun, 12 Apr 2026 11:10:43 +0100 Subject: [PATCH 168/258] [over.match.class.deduct] Add introductory "The alias template". This avoids starting a sentence with a symbol. Sentences should start with normal English words. --- source/overloading.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/overloading.tex b/source/overloading.tex index bd3ea8d0fe..52883f84dd 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -1443,7 +1443,7 @@ 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}. -\tcode{A} is then used +The alias template \tcode{A} is then used instead of the original \grammarterm{template-name} to resolve the placeholder. From 1471e9804e02567a62b9b0acfb2cdb542ce861a2 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sun, 29 Mar 2026 22:37:25 +0200 Subject: [PATCH 169/258] P3598R0 CWG 3158 - `const`-ification of Splice Expressions --- source/expressions.tex | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 90c438e6d6..2193e4c6eb 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -3562,7 +3562,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 @@ -3612,10 +3612,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 +$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 From 002cd77adffb4c9b34ba262e2d84f6b2f15fbc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Sun, 12 Apr 2026 11:29:42 +0100 Subject: [PATCH 170/258] [expr.prim.splice] Add introductory words "The expression". This avoids starting a sentence with a symbol. Sentences should start with normal English words. --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index 2193e4c6eb..13f2e15671 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -3612,7 +3612,7 @@ 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. -$E$ is an lvalue referring to the object or function $X$ +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} From b621f1a42614806ce24070cfa3389bc716c04f09 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sun, 29 Mar 2026 22:58:15 +0200 Subject: [PATCH 171/258] P3726R2 Adjustments to Union Lifetime Rules Fixes NB DE 087, US 48-086 (C++26 CD). Editorial notes: * Missing "freestanding" comment added to the feature test macro line. * Removed "type" after "aggregate" (just "aggregate" is the right term). --- source/basic.tex | 52 +++++++++++++++++++++++++++++++++++++++-- source/classes.tex | 13 +---------- source/memory.tex | 27 +++++++++++++++++++++ source/preprocessor.tex | 2 +- source/support.tex | 1 + source/templates.tex | 4 +++- 6 files changed, 83 insertions(+), 16 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index bd79b3cfb9..f82ae47e77 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3694,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} @@ -3701,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} @@ -3709,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 diff --git a/source/classes.tex b/source/classes.tex index 5a0c0ee597..08134ae8b9 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -1337,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 diff --git a/source/memory.tex b/source/memory.tex index a7f16411e8..7bd8bde552 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 @@ -1036,6 +1038,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 diff --git a/source/preprocessor.tex b/source/preprocessor.tex index f3037b19ad..c2284a582c 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -2451,7 +2451,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 diff --git a/source/support.tex b/source/support.tex index 203a1bf45f..fdc8a05421 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} diff --git a/source/templates.tex b/source/templates.tex index 87c4bb0434..9effb38ee5 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -2574,7 +2574,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} From 06f1ff3a9488021e0330c4b10b7210195d507000 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sun, 29 Mar 2026 23:43:23 +0200 Subject: [PATCH 172/258] P4143R0 Constant evaluation when? Fixes NB US 33-065 (C++26 CD). --- source/expressions.tex | 14 ++++++++------ source/lex.tex | 15 +++++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 13f2e15671..9e150fda31 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -8316,8 +8316,7 @@ assuming that copy elision\iref{class.copy.elision} is not performed, are called constant expressions. \begin{note} -Constant expressions can be evaluated -during translation. +Certain constant expressions are evaluated during translation\iref{lex.phases}. \end{note} \pnum @@ -9070,12 +9069,13 @@ with all contract assertions using the ignore evaluation semantic\iref{basic.contract.eval}, \begin{note} -Within this evaluation, +In the course of this determination, \tcode{std::is_constant_evaluated()}\iref{meta.const.eval} -returns \keyword{true}. +has the value \keyword{true}. \end{note} \begin{note} -The initialization, when evaluated, +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 @@ -9529,6 +9529,8 @@ \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 @@ -9537,7 +9539,7 @@ has constant initialization\iref{basic.start.static}. \begin{footnote} Testing this condition -can involve a trial evaluation of its initializer, +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. diff --git a/source/lex.tex b/source/lex.tex index 4356188c99..ce8aa22ae6 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -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$. From 16e5b370e816cd20a7789124326a975a51fd953d Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sun, 29 Mar 2026 23:55:08 +0200 Subject: [PATCH 173/258] P4149R1 Define "immediate context" Fixes NB US 54-100 (C++26 CD). --- source/exceptions.tex | 9 ++- source/templates.tex | 135 ++++++++++++++++++++++++------------------ 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/source/exceptions.tex b/source/exceptions.tex index 377a0a8237..465c819730 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -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/templates.tex b/source/templates.tex index 9effb38ee5..9fe8e5e420 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -2680,31 +2680,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, @@ -6649,19 +6648,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 @@ -6681,10 +6667,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 @@ -6748,11 +6730,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 @@ -6883,7 +6860,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, @@ -6902,7 +6897,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())); @@ -6920,16 +6917,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} @@ -8053,20 +8050,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 From 1a438cab123cea3a498c9916a7fb4c443bb07649 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Mon, 30 Mar 2026 21:02:29 +0200 Subject: [PATCH 174/258] P3769R1 Clarification of placement new deallocation --- source/expressions.tex | 94 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 9e150fda31..ea8b1848a5 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -6368,23 +6368,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 { @@ -6398,7 +6420,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 From 529dff983f06162d6dcff374e46b8f99ded05e92 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Sun, 5 Apr 2026 22:52:05 -0700 Subject: [PATCH 175/258] CWG3141 Unique objects from define_static_array --- source/basic.tex | 3 +-- source/templates.tex | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index f82ae47e77..7aac6e400e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3646,8 +3646,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} diff --git a/source/templates.tex b/source/templates.tex index 9fe8e5e420..70c42afb2c 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -532,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 From 2ea7dbcaf1919d12f01fa084714e18d43b0cb859 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 16:32:47 -0700 Subject: [PATCH 176/258] LWG2414 Member function reentrancy should be implementation-defined --- source/lib-intro.tex | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/lib-intro.tex b/source/lib-intro.tex index abe4ecf3b7..7015762100 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -3787,6 +3787,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 From 5ea831b1c38b61a096edb9644bdda45e4c91fbd3 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 16:35:07 -0700 Subject: [PATCH 177/258] LWG2746 Inconsistency between requirements for emplace between optional and variant --- source/utilities.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/utilities.tex b/source/utilities.tex index 04e397bb6c..c8403cb178 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -3966,7 +3966,7 @@ \begin{itemdescr} \pnum -\mandates +\constraints \tcode{is_constructible_v} is \tcode{true}. \pnum From 0d37df0808df85a3ab93e08571700353304880bb Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 18:46:48 -0700 Subject: [PATCH 178/258] LWG3504 condition_variable::wait_for is overspecified --- source/threads.tex | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index bfd7367295..5ae112b97e 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -9490,6 +9490,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}% @@ -9836,7 +9846,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 @@ -9946,7 +9956,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 @@ -10220,7 +10230,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 @@ -10288,7 +10298,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} @@ -10407,8 +10417,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} From b58214bffb1480e15e43a44b4b3af70ffd9f099a Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 19:00:38 -0700 Subject: [PATCH 179/258] LWG3599 The const overload of lazy_split_view::begin should be constrained by const Pattern --- source/ranges.tex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/ranges.tex b/source/ranges.tex index 58f2ef0c01..18bed31c3c 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -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; From 612c845e6de14952c45d8f5ef602be1f34498de0 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 19:11:17 -0700 Subject: [PATCH 180/258] LWG4290 Missing Mandates clauses on is_sufficiently_aligned --- source/memory.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/memory.tex b/source/memory.tex index 7bd8bde552..a04dc38664 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -1021,6 +1021,10 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{Alignment} is a power of two. + \pnum \expects \tcode{p} points to From 346d3015ef12d00f3f2b1e3bfd5d9ec596ff4635 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 19:18:08 -0700 Subject: [PATCH 181/258] LWG4453 atomic_ref::required_alignment should be the same as for T Editorial note: * [atomics.ref.ops]p3 Added "," to match wording added in p1. --- source/threads.tex | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/threads.tex b/source/threads.tex index 5ae112b97e..e5a7d114c4 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -3237,6 +3237,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} @@ -3260,6 +3263,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}% From b9add076b449fa0896218ea431252949f86c581d Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 19:29:11 -0700 Subject: [PATCH 182/258] LWG4454 assert should forbid co_await and co_yield Fixes NB GB 05-129 (C++26 CD). --- source/diagnostics.tex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/diagnostics.tex b/source/diagnostics.tex index 47be572caa..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 From e1234bc0c3eb13928e6cf2c81b6b91d88d592536 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 19:55:56 -0700 Subject: [PATCH 183/258] LWG4469 Names of parameters of addressable function shall remain unspecified --- source/lib-intro.tex | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 7015762100..264b436bcc 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -3103,6 +3103,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} From 7a1869014524f0112be155fc716f15453de2bbe8 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 20:02:44 -0700 Subject: [PATCH 184/258] LWG4472 std::atomic_ref can be constructed from temporaries --- source/threads.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/threads.tex b/source/threads.tex index e5a7d114c4..1c86218983 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -3159,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; @@ -3662,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; @@ -3886,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; @@ -4180,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; From b4abee9551d38636d3fede227385e600d571c77f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 20:34:00 -0700 Subject: [PATCH 185/258] LWG4486 integral-constant-like and constexpr-wrapper-like exposition-only concept duplication Fixes NB US 151-242 (C++26 CD). --- source/containers.tex | 5 +---- source/lib-intro.tex | 13 ++++++++++--- source/numerics.tex | 7 ------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 89f3bca5fe..d16560cfd0 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -20392,10 +20392,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 diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 264b436bcc..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} diff --git a/source/numerics.tex b/source/numerics.tex index 31a2e217d6..b5a65c0c80 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16544,13 +16544,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 { From 6923184121f3c8becd24e34b9f320106e7910474 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 20:37:57 -0700 Subject: [PATCH 186/258] LWG4492 std::generate and std::ranges::generate wording is unclear for parallel algorithms --- source/algorithms.tex | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index baf3e4f25f..039136eaf6 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 @@ -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} From 2e5143b248a0f16114bfc2a342c42ad4eb97bd27 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 20:45:44 -0700 Subject: [PATCH 187/258] LWG4496 Precedes vs Reachable in [meta.reflection] --- source/meta.tex | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index c76fa23ee5..a6b3ef6c77 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -3815,7 +3815,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 +3901,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 +4030,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 @@ -4662,13 +4662,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 +5985,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.reflect} 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}, From 1c73ec45cd63b703af98413a95a464ca0c95a23f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 20:49:33 -0700 Subject: [PATCH 188/258] LWG4499 flat_set::insert_range specification may be problematic --- source/containers.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index d16560cfd0..6a9e9cf569 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -19494,8 +19494,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 +20182,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}, From cc66a29b79b34c60db081f3c4d02a86f5e417de9 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 20:52:18 -0700 Subject: [PATCH 189/258] LWG4510 Ambiguity of std::ranges::advance and std::ranges::next when the difference type is also a sentinel type --- source/iterators.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/source/iterators.tex b/source/iterators.tex index 9e972f19ae..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} From 4d1f957eac82a41310c850d7f50a657e7053cdae Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 21:02:08 -0700 Subject: [PATCH 190/258] LWG4511 Inconsistency between the deduction guide of std::mdspan taking (data_handle_type, mapping_type, accessor_type) and the corresponding constructor --- source/containers.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 6a9e9cf569..cbd0964204 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -25030,7 +25030,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; From 585e1252d09b342d36799a0252a5f3bd3b348f42 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 21:11:39 -0700 Subject: [PATCH 191/258] LWG4512 The system_encoded_string() and generic_system_encoded_string() member functions of std::filesystem::path are misnamed Fixes NB US 189-304 (C++26 CD). --- source/future.tex | 4 ++-- source/iostreams.tex | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) 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/iostreams.tex b/source/iostreams.tex index 2ec4c6445e..a430c8dc69 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -13717,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; @@ -13729,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; @@ -14051,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{} @@ -14704,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; @@ -14779,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; From 787562af7f316b80fedc5c7982b6c9c47a6da626 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 21:16:21 -0700 Subject: [PATCH 192/258] LWG4535 Disallow user specialization of templates Fixes NB US 176-280 (C++26 CD). --- source/numerics.tex | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/numerics.tex b/source/numerics.tex index b5a65c0c80..0555a77696 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16534,6 +16534,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} @@ -17484,10 +17489,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} From 97207d1de3bfa61785aaa244f547e73a4760f017 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 21:36:11 -0700 Subject: [PATCH 193/258] LWG4536 Type traits have inconsistent interactions with immediate functions --- source/meta.tex | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index a6b3ef6c77..ac26009293 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -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 From dc8496123fdd4c05e75ba02c35955e608aca8a5f Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 22:29:38 -0700 Subject: [PATCH 194/258] LWG3831 Two-digit formatting of negative year is ambiguous Editorial note: * [tab:time.{format,parse}.spec],[tab:time.parse.spec] Examples changed to usual "codeblock with comments" style, since the "inline" style of the paper was rather awkward. --- source/time.tex | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source/time.tex b/source/time.tex index fa46de5bfb..179b201771 100644 --- a/source/time.tex +++ b/source/time.tex @@ -10788,11 +10788,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 +11471,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 +11485,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. From d1705f9fc2e0bff97ff8dd1ac753f6e75471a160 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 22:47:07 -0700 Subject: [PATCH 195/258] LWG4090 Underspecified use of locale facets for locale-dependent std::format --- source/text.tex | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/source/text.tex b/source/text.tex index df0dc1baea..2de7d40362 100644 --- a/source/text.tex +++ b/source/text.tex @@ -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. From d67ab97be4f97a54a58eb90ce48cf0d1bd065171 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 22:51:21 -0700 Subject: [PATCH 196/258] LWG4130 Preconditions for std::launder might be overly strict --- source/support.tex | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/support.tex b/source/support.tex index fdc8a05421..f269f5de8f 100644 --- a/source/support.tex +++ b/source/support.tex @@ -3144,9 +3144,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}. From f700f35bd80ee87a4c49146b75513775d94a35f9 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 22:56:55 -0700 Subject: [PATCH 197/258] LWG4259 P1148R0 changed the return values of searching functions of std::basic_string on some platforms Editorial note: * [string.find] Use braces in complex if statement. --- source/strings.tex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/strings.tex b/source/strings.tex index 3bc1e0268a..e46f3d1e85 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -4443,7 +4443,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 From ebffd32b4abe7a218a3fbcfa613e171509116bd3 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 22:58:57 -0700 Subject: [PATCH 198/258] LWG4324 unique_ptr::operator* is not SFINAE-friendly --- source/memory.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/memory.tex b/source/memory.tex index a04dc38664..eb7c889a51 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -2668,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}. From 2d3f1b4aa04cd2be1766c8682f5a58f4ed7fde38 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:06:10 -0700 Subject: [PATCH 199/258] LWG4378 Inconsistency between std::basic_string's data() and operator[] specification --- source/strings.tex | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/source/strings.tex b/source/strings.tex index e46f3d1e85..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}% From dbd9c63b6fbc840ec9e1bee7b1978065b106986e Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:12:48 -0700 Subject: [PATCH 200/258] LWG4457 freestanding for stable_sort, stable_partition and inplace_merge Fixes NB US 157-255 (C++26 CD). --- source/algorithms.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 039136eaf6..0c5d2b5cb6 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -2847,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 @@ -3251,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 From b4780d5279a8d2b93ba6a32ca17183d66e14ac96 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:18:46 -0700 Subject: [PATCH 201/258] LWG4460 Missing Throws: for last variant constructor --- source/utilities.tex | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/source/utilities.tex b/source/utilities.tex index c8403cb178..6362adcf09 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -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 From 0aed523bf018a3305dce4af8d7f08999ff8de689 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:20:23 -0700 Subject: [PATCH 202/258] LWG4467 hive::splice can throw bad_alloc --- source/containers.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index cbd0964204..83f3036ff1 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -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 From f2ceb549d87c9222b38020789bd0b18226f927f3 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:22:50 -0700 Subject: [PATCH 203/258] LWG4468 [const.wrap.class] "operator decltype(auto)" is ill-formed --- source/meta.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/meta.tex b/source/meta.tex index ac26009293..1c978df0e6 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -863,7 +863,7 @@ constexpr auto operator=(R) const noexcept -> constant_wrapper { return {}; } - constexpr operator decltype(auto)() const noexcept { return value; } + constexpr operator decltype(value)() const noexcept { return value; } }; } \end{codeblock} From d74efc40e48095265a4e23872bd0a9434a599e3b Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:36:52 -0700 Subject: [PATCH 204/258] LWG4474 "round_to_nearest" rounding mode is unclear --- source/support.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/support.tex b/source/support.tex index f269f5de8f..4122a22c45 100644 --- a/source/support.tex +++ b/source/support.tex @@ -998,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} From ba3eb6ece887924ae8606167a1c1d5c30a3b13a0 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:41:07 -0700 Subject: [PATCH 205/258] LWG4477 Placement operator delete should be constexpr --- source/support.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/support.tex b/source/support.tex index 4122a22c45..ce4a1c9271 100644 --- a/source/support.tex +++ b/source/support.tex @@ -2372,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} @@ -2943,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} @@ -2961,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} From 658ef112267553aef58ea0a4abc66973d7eb34f0 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:43:18 -0700 Subject: [PATCH 206/258] LWG4480 should provide ATOMIC_CHAR8_T_LOCK_FREE --- source/threads.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/source/threads.tex b/source/threads.tex index 1c86218983..5762bd5817 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -7097,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@ From 34bedfa3647198657d82bfc1b53a7cc96966ec18 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Mon, 6 Apr 2026 23:47:24 -0700 Subject: [PATCH 207/258] LWG4481 Disallow chrono::duration --- source/time.tex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/time.tex b/source/time.tex index 179b201771..a29b08edf7 100644 --- a/source/time.tex +++ b/source/time.tex @@ -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 From 1819377efb03c8cfc9e8f3f08feb06d3cc38eac5 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 01:02:21 -0700 Subject: [PATCH 208/258] LWG4483 Multidimensional arrays are not supported by meta::reflect_constant_array and related functions --- source/meta.tex | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index 1c978df0e6..79a5e2f4fa 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -3425,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{\{\}}. @@ -3460,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} @@ -3519,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(); } From 063e72241430c7ac37a04b6b43f96c4d42329eed Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 01:42:37 -0700 Subject: [PATCH 209/258] LWG4491 Rename submdspan_extents and submdspan_canonicalize_slices Fixes NB US 152-243, PL 008 (C++26 CD). --- source/containers.tex | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 83f3036ff1..e4ca851aa1 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -21287,12 +21287,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 submdspan_canonicalize_slices(const extents& src, - SliceSpecifiers... slices); + constexpr auto canonical_slices(const extents& src, + SliceSpecifiers... slices); \end{itemdecl} \begin{itemdescr} @@ -25880,20 +25881,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 @@ -26046,7 +26047,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} @@ -26119,7 +26120,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 @@ -26500,7 +26501,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 From b87220c1fae00e559b8abf7e9bf6f8dfb3948a28 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 01:56:41 -0700 Subject: [PATCH 210/258] LWG4493 Specification for some functions of bit reference types seems missing --- source/containers.tex | 12 ++++++++++++ source/utilities.tex | 25 ++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index e4ca851aa1..63cf29baa1 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -10652,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; diff --git a/source/utilities.tex b/source/utilities.tex index 6362adcf09..7b5fe5d565 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -10553,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; @@ -10698,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; From 518f4c2c48b8081d5d730dfac56e6cd04b66d128 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:01:08 -0700 Subject: [PATCH 211/258] LWG4500 constant_wrapper wording problems --- source/meta.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index 79a5e2f4fa..1a3aff5d63 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -810,16 +810,16 @@ // 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+=(this T, R) noexcept @@ -861,7 +861,7 @@ template<@\exposconcept{constexpr-param}@ R> constexpr auto operator=(R) const noexcept - -> constant_wrapper { return {}; } + -> constant_wrapper<(X = R::value)> { return {}; } constexpr operator decltype(value)() const noexcept { return value; } }; From 661ee8a14a1611eb20a92f7326917ebcf11e577e Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:17:11 -0700 Subject: [PATCH 212/258] LWG4514 Missing absolute value of init in vector_two_norm and matrix_frob_norm --- source/numerics.tex | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/source/numerics.tex b/source/numerics.tex index 0555a77696..46bb6d73b8 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -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}. From 061e643b87fe7061875d077dd430788c18054618 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:23:18 -0700 Subject: [PATCH 213/258] LWG4517 data_member_spec should throw for cv-qualified unnamed bit-fields --- source/meta.tex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/meta.tex b/source/meta.tex index 1a3aff5d63..7e5ea0a8a2 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -6650,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, From add4df6d832892bb97504c65a3ea751ab820e513 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:29:02 -0700 Subject: [PATCH 214/258] LWG4522 Clarify that std::format transcodes for std::wformat_strings --- source/text.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/text.tex b/source/text.tex index 2de7d40362..473255ae52 100644 --- a/source/text.tex +++ b/source/text.tex @@ -6446,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 From be29bdf8eb783f1109171ab5fef5b3c5bf3ad1ae Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:31:18 -0700 Subject: [PATCH 215/258] LWG4523 constant_wrapper should assign to value --- source/meta.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/meta.tex b/source/meta.tex index 7e5ea0a8a2..b2a168331b 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -861,7 +861,7 @@ template<@\exposconcept{constexpr-param}@ R> constexpr auto operator=(R) const noexcept - -> constant_wrapper<(X = R::value)> { return {}; } + -> constant_wrapper<(value = R::value)> { return {}; } constexpr operator decltype(value)() const noexcept { return value; } }; From 1bbe75117c766467627a779ef826335ee1e8bb8a Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:33:40 -0700 Subject: [PATCH 216/258] LWG4525 task's final_suspend should move the result --- source/exec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exec.tex b/source/exec.tex index 4455a1c991..6547c050ab 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7568,7 +7568,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} From 79a781c6e7972526930343d61a10997c236f1ed7 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:35:15 -0700 Subject: [PATCH 217/258] LWG4527 await_transform needs to use as_awaitable --- source/exec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exec.tex b/source/exec.tex index 6547c050ab..b53cdba51b 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7617,7 +7617,7 @@ \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} From a76d1f2629ab71ee0df90e36c0c27d3400e1e7c5 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:52:44 -0700 Subject: [PATCH 218/258] LWG4528 task needs get_completion_signatures() --- source/exec.tex | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index b53cdba51b..da1b4ef9b5 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7227,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@; @@ -7240,6 +7239,9 @@ task(task&&) noexcept; ~task(); + template + static consteval auto get_completion_signatures(); + template<@\libconcept{receiver}@ Rcvr> @\exposid{state}@ connect(Rcvr&& rcvr) &&; @@ -7281,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. @@ -7325,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> From a3bbccbb192b6989d0d32feb04561f1d7da1be97 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 02:56:36 -0700 Subject: [PATCH 219/258] LWG4529 task::promise_type::await_transform declaration and definition mismatch --- source/exec.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index da1b4ef9b5..cba1458af9 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7491,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); @@ -7611,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 @@ -7625,7 +7625,7 @@ \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 From df247bfef9fa78233bf9c3dc7a52e97306f7faee Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 08:23:37 +0200 Subject: [PATCH 220/258] [std] Add Annex for undefined and IFNDR behavior --- source/basic.tex | 28 +- source/classes.tex | 28 +- source/declarations.tex | 16 +- source/exceptions.tex | 2 +- source/expressions.tex | 52 +- source/ifndr.tex | 600 +++++++++++++ source/lex.tex | 2 +- source/macros.tex | 11 + source/modules.tex | 4 +- source/overloading.tex | 2 +- source/statements.tex | 8 +- source/std.tex | 2 + source/templates.tex | 26 +- source/ub.tex | 1760 +++++++++++++++++++++++++++++++++++++++ 14 files changed, 2457 insertions(+), 84 deletions(-) create mode 100644 source/ifndr.tex create mode 100644 source/ub.tex diff --git a/source/basic.tex b/source/basic.tex index 7aac6e400e..e3bb0699e6 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -674,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}, @@ -957,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}% @@ -1838,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} \} \} @@ -3768,7 +3768,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. @@ -4029,7 +4029,7 @@ 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\ubdef{lifetime.outside.pointer} if: \begin{itemize} \item the pointer is used as the operand of a \grammarterm{delete-expression}, @@ -4084,7 +4084,7 @@ 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\ubdef{lifetime.outside.glvalue} 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 @@ -4176,7 +4176,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} @@ -4196,7 +4196,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 { @@ -4544,7 +4544,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|)} @@ -6607,7 +6607,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}% @@ -7015,7 +7015,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 @@ -7379,7 +7379,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}% @@ -7716,7 +7716,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 @@ -7744,7 +7744,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 diff --git a/source/classes.tex b/source/classes.tex index 08134ae8b9..16a3643dbd 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -2264,7 +2264,7 @@ that is, if the object is not of the destructor's class type and not of a class derived from the destructor's class type (including when the destructor is invoked via a null pointer value), the program has -undefined behavior. +undefined behavior\ubdef{class.dtor.not.class.type}. \begin{note} Invoking \keyword{delete} on a null pointer does not call the destructor; see \ref{expr.delete}. @@ -2331,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, @@ -3211,7 +3211,7 @@ each anonymous union member \tcode{X}\iref{class.union.anon} that is a member of a union and has such an element as an immediate subobject (recursively), -if modification of \tcode{X} would have undefined behavior under~\ref{basic.life}, +if modification of \tcode{X} would have undefined behavior\ubdef{class.union.assignment.not.start.lifetime} under~\ref{basic.life}, an object of the type of \tcode{X} is implicitly created in the nominated storage; no initialization is performed and @@ -4002,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 @@ -4236,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}% @@ -5521,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 { @@ -5836,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 { @@ -6033,9 +6033,9 @@ \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.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 results in undefined behavior. +execution results in undefined behavior\ubdef{class.cdtor.before.ctor.after.dtor}. \begin{example} \begin{codeblock} struct X { int i; }; @@ -6120,7 +6120,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.or.form.pointer}. To form a pointer to (or access the value of) a direct non-static member of an object \tcode{obj}, @@ -6128,7 +6128,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.convert.or.form.pointer}. \begin{example} \begin{codeblock} struct A { }; @@ -6172,7 +6172,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 { @@ -6229,7 +6229,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}% @@ -6254,7 +6254,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 { diff --git a/source/declarations.tex b/source/declarations.tex index 2cf20c3632..2c89286ac4 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1296,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) @@ -1340,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}}% @@ -7398,7 +7398,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. @@ -7492,7 +7492,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. @@ -9668,7 +9668,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} @@ -9722,7 +9722,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} @@ -10154,12 +10154,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. diff --git a/source/exceptions.tex b/source/exceptions.tex index 465c819730..2747ac462d 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -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 diff --git a/source/expressions.tex b/source/expressions.tex index ea8b1848a5..b2e14a7244 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, @@ -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. @@ -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.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,7 @@ 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.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. @@ -3321,7 +3321,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 = @@ -3860,7 +3860,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 @@ -4392,7 +4392,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.not.similar}. \begin{example} \begin{codeblock} struct A { int i; }; @@ -4733,7 +4733,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 { }; @@ -4833,7 +4833,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 @@ -4848,7 +4848,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.downcast.wrong.derived.type}. \pnum \indextext{cast!base class}% @@ -4892,7 +4892,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 @@ -6286,7 +6286,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 @@ -6528,7 +6528,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 @@ -6540,7 +6540,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.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 @@ -6561,9 +6561,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}% @@ -7128,7 +7128,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 @@ -7180,7 +7180,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}% @@ -7221,7 +7221,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} @@ -7229,7 +7229,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}% @@ -7308,7 +7308,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$ @@ -7334,13 +7334,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.polymorphic}. \begin{example} \begin{codeblock} int arr[5] = {1, 2, 3, 4, 5}; @@ -7377,7 +7377,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 @@ -8288,7 +8288,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.ass.overlap}. \begin{note} This restriction applies to the relationship between the left and right sides of the assignment operation; it is not a diff --git a/source/ifndr.tex b/source/ifndr.tex new file mode 100644 index 0000000000..c904fd5a5a --- /dev/null +++ b/source/ifndr.tex @@ -0,0 +1,600 @@ +%!TEX root = std.tex +\infannex{ifndr}{Enumeration of Ill-formed, No Diagnostic Required} + +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 C++ implementations and shall not be used otherwise; no +diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +int _z; // No diagnostic required, \_z is reserved because it starts with \_ at global scope + +int main() { + int __x; // No diagnostic required, \_\_x is reserved because it starts with \_\_ + int _Y; // No diagnostic required, \_Y is reserved because it starts with \_ followed by a capital letter + int x__y; // No diagnostic required, x\_\_y is reserved because it contains \_\_ +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.basic]{\ref{basic}: Basics} + +\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 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.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 x is bound to the global x later during parsing the template + // parameter x is bound to the local x declared on the same line +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.dcl.dcl]{\ref{dcl}: Declarations} + +\rSec2[ifndr.dcl.align]{Alignment specifier} + +\pnum +\ifndrxref{dcl.align.diff.translation.units} \\ +No diagnostic is required if declarations of an entity have different alignment-specifiers in different +translation units. + +\pnum +\begin{example} +\begin{codeblock} +// Translation unit \#1: +struct S { int x; } s, *p = &s; + +// Translation unit \#2: +struct alignas(16) S; // ill-formed, no diagnostic required: definition of S lacks alignment +extern S* p; +\end{codeblock} +\end{example} + +\rSec2[ifndr.dcl.attr.noreturn]{Noreturn attribute} + +\pnum +\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} \\ + +\pnum +\begin{example} +\begin{codeblock} +/* Translation Unit A */ +[[noreturn]] void f() { +} + +/* Translation Unit B */ +struct void f(int i); // Ill-formed no diagnostic required, declared without noreturn +\end{codeblock} +\end{example} + +\rSec1[ifndr.module]{\ref{module}: Modules} + +\rSec2[ifndr.module.unit]{Module units and purviews} + +\pnum +\ifndrxref{module.unit.reserved.identifiers} \\ +All module-names either beginning with an identifier consisting of +std followed by zero or more digits or containing a reserved identifier (5.10) are reserved and shall not be +specified in a module-declaration; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +module std; // Ill-formed no diagnostic required, std is not allowed at the beginning +module module; // Ill-formed no diagnostic required, module is a reserved identifier +module std0; // Ill-formed no diagnostic required, std followed by digits is not allowed at the beginning +export module _Test; // Ill-formed no diagnostic required, _Test is a reserved identifier +export module te__st; // Ill-formed no diagnostic required, 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 parition not allowed +\end{codeblock} +\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 _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 (6.3) in which it is +implicitly instantiated (13.9.2) unless the corresponding specialization is explicitly instantiated (13.9.3) 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 (13.7.6) 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} + + +\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} + +\pnum +\ifndrxref{temp.names.sat.constraints} \\ +When the template-name of a simple-template-id names a constrained non-function template or a constrained +template template-parameter, and all template-arguments in the simple-template-id are non-dependent (13.8.3.5), +the associated constraints (13.5.3) of the constrained template shall be satisfied (13.5.2). + +\pnum +\begin{example} +\begin{codeblock} +template concept C1 = sizeof(T) != sizeof(int); +template using Ptr = T*; + +Ptr p; // error: constraints not satisfied + +template +struct S2 { Ptr x; }; // ill-formed, no diagnostic required +\end{codeblock} +\end{example} + + +\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 (13.8.4.1) 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} + +\rSec2[ifndr.temp.dep.res]{Dependent name resolution} + +\rSec3[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} + + +\rSec2[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 (13.9.2) 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} + + +\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 typename T::X h(typename A::X); +template auto h(typename A::X) -> typename T::X; // redeclaration +template void h(...) { } + +void x() { + h(0); // ill-formed, no diagnostic required +} +\end{codeblock} +\end{example} diff --git a/source/lex.tex b/source/lex.tex index ce8aa22ae6..b15fc493bf 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -999,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 diff --git a/source/macros.tex b/source/macros.tex index 397ea0f2d1..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}} diff --git a/source/modules.tex b/source/modules.tex index 4db5625672..fea1cc14e3 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 diff --git a/source/overloading.tex b/source/overloading.tex index 52883f84dd..0a0bfbd5fb 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -4168,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/statements.tex b/source/statements.tex index fa6944b172..3742c06e8a 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -1130,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 @@ -1226,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}} @@ -1366,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) { @@ -1458,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 { 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/templates.tex b/source/templates.tex index 70c42afb2c..d1f3312db6 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -249,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} @@ -987,7 +987,7 @@ are non-dependent\iref{temp.dep.temp}, the associated constraints\iref{temp.constr.decl} of the constrained template -shall be satisfied\iref{temp.constr.constr}. +shall be satisfied\iref{temp.constr.constr}\ifndrdef{temp.names.sat.constraints}. \begin{example} \begin{codeblock} template concept C1 = sizeof(T) != sizeof(int); @@ -1514,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 @@ -1871,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() @@ -1902,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 = @@ -2255,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 @@ -3739,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 @@ -4349,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 @@ -4915,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 @@ -6261,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} @@ -6939,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 { @@ -7168,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 @@ -8011,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} diff --git a/source/ub.tex b/source/ub.tex new file mode 100644 index 0000000000..b2078fae70 --- /dev/null +++ b/source/ub.tex @@ -0,0 +1,1760 @@ +%!TEX root = std.tex +\infannex{ub}{Enumeration of Core Undefined Behavior} + +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} +#include +struct X { + int a, b; + ~X() = delete; // deleted destructor makes X + // a non-implicit-lifetime class +}; + +X* make_x() { + // The call to std::malloc can not implicitly create an object of type X + // because 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 p1 was started but not + // ended and lifetime of p2 was not started. + return p2; +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.life]{Object lifetime} + +\pnum +\ubxref{lifetime.outside.pointer} \\ +The behavior of some uses of a pointer +pointing to an object outside its lifetime +are not defined: +\begin{itemize} +\item + 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}, +\item + the pointer is used to access a non-static data member or call a + non-static member function of the object, or +\item + the pointer is implicitly converted\iref{conv.ptr} to a pointer + to a virtual base class, or +\item + the pointer is used as the operand of a + \tcode{static_cast}\iref{expr.static.cast}, except when the conversion + is to pointer to \cv{}~\tcode{void}, or to pointer to \cv{}~\tcode{void} + and subsequently to pointer to + \cv{}~\tcode{char}, + \cv{}~\tcode{unsigned char}, or + \cv{}~\tcode{std::byte}\iref{cstddef.syn}, or +\item + the pointer is used as the operand of a + \tcode{dynamic_cast}\iref{expr.dynamic.cast}. +\end{itemize} + + +\pnum +\begin{example} +\begin{codeblock} +struct S { + float f = 0; + ~S() {} +}; + +float f() { + S s; + S* p1 = &s; + S* p2 = new S; + s.~S(); + p2->~S(); + delete p2; // Undefined behavior, operand of delete, lifetime has ended and S + // has a non-trivial destructor + return p1->f; // Undefined behavior, accessing non-static data member after + // end of lifetime +} +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +#include +#include + +struct B { + virtual void f(); + void mutate(); + virtual ~B(); +}; + +struct D1 : B { + void f(); +}; +struct D2 : B { + void f(); +}; + +void B::mutate() { + new (this) D2; // reuses storage — ends the lifetime of *this + f(); // undefined behavior + B *b = this; // OK, this points to valid memory +} + +void g() { + void* p = std::malloc(sizeof(D1) + sizeof(D2)); + B* pb = new (p) D1; + pb->mutate(); + *pb; // OK: pb points to valid memory + void* q = pb; // OK: pb points to valid memory + pb->f(); // undefined behavior: lifetime of *pb has ended +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue} \\ +The behavior of some uses of a glvalue +that refers to an object outside its lifetime +are not defined. + +\pnum +\begin{example} +\begin{codeblock} +struct A{void f(){} }; + +void f() { + int x = int{10}; + A a; + using T = int; + x.~T(); + a.~A(); + a.f(); // Undefined behavior, glvalue used to access a + // non-static member function after the lifetime has ended + int y = x; // Undefined behavior, glvalue used to access the + // object after the lifetime has ended +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{original.type.implicit.destructor} \\ +The behavior of an implicit destructor call when the type that is not +the original type occupies the 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.stc.dynamic]{Dyanmic 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 \iref{basic.stc.dynamic.allocation} and \iref{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 reutrn 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} + +\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 \iref{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.basic.start.main]{main function} + +\pnum +\ubxref{basic.start.main.exit.during.destruction} \\ +If 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 ex is called it will call 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; + +int main() {} +// Undefined behavior, static objects are destructed in reverse order, in this case a then b and +// finally c. When the destructor of c is call it calls f() which passes through 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} + + +\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 through a glvalue whose type is not +similar \iref{conv.rval} to one of the following 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 int + + return *i; +} + +int main() { + int x = 0; + + x = foo(reinterpret_cast(&x), &x); +} +\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 + // represetable 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.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 + + __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.expr.call]{Function call} + +\pnum +\ubxref{expr.call.different.type} \\ +Calling a function through an expression whose function type is different from 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.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} + + +\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} +truct B {}; +struct D1 : B {}; +struct D2 : B {}; + +void f() { + D1 d; + B &b = d; + static_cast(b); // Undefined behavior, base class + // object of type D1 not 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.downcast.wrong.derived.type} \\ +Down-casting to the wrong derived type is 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 D1 not D2 +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.does.not.contain.orignal.member} \\ +We can cast a pointer to mamber of dervied class D to a pointer to memeber of base class D (with certain restrictions wrt to cv qualifiers) +as long B contains the original member, 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 + // B does not contain the original member c +} +\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 *buffer = nullptr; + A *a = new (buffer) 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 and vice versa 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.dynamic.type.differ} \\ +If the static type of the object to be deleted is different from its dynamic +type and the selected deallocation function (see below) 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 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 B does not contain x +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.mptr.oper.member.func.null} \\ +If the second operand 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 -2147483648 which when divided by -1 + // gives us 2147483648 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, p1 and p2 point to different arrays +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.add.polymorphic} \\ +For addition or subtraction, if the expressions 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.ass]{Assignment and compound assignment operators} + +\pnum +\ubxref{expr.ass.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. + +\pnum +\begin{example} +\begin{codeblock} +int f(int x) { + if (x) + return 1; + // Undefined behavior if we reach this point and flow off the end +} + +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} \\ +Falling off the end of a coroutine function body that does not return void is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include +#include +#include +#include + +class resumable { + public: + struct promise_type; + using coro_handle = std::experimental::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(); + // co_return "Coroutine" ; // 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.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 am assumption expression would not evaluate to true at the point where it +appears the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int divide_by_32(int x) { + [[assume(x >= 0)]]; + return x/32; +} + +int f() { + return divide_by_32(-10); // Undefined behavior, assumption in divide_by_32() + // if evaluated would be 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 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, we will return from a [[noreturn]] function +} +\end{codeblock} +\end{example} + + + +\rSec1[ub.class]{\ref{class}: Classes} + +\rSec2[ub.class.dtor]{Destructors} + +\pnum +\ubxref{class.dtor.not.class.type} \\ +The invocation of a destructor is subject to the usual rules for +member functions \iref{class.mfct}; that is, if the object is not of the destructor’s class type and not of a class derived +from the destructor’s class type (including when the destructor is invoked via a null pointer value), the +program has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +struct X {}; + +void f() { + X *x = nullptr; + x->~X(); // undefined behavior, invoked using a nullptr +} + +struct Y {}; +void h() { + alignas(X) char buf[sizeof(X)]; + X *p = new (buf) X(); // use buf[] and initialize + + Y *yp = reinterpret_cast(p); + yp->Y::~Y(); // undefined behavior, destructor of Y called for object of type + // X +} + +struct Base { + virtual ~Base(); +}; +struct Derived : Base {}; + +int k() { + Base *b = new Base; + Derived *d = static_cast(b); + d->~Derived(); // undefined behavior, destructor of Derived call for object of + // type Base + // elided code +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.dtor.no.longer.exists} \\ +Once a destructor is invoked for an object, the object no longer exists; 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, destructor will be invoked again at scope exit +} +\end{codeblock} +\end{example} + + +\rSec2[ub.class.union]{Unions} + +\pnum +\ubxref{class.union.assignment.not.start.lifetime} \\ +Assigning to a union member may not start its lifetime, in that case using it will result in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct X { + const int a; + int b; +}; + +union Y { + X x; + int k; +}; + +void g() { + Y y = {{1, 2}}; // OK, y.x is active union member (11.4) + int n = y.x.a; + y.k = 4; // OK: ends lifetime of y.x, y.k is active member of union + y.x.b = n; // undefined behavior: y.x.b modified outside its lifetime, + // S(y.x.b) is empty because X’s default constructor is deleted, + // so union member y.x’s lifetime does not implicitly start +} +\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, 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 mem-initializers 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 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.after.dtor} \\ +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 any non-static member or base class of the object after the destructor finishes 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 bobj + +extern X xobj; +int *p3 = &xobj.i; // OK, 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, x is not yet constructed + } +}; +\end{codeblock} +\end{example} + + +\pnum +\ubxref{class.cdtor.convert.or.form.pointer} \\ +When converting a pointer to a base class of an object or forming a pointer to a direct non-static +member of a class, 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: upcast from E* to A* might use path E->D->A + // but D is not constructed + // “D((C*)this)” would be defined: E->C is defined because + // E() has started, and C->A is defined because C is fully + // constructed + X(this) { + } // defined: upon construction of X, C/B/D/A sublattice is fully constructed +}; +\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 V::f, not A::f + g(); // calls B::g, not D::g + v->g(); // v is base of B, the call is well-defined, calls B::g + a->f(); // undefined behavior, a’s type not a base of 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); // type_info for B + typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B + typeid(*a); // undefined behavior: type A not a base of 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: v of type V*, V base of B results in B* + dynamic_cast(a); // undefined behavior: a has type A*, A not a base of 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 generation of X requires + // the implicit instantiation of X which requires + // the implicit instantiation of X which . . . +}; + +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} + + +\rSec1[ub.cpp]{\ref{cpp}: Preprocessing directives} + +\rSec2[ub.cpp.cond]{Conditional inclusion} + +\pnum +\ubxref{cpp.cond.defined} \\ +If the token defined is generated as a result of this replacement process or use of +the defined unary operator does not match one of the two specified forms prior to macro replacement, the +behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define A +#define B defined(A) +#if B // Undefined behavior, defined is generated by macro replacement for controlling expression +#endif +\end{codeblock} +\end{example} + + +\rSec2[ub.cpp.include]{Source file inclusion} + +\pnum +\ubxref{cpp.include.one.of.two.forms} \\ +If the an include directive after replacement does not match one of the two forms +outlined [cpp.indlude]\iref{cpp.include} then the behavior is undefined + +\pnum +\begin{example} +\begin{codeblock} +#include " // Undefined behavior, does not match one of the two allowable forms +\end{codeblock} +\end{example} + + +\rSec2[ub.cpp.replace]{Macro replacement} + +\pnum +\ubxref{cpp.replace.macro.pptoken} \\ +If there are sequences of preprocessing tokens within the list of arguments to a function-like macro +that would otherwise act as preprocessing directives, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define M(d, n) d = n + +void f(int x) { + M(x, +#ifdef D // Undefined behavior, preprocessing directive + 16 +#else // Undefined behavior, preprocessing directive + 32 +#endif // Undefined behavior, preprocessing directive + ); +} + +int main() { + int x; + f(x); +} +\end{codeblock} +\end{example} + + +\rSec2[ub.cpp.stringize]{The \# operator} + +\pnum +\ubxref{cpp.stringize.invalid.char} \\ +If an invalid character results from using the stringize operator the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define s_lit(x) #x +s_lit( \ ) // Stringizes to "\tcode{\textbackslash}"", which is not a valid token. +\end{codeblock} +\end{example} + + +\rSec2[ub.cpp.concat]{The \#\# operator} + +\pnum +\ubxref{cpp.concat.universal.char} \\ +If a character sequence that matches the syntax of a \grammarterm{universal-character-name} +is produced by token concatenation \iref{cpp.concat}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define GUARD_NAME ï ## _GUARD // Undefined behavior, character sequence produced contains + // a universal-character-name +#define COLUMN ï ##_column // Undefined behavior, character sequence produced contains + // a universal-character-name +\end{codeblock} +\end{example} + +\pnum +\ubxref{cpp.concat.invalid.preprocessing.token} \\ +If an invalid preprocessing token results from using the concat operator the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define cat(x, y) x##y + +void f() { + cat(/, /) // Undefined behavior // is not a valid preprocessing token +} +\end{codeblock} +\end{example} + + +\rSec2[ub.cpp.line]{Line control} + +\pnum +\ubxref{cpp.line.zero.or.overflow} \\ +When using the \tcode{\#line} directive, if the digit sequence +specifies zero or a number greater than 2147483647, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#line 4294967295 // Undefined behavior, number greater than 2147483647 + +int main() { return notdefined; } +\end{codeblock} +\end{example} + +\pnum +\ubxref{cpp.line.pptoken.not.match} \\ +When using the \grammarterm{pp-token} variant of the \tcode{\#line} directive, if the directive resulting after all replacements does not match +one of the two previous forms, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define cat(a, b) a##b +#line cat(10, e20) +\end{codeblock} +\end{example} + +\rSec2[ub.cpp.predefined]{Predefined macro names} + +\pnum +\ubxref{cpp.predefined.define.undef} \\ +If any of the pre-defined macro names in [cpp.predefined], or the identifier defined, is the subject of a \tcode{\#define} +or a \tcode{\#undef} preprocessing directive, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#define __cplusplus 300012L +\end{codeblock} +\end{example} From d230d0b4ed29f845c9937c6f0b27756a067a2af9 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 19:24:53 +0200 Subject: [PATCH 221/258] [class.cdtor] Remove duplicate UB labels --- source/classes.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index 16a3643dbd..aad31010e3 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -6035,7 +6035,7 @@ or base class of the object before the constructor begins execution results in undefined behavior\ubdef{class.cdtor.before.ctor.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 results in undefined behavior\ubdef{class.cdtor.before.ctor.after.dtor}. +execution results in undefined behavior. \begin{example} \begin{codeblock} struct X { int i; }; @@ -6120,7 +6120,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\ubdef{class.cdtor.convert.or.form.pointer}. +completed, otherwise the conversion results in undefined behavior. To form a pointer to (or access the value of) a direct non-static member of an object \tcode{obj}, From 13e075f3ee5cd4618809fd197588c58f75bbf451 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 11 Apr 2025 16:38:43 +0200 Subject: [PATCH 222/258] [expr.delete] Remove duplicate UB label --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index b2e14a7244..c38b811787 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -6540,7 +6540,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\ubdef{expr.delete.mismatch}. +If not, the behavior is undefined. \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 From 12fe729b45c310e55c6b4ddc85cf773f32caa52a Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 11 Apr 2025 16:39:00 +0200 Subject: [PATCH 223/258] [conv.fpint] Remove duplicate UB label --- source/expressions.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index c38b811787..cfc3652ca2 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -1024,7 +1024,7 @@ 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\ubdef{conv.fpint.not.represented}. If the +outside the range of values that can be represented, the behavior is undefined. If the source type is \keyword{bool}, the value \keyword{false} is converted to zero and the value \keyword{true} is converted to one. From ac1b907e679aab113a4de87315700b992f4d8ea8 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 11:58:40 +0200 Subject: [PATCH 224/258] [ifndr.lex] Replace C++ with \Cpp --- source/ifndr.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index c904fd5a5a..ced81a38eb 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -13,7 +13,7 @@ \pnum \ifndrxref{lex.name.reserved} \\ -Some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no +Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no diagnostic is required. \pnum From 902c987ce9ff6f96928b068fe348ca2f370f4c76 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 10:15:45 +0200 Subject: [PATCH 225/258] [ub,ifndr] Fix column alignment of comments --- source/ifndr.tex | 86 +++++++-------- source/ub.tex | 281 +++++++++++++++++++++-------------------------- 2 files changed, 170 insertions(+), 197 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index ced81a38eb..9822d49f10 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -19,12 +19,12 @@ \pnum \begin{example} \begin{codeblock} -int _z; // No diagnostic required, \_z is reserved because it starts with \_ at global scope +int _z; // no diagnostic required, \tcode{\_z} is reserved because it starts with \tcode{\_} at global scope int main() { - int __x; // No diagnostic required, \_\_x is reserved because it starts with \_\_ - int _Y; // No diagnostic required, \_Y is reserved because it starts with \_ followed by a capital letter - int x__y; // No diagnostic required, x\_\_y is reserved because it contains \_\_ + 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} @@ -47,9 +47,9 @@ return A{}; } decltype(f()) g(); -auto x = g(); // Ill-formed, no diagnostic required, function 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 +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} @@ -73,8 +73,8 @@ // 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 +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} @@ -166,9 +166,9 @@ int main() { using T = const int; T(x) - (100), (y)(A::a); // Ill-formed no diagnostic required, during trial parse the template - // parameter x is bound to the global x later during parsing the template - // parameter x is bound to the local x declared on the same line + (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} @@ -190,7 +190,7 @@ struct S { int x; } s, *p = &s; // Translation unit \#2: -struct alignas(16) S; // ill-formed, no diagnostic required: definition of S lacks alignment +struct alignas(16) S; // ill-formed, no diagnostic required, definition of \tcode{S} lacks alignment extern S* p; \end{codeblock} \end{example} @@ -208,7 +208,7 @@ } /* Translation Unit B */ -struct void f(int i); // Ill-formed no diagnostic required, declared without noreturn +struct void f(int i); // ill-formed no diagnostic required, declared without noreturn \end{codeblock} \end{example} @@ -225,11 +225,11 @@ \pnum \begin{example} \begin{codeblock} -module std; // Ill-formed no diagnostic required, std is not allowed at the beginning -module module; // Ill-formed no diagnostic required, module is a reserved identifier -module std0; // Ill-formed no diagnostic required, std followed by digits is not allowed at the beginning -export module _Test; // Ill-formed no diagnostic required, _Test is a reserved identifier -export module te__st; // Ill-formed no diagnostic required, te__st is a reserved identifier +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} @@ -244,7 +244,7 @@ \begin{example} \begin{codeblock} module A; -export import :Internals; // Ill-formed no diagnostic required, module parition not allowed +export import :Internals; // ill-formed no diagnostic required, module partition not allowed \end{codeblock} \end{example} @@ -262,10 +262,10 @@ \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 + 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} @@ -286,7 +286,7 @@ }; int main() { - A a; // Ill-formed no diagnostic required, virtual function that is not pure but has not definition + A a; // ill-formed no diagnostic required, virtual function that is not pure but has not definition } \end{codeblock} \end{example} @@ -305,10 +305,8 @@ \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 _Bq +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} @@ -333,8 +331,8 @@ // a.cpp #include "a.h" int main() { - f(); // Ill-formed no diagnostic required, function template implicity - // instantiated but not reachable definition + f(); // ill-formed no diagnostic required, function template implicity + // instantiated but not reachable definition } \end{codeblock} \end{example} @@ -388,9 +386,9 @@ 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 +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} @@ -405,10 +403,10 @@ concept Complete = sizeof(T) == sizeof(T); struct A; -static_assert(!Complete); // 1 +static_assert(!Complete); // \#1 struct A {}; -static_assert(Complete); // Ill-formed no diagnostic required, satisfaction - // result differs from point 1 +static_assert(Complete); // ill-formed no diagnostic required, satisfaction + // result differs from point \#1 \end{codeblock} \end{example} @@ -446,8 +444,8 @@ void foo(){}; }; -template class X; // Ill-formed no diagnostic required, explicit instantiation - // and partial specialization is not reachable +template class X; // ill-formed no diagnostic required, explicit instantiation + // and partial specialization is not reachable template class X{ public: @@ -474,7 +472,7 @@ Ptr p; // error: constraints not satisfied template -struct S2 { Ptr x; }; // ill-formed, no diagnostic required +struct S2 { Ptr x; }; // ill-formed, no diagnostic required \end{codeblock} \end{example} @@ -569,8 +567,8 @@ extern template class std::vector; int main() { - std::cout << std::vector().size(); // Ill-formed no diagnostic required, implicit instantiation - // but no explicit instantiation definition + std::cout << std::vector().size(); // ill-formed no diagnostic required, implicit instantiation + // but no explicit instantiation definition } \end{codeblock} \end{example} @@ -590,11 +588,11 @@ \begin{example} \begin{codeblock} template typename T::X h(typename A::X); -template auto h(typename A::X) -> typename T::X; // redeclaration +template auto h(typename A::X) -> typename T::X; // redeclaration template void h(...) { } void x() { - h(0); // ill-formed, no diagnostic required + h(0); // ill-formed, no diagnostic required } \end{codeblock} \end{example} diff --git a/source/ub.tex b/source/ub.tex index b2078fae70..88500685c7 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -27,15 +27,14 @@ #include struct X { int a, b; - ~X() = delete; // deleted destructor makes X - // a non-implicit-lifetime class + ~X() = delete; // deleted destructor makes \tcode{X} a non-implicit-lifetime class }; X* make_x() { - // The call to std::malloc can not implicitly create an object of type X - // because X is not an implicit-lifetime class. + // The call to std::malloc can not implicitly create an object of type X + // because 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 + p->a = 1; // undefined behavior, no set of objects give us defined behavior return p; } \end{codeblock} @@ -56,8 +55,8 @@ X* p1 = (X*)std::malloc(sizeof(struct X)); p1->a = 1; Y* p2 = (Y*)p1; - p2->x = 2; // Undefined behavior, lifetime of p1 was started but not - // ended and lifetime of p2 was not started. + 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} @@ -93,7 +92,6 @@ \tcode{dynamic_cast}\iref{expr.dynamic.cast}. \end{itemize} - \pnum \begin{example} \begin{codeblock} @@ -108,10 +106,10 @@ S* p2 = new S; s.~S(); p2->~S(); - delete p2; // Undefined behavior, operand of delete, lifetime has ended and S - // has a non-trivial destructor - return p1->f; // Undefined behavior, accessing non-static data member after - // end of lifetime + delete p2; // undefined behavior, operand of delete, lifetime has ended and \tcode{S} + // has a non-trivial destructor + return p1->f; // Undefined behavior, accessing non-static data member after + // end of lifetime } \end{codeblock} \end{example} @@ -134,18 +132,18 @@ }; void B::mutate() { - new (this) D2; // reuses storage — ends the lifetime of *this - f(); // undefined behavior - B *b = this; // OK, this points to valid memory + new (this) D2; // reuses storage and ends the lifetime of *this + f(); // undefined behavior + B *b = this; // OK, this points to valid memory } void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate(); - *pb; // OK: pb points to valid memory - void* q = pb; // OK: pb points to valid memory - pb->f(); // undefined behavior: lifetime of *pb has ended + *pb; // OK, pb points to valid memory + void* q = pb; // OK, pb points to valid memory + pb->f(); // undefined behavior, lifetime of \tcode{*pb} has ended } \end{codeblock} \end{example} @@ -167,10 +165,10 @@ using T = int; x.~T(); a.~A(); - a.f(); // Undefined behavior, glvalue used to access a - // non-static member function after the lifetime has ended - int y = x; // Undefined behavior, glvalue used to access the - // object after the lifetime has ended + a.f(); // undefined behavior, glvalue used to access a + // non-static member function after the lifetime has ended + int y = x; // undefined behavior, glvalue used to access the + // object after the lifetime has ended } \end{codeblock} \end{example} @@ -193,7 +191,7 @@ void h() { B b; new (&b) T; -} // undefined behavior at block exit +} // undefined behavior at block exit \end{codeblock} \end{example} @@ -235,14 +233,13 @@ #include void* operator new(std::size_t sz) { if (sz == 0) - return nullptr; // undefined behavior, should return non-null pointer + return nullptr; // undefined behavior, should return non-null pointer - return std::malloc( - 1); // undefined behavior, if successful should reutrn allocation with - // length in bytes is at least as large as the requested size + 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 + throw 0; // undefined behavior, terminates by throwing an exception } \end{codeblock} \end{example} @@ -376,8 +373,8 @@ #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 + 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} @@ -394,7 +391,7 @@ \begin{codeblock} int foo(float* f, int* i) { *i = 1; - *f = 0.f; // undefined behavior, glvalue is not similar to int + *f = 0.f; // undefined behavior, glvalue is not similar to \tcode{int} return *i; } @@ -422,11 +419,10 @@ 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 + float f = d2; // 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 - int i = d2; // Undefined behavior, the max value of double is not - // representable as int + int i = d2; // undefined behavior, the max value of double is not representable as int } \end{codeblock} @@ -449,11 +445,10 @@ // 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 + int x1 = d; // undefined behavior 2,147,483,647 + 1 is not representable as int __uint128_t x2 = -1; - float f = x2; // Undefined behavior on systems where the range of + 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 } @@ -478,8 +473,8 @@ 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 + return reinterpret_cast(f1)(20); // undefined behavior, the function type of the expression + // is different from the called functions definition } \end{codeblock} \end{example} @@ -499,7 +494,7 @@ struct D : A, B {}; void f() { D d; - reinterpret_cast(d).j; // undefined behavior + reinterpret_cast(d).j; // undefined behavior } \end{codeblock} \end{example} @@ -522,8 +517,7 @@ void f() { D1 d; B &b = d; - static_cast(b); // Undefined behavior, base class - // object of type D1 not D2 + static_cast(b); // undefined behavior, base class object of type \tcode{D1} not \tcode{D2} } \end{codeblock} \end{example} @@ -540,8 +534,7 @@ enum A { e1 = 1, e2 }; void f() { - enum A a = - static_cast(4); // Undefined behavior, 4 is not with the range of enumeration values. + enum A a = static_cast(4); // undefined behavior, 4 is not with the range of enumeration values } \end{codeblock} \end{example} @@ -559,7 +552,7 @@ void f() { B *bp = new D1; - static_cast(bp); // Undefined behavior, base class object of type D1 not D2 + static_cast(bp); // undefined behavior, base class object of type \tcode{D1} not \tcode{D2} } \end{codeblock} \end{example} @@ -585,9 +578,7 @@ int main() { char D::*p1 = &D::c; - char B::*p2 = - static_cast(p1); // undefined behavior - // B does not contain the original member c + char B::*p2 = static_cast(p1); // undefined behavior, \tcode{B} does not contain the original member \tcode{c} } \end{codeblock} \end{example} @@ -605,7 +596,7 @@ \begin{codeblock} #include [[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept { - return nullptr; // undefined behavior, should return non-null pointer + return nullptr; // undefined behavior, should return non-null pointer } \end{codeblock} \end{example} @@ -618,8 +609,8 @@ }; int main() { - char *buffer = nullptr; - A *a = new (buffer) A; // Undefined behavior, non-allocting new returning nullptr + char *p = nullptr; + A *a = new (p) A; // undefined behavior, non-allocting new returning nullptr } \end{codeblock} \end{example} @@ -635,7 +626,7 @@ \begin{example} \begin{codeblock} int* x = new int; -delete[] x; // undefined behavior, allocated using single object new expression +delete[] x; // undefined behavior, allocated using single object new expression \end{codeblock} \end{example} @@ -660,7 +651,7 @@ void f() { B* b = new D; - delete b; // undefined behavior, no virtual destructor + delete b; // undefined behavior, no virtual destructor } \end{codeblock} \end{example} @@ -684,16 +675,14 @@ void f(int i) { D* dp = new D[i]; - delete[] dp; // uses D::operator delete[](void*, std::size_t) + delete[] dp; // uses \tcode{D::operator delete[](void*, std::size_t)} B* bp = new D[i]; - delete[] bp; // undefined behavior + delete[] bp; // undefined behavior } \end{codeblock} \end{example} - - \rSec2[ub.expr.mptr.oper]{Pointer-to-member operators} \pnum @@ -713,7 +702,7 @@ B *b = new B; D *d = static_cast(b); int D::*p = &D::x; - (*d).*p = 1; // undefined behavior, dynamic type B does not contain x + (*d).*p = 1; // undefined behavior, dynamic type \tcode{B} does not contain \tcode{x} } \end{codeblock} \end{example} @@ -734,7 +723,7 @@ void f() { S cs; int (S::*pm)() = nullptr; - (cs.*pm)(); // Undefined behavior, the second operand is null + (cs.*pm)(); // undefined behavior, the second operand is null } \end{codeblock} \end{example} @@ -750,15 +739,14 @@ \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 + 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 @@ -790,17 +778,18 @@ static const int arrs[10]{}; int main() { - const int *y = arrs + 11; // Undefined behavior, creating an out of bounds pointer + 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, + 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} @@ -818,7 +807,7 @@ int y[2]; int* p1 = x; int* p2 = y; - std::ptrdiff_t off = p1 - p2; // Undefined behavior, p1 and p2 point to different arrays + std::ptrdiff_t off = p1 - p2; // undefined behavior, \tcode{p1} and \tcode{p2} point to different arrays } \end{codeblock} \end{example} @@ -862,11 +851,11 @@ \pnum \begin{example} \begin{codeblock} -int y = 1 << -1; // undefined behavior, shift is negative +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 +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} @@ -882,12 +871,10 @@ \begin{codeblock} int x = 1; char* c = reinterpret_cast(&x); -x = *c; // Undefined behavior, source overlaps storage of destination +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} @@ -903,11 +890,11 @@ int f(int x) { if (x) return 1; - // Undefined behavior if we reach this point and flow off the end + // 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 + 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} @@ -923,14 +910,14 @@ \begin{example} \begin{codeblock} #include -#include +#include #include #include class resumable { public: struct promise_type; - using coro_handle = std::experimental::coroutine_handle; + using coro_handle = std::coroutine_handle; resumable(coro_handle handle) : handle_(handle) { assert(handle); } resumable(resumable&) = delete; resumable(resumable&&) = delete; @@ -963,8 +950,7 @@ resumable foo() { std::cout << "Hello" << std::endl; co_await std::experimental::suspend_always(); - // co_return "Coroutine" ; // Undefined behavior, falling off the end of - // coroutine that does not return void + // undefined behavior, falling off the end of coroutine that does not return void } int main() { @@ -987,7 +973,7 @@ \begin{example} \begin{codeblock} int foo(int i) { - static int s = foo(2 * i); // recursive call - undefined + static int s = foo(2 * i); // recursive call - undefined return i + 1; } \end{codeblock} @@ -1026,8 +1012,7 @@ \begin{codeblock} volatile int x = 0; int& y = const_cast(x); -std::cout << y; // undefined behavior, accessing volatile through non-volatile - // glvalue +std::cout << y; // undefined behavior, accessing volatile through non-volatile glvalue \end{codeblock} \end{example} @@ -1147,8 +1132,6 @@ \end{codeblock} \end{example} - - \rSec2[ub.dcl.attr.assume]{Assumption attribute} \pnum @@ -1159,14 +1142,13 @@ \pnum \begin{example} \begin{codeblock} -int divide_by_32(int x) { +int g(int x) { [[assume(x >= 0)]]; return x/32; } int f() { - return divide_by_32(-10); // Undefined behavior, assumption in divide_by_32() - // if evaluated would be false + return g(-10); // undefined behavior, assumption in \tcode{g} is \tcode{false} } \end{codeblock} \end{example} @@ -1176,7 +1158,7 @@ \pnum \ubxref{dcl.attr.noreturn.eventually.returns} \\ -If a function f is called where f was previously declared with the noreturn attribute and f 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 @@ -1188,13 +1170,12 @@ } int main() { - f(0); // Undefined behavior, we will return from a [[noreturn]] function + f(0); // undefined behavior, returns from a [[noreturn]] function } \end{codeblock} \end{example} - \rSec1[ub.class]{\ref{class}: Classes} \rSec2[ub.class.dtor]{Destructors} @@ -1215,17 +1196,16 @@ void f() { X *x = nullptr; - x->~X(); // undefined behavior, invoked using a nullptr + x->~X(); // undefined behavior, invoked using a null pointer value } struct Y {}; void h() { alignas(X) char buf[sizeof(X)]; - X *p = new (buf) X(); // use buf[] and initialize + X *p = new (buf) X(); // use \tcode{buf[] }and initialize Y *yp = reinterpret_cast(p); - yp->Y::~Y(); // undefined behavior, destructor of Y called for object of type - // X + yp->Y::~Y(); // undefined behavior, destructor of \tcode{Y} called for object of type \tcode{X} } struct Base { @@ -1236,9 +1216,8 @@ int k() { Base *b = new Base; Derived *d = static_cast(b); - d->~Derived(); // undefined behavior, destructor of Derived call for object of - // type Base - // elided code + d->~Derived(); // undefined behavior, destructor of Derived call for object of + // type \tcode{Base} } \end{codeblock} \end{example} @@ -1257,7 +1236,7 @@ int main() { A a; - a.~A(); // undefined behavior, destructor will be invoked again at scope exit + a.~A(); // undefined behavior, destructor will be invoked again at scope exit } \end{codeblock} \end{example} @@ -1283,12 +1262,12 @@ }; void g() { - Y y = {{1, 2}}; // OK, y.x is active union member (11.4) + Y y = {{1, 2}}; // OK, \tcode{y.x} is active union member\iref{11.4} int n = y.x.a; - y.k = 4; // OK: ends lifetime of y.x, y.k is active member of union - y.x.b = n; // undefined behavior: y.x.b modified outside its lifetime, - // S(y.x.b) is empty because X’s default constructor is deleted, - // so union member y.x’s lifetime does not implicitly start + y.k = 4; // OK, ends lifetime of \tcode{y.x}, \tcode{y.k} is active member of union + y.x.b = n; // undefined behavior: \tcode{y.x.b} modified outside its lifetime, + // \tcode{S(y.x.b)} is empty because \tcode{X}’s default constructor is deleted, + // so union member \tcode{y.x}'s lifetime does not implicitly start } \end{codeblock} \end{example} @@ -1306,8 +1285,7 @@ struct B { virtual void f() = 0; B() { - f(); // undefined behavior, f is pure virtual and we are calling from the - // constructor + f(); // undefined behavior, \tcode{f} is pure virtual and we are calling from the constructor } }; @@ -1322,7 +1300,7 @@ \pnum \ubxref{class.base.init.mem.fun} \\ -It is undefined behavior to call a member function before all the mem-initializers for base classes have completed. +It is undefined behavior to call a member function before all the \grammarterm{mem-initializer}s for base classes have completed. \pnum \begin{example} @@ -1338,9 +1316,8 @@ public: int f(); B() - : A(f()), // undefined: calls member function but base A not yet - // initialized - j(f()) {} // well-defined: bases are all initialized + : A(f()), // undefined: calls member function but base Ac not yet initialized + j(f()) {} // well-defined: bases are all initialized }; class C { @@ -1353,9 +1330,8 @@ public: D() - : C(f()), // undefined: calls member function but base C not yet - // initialized - i(f()) {} // well-defined: bases are all initialized + : 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} @@ -1378,25 +1354,25 @@ }; struct Y : X { Y(); -}; // non-trivial +}; // non-trivial struct A { int a; }; struct B : public A { int j; Y y; -}; // non-trivial +}; // 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 +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 bobj +A *pa = &bobj; // undefined, upcast to a base class type +B bobj; // definition of \tcode{bobj} extern X xobj; -int *p3 = &xobj.i; // OK, X is a trivial class +int *p3 = &xobj.i; // OK, \tcode{X} is a trivial class X xobj; struct W { @@ -1406,7 +1382,7 @@ struct Y { int *p; X x; - Y() : p(&x.j) { // undefined, x is not yet constructed + Y() : p(&x.j) { // undefined, \tcode{x} is not yet constructed } }; \end{codeblock} @@ -1432,15 +1408,14 @@ X(A *); }; struct E : C, D, X { - E() - : D(this), // undefined: upcast from E* to A* might use path E->D->A - // but D is not constructed - // “D((C*)this)” would be defined: E->C is defined because - // E() has started, and C->A is defined because C is fully - // constructed - X(this) { - } // defined: upon construction of X, C/B/D/A sublattice is fully constructed + : D(this), // undefined: upcast from \tcode{E*} to \tcode{A*} might use path E->D->A + // but \tcode{D} is not constructed + // \tcode{D((C*)this)} would be defined: E->C is defined because + // \tcode{E()} has started, and C->A is defined because \tcode{C} is fully + // constructed + X(this) // well-defined: upon construction of \tcode{X}, C/B/D/A sublattice is fully constructed + {} }; \end{codeblock} \end{example} @@ -1479,10 +1454,10 @@ }; B::B(V *v, A *a) { - f(); // calls V::f, not A::f - g(); // calls B::g, not D::g - v->g(); // v is base of B, the call is well-defined, calls B::g - a->f(); // undefined behavior, a’s type not a base of B + 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} @@ -1511,9 +1486,9 @@ }; B::B(V *v, A *a) { - typeid(*this); // type_info for B - typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B - typeid(*a); // undefined behavior: type A not a base of B + 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} @@ -1543,14 +1518,13 @@ }; B::B(V *v, A *a) { - dynamic_cast(v); // well-defined: v of type V*, V base of B results in B* - dynamic_cast(a); // undefined behavior: a has type A*, A not a base of B + 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} @@ -1561,15 +1535,16 @@ \pnum \begin{example} \begin{codeblock} -template class X { - X *p; // OK - X a; // implicit generation of X requires - // the implicit instantiation of X which requires - // the implicit instantiation of X which . . . +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 + X x; // undefined behavior, instantiation will kick off infinite recursion } \end{codeblock} \end{example} @@ -1592,8 +1567,8 @@ 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 + 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; @@ -1617,7 +1592,7 @@ \begin{codeblock} #define A #define B defined(A) -#if B // Undefined behavior, defined is generated by macro replacement for controlling expression +#if B // undefined behavior, \tcode{defined} is generated by macro replacement for controlling expression #endif \end{codeblock} \end{example} @@ -1633,7 +1608,7 @@ \pnum \begin{example} \begin{codeblock} -#include " // Undefined behavior, does not match one of the two allowable forms +#include " // undefined behavior, does not match one of the allowable forms \end{codeblock} \end{example} @@ -1652,11 +1627,11 @@ void f(int x) { M(x, -#ifdef D // Undefined behavior, preprocessing directive +#ifdef D // undefined behavior, preprocessing directive 16 -#else // Undefined behavior, preprocessing directive +#else // undefined behavior, preprocessing directive 32 -#endif // Undefined behavior, preprocessing directive +#endif // undefined behavior, preprocessing directive ); } @@ -1678,7 +1653,7 @@ \begin{example} \begin{codeblock} #define s_lit(x) #x -s_lit( \ ) // Stringizes to "\tcode{\textbackslash}"", which is not a valid token. +s_lit( \ ) // stringizes to "\tcode{\textbackslash}"", which is not a valid token \end{codeblock} \end{example} @@ -1726,7 +1701,7 @@ \pnum \begin{example} \begin{codeblock} -#line 4294967295 // Undefined behavior, number greater than 2147483647 +#line 4294967295 // undefined behavior, number greater than 2147483647 int main() { return notdefined; } \end{codeblock} From e48cdb8acafa18c92c229ba30e6855f97314ef71 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 11:57:37 +0200 Subject: [PATCH 226/258] [ifndr] Fix cross-references --- source/ifndr.tex | 14 +++++++------- source/ub.tex | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 9822d49f10..90067d8890 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -317,8 +317,8 @@ \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 (6.3) in which it is -implicitly instantiated (13.9.2) unless the corresponding specialization is explicitly instantiated (13.9.3) in +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 @@ -342,7 +342,7 @@ \pnum \ifndrxref{temp.arg.template.sat.constraints} \\ -Any partial specializations (13.7.6) associated with the primary template are considered when a specialization +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. @@ -460,8 +460,8 @@ \pnum \ifndrxref{temp.names.sat.constraints} \\ When the template-name of a simple-template-id names a constrained non-function template or a constrained -template template-parameter, and all template-arguments in the simple-template-id are non-dependent (13.8.3.5), -the associated constraints (13.5.3) of the constrained template shall be satisfied (13.5.2). +template template-parameter, and all template-arguments in the simple-template-id are non-dependent\iref{temp.dep.temp}, +the associated constraints\iref{temp.constr.decl} of the constrained template shall be satisfied\iref{temp.constr.constr}. \pnum \begin{example} @@ -506,7 +506,7 @@ \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 (13.8.4.1) but is not found by lookup for the specialization, the program is ill-formed, no +specialization\iref{temp.point} but is not found by lookup for the specialization, the program is ill-formed, no diagnostic required. \pnum @@ -557,7 +557,7 @@ \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 (13.9.2) in the translation unit shall be the subject of an explicit instantiation definition +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 diff --git a/source/ub.tex b/source/ub.tex index 88500685c7..dbe5b3f58c 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -1262,7 +1262,7 @@ }; void g() { - Y y = {{1, 2}}; // OK, \tcode{y.x} is active union member\iref{11.4} + Y y = {{1, 2}}; // OK, \tcode{y.x} is active union member\iref{class.mem} int n = y.x.a; y.k = 4; // OK, ends lifetime of \tcode{y.x}, \tcode{y.k} is active member of union y.x.b = n; // undefined behavior: \tcode{y.x.b} modified outside its lifetime, @@ -1709,7 +1709,7 @@ \pnum \ubxref{cpp.line.pptoken.not.match} \\ -When using the \grammarterm{pp-token} variant of the \tcode{\#line} directive, if the directive resulting after all replacements does not match +When using the \grammarterm{pp-tokens} variant of the \tcode{\#line} directive, if the directive resulting after all replacements does not match one of the two previous forms, the behavior is undefined. \pnum From d0cb955890393acb954b6199a92aae30731442d4 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 13:41:22 +0200 Subject: [PATCH 227/258] [ub] Replace non-ASCII chars --- source/ub.tex | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index dbe5b3f58c..def014e697 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -460,7 +460,7 @@ \pnum \ubxref{expr.call.different.type} \\ Calling a function through an expression whose function type is different from the function type of the called -function’s definition results in undefined behavior. +function's definition results in undefined behavior. \pnum \begin{example} @@ -814,7 +814,7 @@ \pnum \ubxref{expr.add.polymorphic} \\ -For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array +For addition or subtraction, if the expressions 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 @@ -1183,8 +1183,8 @@ \pnum \ubxref{class.dtor.not.class.type} \\ The invocation of a destructor is subject to the usual rules for -member functions \iref{class.mfct}; that is, if the object is not of the destructor’s class type and not of a class derived -from the destructor’s class type (including when the destructor is invoked via a null pointer value), the +member functions \iref{class.mfct}; that is, if the object is not of the destructor's class type and not of a class derived +from the destructor's class type (including when the destructor is invoked via a null pointer value), the program has undefined behavior. \pnum @@ -1266,7 +1266,7 @@ int n = y.x.a; y.k = 4; // OK, ends lifetime of \tcode{y.x}, \tcode{y.k} is active member of union y.x.b = n; // undefined behavior: \tcode{y.x.b} modified outside its lifetime, - // \tcode{S(y.x.b)} is empty because \tcode{X}’s default constructor is deleted, + // \tcode{S(y.x.b)} is empty because \tcode{X}'s default constructor is deleted, // so union member \tcode{y.x}'s lifetime does not implicitly start } \end{codeblock} @@ -1366,7 +1366,7 @@ 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 +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} @@ -1423,11 +1423,11 @@ \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 +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. +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 +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 @@ -1467,7 +1467,7 @@ \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. +destructor's class nor one of its bases, the behavior is undefined. \pnum \begin{example} @@ -1498,7 +1498,7 @@ \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} +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 @@ -1668,10 +1668,10 @@ \pnum \begin{example} \begin{codeblock} -#define GUARD_NAME ï ## _GUARD // Undefined behavior, character sequence produced contains - // a universal-character-name -#define COLUMN ï ##_column // Undefined behavior, character sequence produced contains - // a universal-character-name +#define GUARD_NAME ï ## _GUARD // undefined behavior, character sequence produced contains + // a \grammarterm{universal-character-name} +#define COLUMN ï ##_column // undefined behavior, character sequence produced contains + // a \grammarterm{universal-character-name} \end{codeblock} \end{example} From e9ce55d0e8018c8c2143bdfa27b7592d25f226ae Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sun, 6 Apr 2025 08:26:55 +0200 Subject: [PATCH 228/258] [check] Handle ub/ifndr labels --- tools/check-output.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/check-output.sh b/tools/check-output.sh index 8b23f65141..280fc1d423 100755 --- a/tools/check-output.sh +++ b/tools/check-output.sh @@ -36,7 +36,7 @@ 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 From 24dbef30a09b1381fe624c685b66058a577bdc03 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 11 Apr 2025 16:30:42 +0200 Subject: [PATCH 229/258] [check] Exclude [ub] and [ifndr] from sibling checking for now --- tools/check-source.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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:&/" | From 43476f429e14a220b89edf1adf8406dc9b764f99 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 5 Apr 2025 19:21:37 +0200 Subject: [PATCH 230/258] [ub.cpp.concat] Remove universal-character-name formation from ##; now well-defined --- source/ub.tex | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index def014e697..e67b430d6c 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -1660,21 +1660,6 @@ \rSec2[ub.cpp.concat]{The \#\# operator} -\pnum -\ubxref{cpp.concat.universal.char} \\ -If a character sequence that matches the syntax of a \grammarterm{universal-character-name} -is produced by token concatenation \iref{cpp.concat}, the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define GUARD_NAME ï ## _GUARD // undefined behavior, character sequence produced contains - // a \grammarterm{universal-character-name} -#define COLUMN ï ##_column // undefined behavior, character sequence produced contains - // a \grammarterm{universal-character-name} -\end{codeblock} -\end{example} - \pnum \ubxref{cpp.concat.invalid.preprocessing.token} \\ If an invalid preprocessing token results from using the concat operator the behavior is undefined. From eb687a9021ba43a0b86fcd61afbab33a6b33ad62 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sun, 6 Apr 2025 10:46:03 +0200 Subject: [PATCH 231/258] [ifndr] Use codeblocktu --- source/ifndr.tex | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 90067d8890..4bdc7199e2 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -180,19 +180,18 @@ \pnum \ifndrxref{dcl.align.diff.translation.units} \\ -No diagnostic is required if declarations of an entity have different alignment-specifiers in different +No diagnostic is required if declarations of an entity have different \grammarterm{alignment-specifier}s in different translation units. \pnum \begin{example} -\begin{codeblock} -// Translation unit \#1: +\begin{codeblocktu}{Translation unit \#1} struct S { int x; } s, *p = &s; - -// Translation unit \#2: +\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{codeblock} +\end{codeblocktu} \end{example} \rSec2[ifndr.dcl.attr.noreturn]{Noreturn attribute} @@ -202,14 +201,12 @@ \pnum \begin{example} -\begin{codeblock} -/* Translation Unit A */ -[[noreturn]] void f() { -} - -/* Translation Unit B */ -struct void f(int i); // ill-formed no diagnostic required, declared without noreturn -\end{codeblock} +\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} @@ -218,9 +215,9 @@ \pnum \ifndrxref{module.unit.reserved.identifiers} \\ -All module-names either beginning with an identifier consisting of -std followed by zero or more digits or containing a reserved identifier (5.10) are reserved and shall not be -specified in a module-declaration; no diagnostic is required. +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} From 08fddc1955094657e157fb24eca01749ed10eecd Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sun, 13 Apr 2025 21:35:33 +0200 Subject: [PATCH 232/258] Rename label expr.ass.overlap to expr.assign.overlap --- source/expressions.tex | 2 +- source/ub.tex | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index cfc3652ca2..03eb88f9e9 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -8288,7 +8288,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\ubdef{expr.ass.overlap}. +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 diff --git a/source/ub.tex b/source/ub.tex index e67b430d6c..09eb603193 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -860,10 +860,10 @@ \end{example} -\rSec2[ub.expr.ass]{Assignment and compound assignment operators} +\rSec2[ub.expr.assign]{Assignment and compound assignment operators} \pnum -\ubxref{expr.ass.overlap} \\ +\ubxref{expr.assign.overlap} \\ Overlap in the storage between the source and destination may result in undefined behavior. \pnum From 4e12d8bbc055a16496b46a5c0cdef6d4a95088ac Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Mon, 14 Apr 2025 17:53:12 +0200 Subject: [PATCH 233/258] [ub.basic.stc.dynamic] Fix typo --- source/ub.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ub.tex b/source/ub.tex index 09eb603193..030bdaed4e 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -220,7 +220,7 @@ \end{example} -\rSec2[ub.basic.stc.dynamic]{Dyanmic storage Duration} +\rSec2[ub.basic.stc.dynamic]{Dynamic storage Duration} \pnum \ubxref{basic.stc.alloc.dealloc.constraint} \\ From d8888c7ffff15acc130250f8ece7a3c1a65ade58 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Tue, 22 Apr 2025 22:27:42 +0200 Subject: [PATCH 234/258] [ub] Fix some formatting (#7828) --- source/ub.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index 030bdaed4e..b2a41ab141 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -31,8 +31,8 @@ }; X* make_x() { - // The call to std::malloc can not implicitly create an object of type X - // because X is not an implicit-lifetime class. + // 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; @@ -289,7 +289,7 @@ \pnum \ubxref{basic.start.main.exit.during.destruction} \\ -If std::exit is called to +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. @@ -305,7 +305,7 @@ Exiter ex; // int main() {} -// Undefined behavior when destructor of static variable ex is called it will call std::exit +// undefined behavior when destructor of static variable \tcode{ex} is called it will call \tcode{std::exit} \end{codeblock} \end{example} @@ -339,8 +339,8 @@ B b; int main() {} -// Undefined behavior, static objects are destructed in reverse order, in this case a then b and -// finally c. When the destructor of c is call it calls f() which passes through definition of +// 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} From 6a9a2f451142bc74f7d3272fae3ddf58f7d04059 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Apr 2025 07:22:26 +0200 Subject: [PATCH 235/258] Remove class.dtor.not.class.type (#7835) --- source/classes.tex | 2 +- source/ub.tex | 42 ------------------------------------------ 2 files changed, 1 insertion(+), 43 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index aad31010e3..b315b7ab83 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -2264,7 +2264,7 @@ that is, if the object is not of the destructor's class type and not of a class derived from the destructor's class type (including when the destructor is invoked via a null pointer value), the program has -undefined behavior\ubdef{class.dtor.not.class.type}. +undefined behavior. \begin{note} Invoking \keyword{delete} on a null pointer does not call the destructor; see \ref{expr.delete}. diff --git a/source/ub.tex b/source/ub.tex index b2a41ab141..b58e5ffc2a 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -1180,48 +1180,6 @@ \rSec2[ub.class.dtor]{Destructors} -\pnum -\ubxref{class.dtor.not.class.type} \\ -The invocation of a destructor is subject to the usual rules for -member functions \iref{class.mfct}; that is, if the object is not of the destructor's class type and not of a class derived -from the destructor's class type (including when the destructor is invoked via a null pointer value), the -program has undefined behavior. - -\pnum -\begin{example} -\begin{codeblock} -#include - -struct X {}; - -void f() { - X *x = nullptr; - x->~X(); // undefined behavior, invoked using a null pointer value -} - -struct Y {}; -void h() { - alignas(X) char buf[sizeof(X)]; - X *p = new (buf) X(); // use \tcode{buf[] }and initialize - - Y *yp = reinterpret_cast(p); - yp->Y::~Y(); // undefined behavior, destructor of \tcode{Y} called for object of type \tcode{X} -} - -struct Base { - virtual ~Base(); -}; -struct Derived : Base {}; - -int k() { - Base *b = new Base; - Derived *d = static_cast(b); - d->~Derived(); // undefined behavior, destructor of Derived call for object of - // type \tcode{Base} -} -\end{codeblock} -\end{example} - \pnum \ubxref{class.dtor.no.longer.exists} \\ Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the From 2ba186d383a0c41e6b432ba1e119180e9f2f1761 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Apr 2025 07:23:28 +0200 Subject: [PATCH 236/258] Remove incorrect class.union.assignment.not.start.lifetime (#7833) --- source/classes.tex | 2 +- source/ub.tex | 31 ------------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/source/classes.tex b/source/classes.tex index b315b7ab83..88a12b3083 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -3211,7 +3211,7 @@ each anonymous union member \tcode{X}\iref{class.union.anon} that is a member of a union and has such an element as an immediate subobject (recursively), -if modification of \tcode{X} would have undefined behavior\ubdef{class.union.assignment.not.start.lifetime} under~\ref{basic.life}, +if modification of \tcode{X} would have undefined behavior under~\ref{basic.life}, an object of the type of \tcode{X} is implicitly created in the nominated storage; no initialization is performed and diff --git a/source/ub.tex b/source/ub.tex index b58e5ffc2a..1388ede0d5 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -1200,37 +1200,6 @@ \end{example} -\rSec2[ub.class.union]{Unions} - -\pnum -\ubxref{class.union.assignment.not.start.lifetime} \\ -Assigning to a union member may not start its lifetime, in that case using it will result in undefined behavior. - -\pnum -\begin{example} -\begin{codeblock} -struct X { - const int a; - int b; -}; - -union Y { - X x; - int k; -}; - -void g() { - Y y = {{1, 2}}; // OK, \tcode{y.x} is active union member\iref{class.mem} - int n = y.x.a; - y.k = 4; // OK, ends lifetime of \tcode{y.x}, \tcode{y.k} is active member of union - y.x.b = n; // undefined behavior: \tcode{y.x.b} modified outside its lifetime, - // \tcode{S(y.x.b)} is empty because \tcode{X}'s default constructor is deleted, - // so union member \tcode{y.x}'s lifetime does not implicitly start -} -\end{codeblock} -\end{example} - - \rSec2[ub.class.abstract]{Abstract classes} \pnum From f47a95ce66f1220a57fd4c279d9802accb8fe212 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sun, 4 May 2025 07:40:39 +0200 Subject: [PATCH 237/258] [ub.general,ifndr.general] Avoid hanging paragraphs by introducing 'General' subclauses (#7848) --- source/ifndr.tex | 2 ++ source/ub.tex | 2 ++ 2 files changed, 4 insertions(+) diff --git a/source/ifndr.tex b/source/ifndr.tex index 4bdc7199e2..da465bf423 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -1,6 +1,8 @@ %!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 diff --git a/source/ub.tex b/source/ub.tex index 1388ede0d5..e8f445d6f7 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -1,6 +1,8 @@ %!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 From 9f56f561442e9fa7c79094aebea92e60cef59d9d Mon Sep 17 00:00:00 2001 From: Joshua Berne Date: Wed, 14 May 2025 17:38:13 -0400 Subject: [PATCH 238/258] [ub] Add many missing entries to UB annex (#7864) Co-authored-by: jberne4 --- source/basic.tex | 10 +- source/classes.tex | 5 +- source/declarations.tex | 6 +- source/expressions.tex | 29 +-- source/ub.tex | 382 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 400 insertions(+), 32 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index e3bb0699e6..3611f0285e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3840,7 +3840,7 @@ 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 @@ -4257,7 +4257,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: @@ -4584,7 +4584,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 @@ -4707,7 +4707,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. @@ -6087,7 +6087,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 diff --git a/source/classes.tex b/source/classes.tex index 88a12b3083..a697bff79d 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -6033,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\ubdef{class.cdtor.before.ctor.after.dtor}. 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; }; diff --git a/source/declarations.tex b/source/declarations.tex index 2c89286ac4..d06863ebc7 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -3285,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 @@ -3303,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&); diff --git a/source/expressions.tex b/source/expressions.tex index 03eb88f9e9..b35a8679b0 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -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() { @@ -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\ubdef{conv.fpint.not.represented} 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,8 @@ 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 +1078,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 +1112,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 @@ -4392,7 +4394,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\ubdef{expr.ref.not.similar}. +the behavior is undefined\ubdef{expr.ref.member.not.similar}. \begin{example} \begin{codeblock} struct A { int i; }; @@ -4528,7 +4530,7 @@ 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.lifetime} \pnum If \tcode{T} is ``pointer to \cv{} \keyword{void}'', then the result @@ -4848,7 +4850,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\ubdef{expr.static.cast.downcast.wrong.derived.type}. +Otherwise, the behavior is undefined\ubdef{expr.static.cast.fp.outside.range}. \pnum \indextext{cast!base class}% @@ -4869,7 +4871,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}% @@ -5270,7 +5272,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} @@ -7340,7 +7343,7 @@ \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\ubdef{expr.add.polymorphic}. +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}; diff --git a/source/ub.tex b/source/ub.tex index e8f445d6f7..fa3e3f42a3 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -64,6 +64,26 @@ \end{codeblock} \end{example} +\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 +} +\end{codeblock} +\end{example} + \rSec2[ub.basic.life]{Object lifetime} \pnum @@ -221,13 +241,34 @@ \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 \iref{basic.stc.dynamic.allocation} and \iref{basic.stc.dynamic.deallocation}, the behavior is undefined. +If the behavior of an allocation or deallocation function does not satisfy the semantic constraints +specified +in \iref{basic.stc.dynamic.allocation} and \iref{basic.stc.dynamic.deallocation}. +the behavior is undefined. + \pnum \begin{example} @@ -246,6 +287,71 @@ \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 @@ -385,8 +491,10 @@ \pnum \ubxref{expr.basic.lvalue.strict.aliasing.violation} \\ -If a program attempts to access \iref{defns.access} the stored value of an object through a glvalue whose type is not -similar \iref{conv.rval} to one of the following types the behavior is undefined +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} @@ -406,6 +514,67 @@ \end{codeblock} \end{example} +\pnum +\ubxref{expr.basic.lvalue.union.initialization} \\ +If a program invokes a defaulted copy/move constructor or 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} @@ -426,7 +595,6 @@ // represetable 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} @@ -434,7 +602,8 @@ \rSec2[ub.conv.fpint]{Floating-integral conversions} \pnum -\ubxref{conv.fpint.not.represented} \\ +\ubxref{conv.fpint.float.not.represented} \\ +%\ubxref{conv.fpint.int.not.represented} \\ % in same section 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. @@ -457,6 +626,59 @@ \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 @@ -484,7 +706,7 @@ \rSec2[ub.expr.ref]{Class member access} \pnum -\ubxref{expr.ref.not.similar} \\ +\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. @@ -501,6 +723,25 @@ \end{codeblock} \end{example} +\rSec2[ub.expr.dynamic.cast]{Dynamic cast} + +\pnum +\ubxref{expr.dynamic.cast.lifetime} \\ +Evaluating a \keyword{dynamic_cast} on a non-null pointer or reference that +denotes an object (of polymorphic type) of the wrong type or that is +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 + B& dr = dynamic_cast(bs[1]); // undefined behavior +} +\end{codeblock} +\end{example} \rSec2[ub.expr.static.cast]{Static cast} @@ -541,6 +782,31 @@ \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} +\begin{codeblock} +void f() { + double d = FLT_MAX * 16; + d *= 16; + float f = static_cast(d); // undefined behavior. +} +\end{codeblock} +\end{example} + + +\pnum +\begin{example} +\begin{codeblock} + +\end{codeblock} +\end{example} + \pnum \ubxref{expr.static.cast.downcast.wrong.derived.type} \\ Down-casting to the wrong derived type is undefined behavior. @@ -585,6 +851,24 @@ \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} @@ -815,7 +1099,7 @@ \end{example} \pnum -\ubxref{expr.add.polymorphic} \\ +\ubxref{expr.add.not.similar} \\ For addition or subtraction, if the expressions 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. @@ -1018,6 +1302,57 @@ \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 ir1 = 17; +\end{codeblock} +\end{example} + + + \rSec2[ub.dcl.fct.def.coroutine]{Coroutine definitions} @@ -1269,7 +1604,7 @@ \rSec2[ub.class.cdtor]{Construction and destruction} \pnum -\ubxref{class.cdtor.before.ctor.after.dtor} \\ +\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. 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 @@ -1318,6 +1653,35 @@ \end{example} +\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*p = px->i; // undefined behavior +} +\end{codeblock} +\end{example} + + \pnum \ubxref{class.cdtor.convert.or.form.pointer} \\ When converting a pointer to a base class of an object or forming a pointer to a direct non-static From bc7bd9838d320a44be9421c3e4b294253e5c3714 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 16 May 2025 14:49:15 +0200 Subject: [PATCH 239/258] [conv.fpint] Remove unreferenced \ubdef that causes an undefined symbol error --- source/expressions.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/expressions.tex b/source/expressions.tex index b35a8679b0..be6170499e 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -1024,7 +1024,8 @@ 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.\ubdef{conv.fpint.int.not.represented} +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. From b5d6c3334f3e4796df9914ecdd5b6af3f18e5a3b Mon Sep 17 00:00:00 2001 From: Joshua Berne Date: Wed, 28 May 2025 17:50:12 -0400 Subject: [PATCH 240/258] [ub] small fixes to examples (#7890) --- source/ub.tex | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index fa3e3f42a3..5dc126bab8 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -790,9 +790,13 @@ \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 * 16; + double d = FLT_MAX; d *= 16; float f = static_cast(d); // undefined behavior. } @@ -800,13 +804,6 @@ \end{example} -\pnum -\begin{example} -\begin{codeblock} - -\end{codeblock} -\end{example} - \pnum \ubxref{expr.static.cast.downcast.wrong.derived.type} \\ Down-casting to the wrong derived type is undefined behavior. @@ -1347,7 +1344,8 @@ \begin{codeblock} extern int &ir1; int i2 = ir1; // undefined behavior, \tcode{ir1} not yet initialized -int ir1 = 17; +int i3 = 17; +int &ir1 = i3; \end{codeblock} \end{example} @@ -1674,9 +1672,9 @@ } void f() { - X& px = &g(); + X* px = &g(); px->~X(); - int*p = px->i; // undefined behavior + int j = px->i; // undefined behavior } \end{codeblock} \end{example} From 02951bca2d2aacc2922e5705dceeab828a76b9f6 Mon Sep 17 00:00:00 2001 From: Timur Doumler Date: Sat, 21 Jun 2025 13:19:10 +0300 Subject: [PATCH 241/258] [ub] Added all missing ubdefs to bring UB annex in line with P3100R2 list (#7888) --- source/basic.tex | 23 +-- source/classes.tex | 4 +- source/expressions.tex | 8 +- source/ifndr.tex | 4 +- source/ub.tex | 399 +++++++++++++++++++++++++++++------------ 5 files changed, 304 insertions(+), 134 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 3611f0285e..c8341a6d07 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3786,7 +3786,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. @@ -4029,19 +4029,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\ubdef{lifetime.outside.pointer} 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} @@ -4084,14 +4085,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\ubdef{lifetime.outside.glvalue} 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} diff --git a/source/classes.tex b/source/classes.tex index a697bff79d..bc9a4d0b20 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -6121,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}, @@ -6129,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\ubdef{class.cdtor.convert.or.form.pointer}. +value) results in undefined behavior\ubdef{class.cdtor.form.pointer}. \begin{example} \begin{codeblock} struct A { }; diff --git a/source/expressions.tex b/source/expressions.tex index be6170499e..9303830899 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -1025,7 +1025,7 @@ \end{note} If the value being converted is outside the range of values that can be represented, the behavior is undefined. -% \ubdef{conv.fpint.int.not.represented} +\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. @@ -4524,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.\ubdef{expr.dynamic.cast.lifetime} +the behavior is undefined.\ubdef{expr.dynamic.cast.glvalue.lifetime} \pnum If \tcode{T} is ``pointer to \cv{} \keyword{void}'', then the result @@ -6544,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 diff --git a/source/ifndr.tex b/source/ifndr.tex index da465bf423..dd9422b209 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -39,7 +39,7 @@ \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. +that program outside of a discarded statement\iref{stmt.if}; no diagnostic required. \pnum \begin{example} @@ -59,7 +59,7 @@ \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 +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. diff --git a/source/ub.tex b/source/ub.tex index 5dc126bab8..349fc30705 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -19,10 +19,36 @@ \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 +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} @@ -87,32 +113,10 @@ \rSec2[ub.basic.life]{Object lifetime} \pnum -\ubxref{lifetime.outside.pointer} \\ -The behavior of some uses of a pointer -pointing to an object outside its lifetime -are not defined: -\begin{itemize} -\item - 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}, -\item - the pointer is used to access a non-static data member or call a - non-static member function of the object, or -\item - the pointer is implicitly converted\iref{conv.ptr} to a pointer - to a virtual base class, or -\item - the pointer is used as the operand of a - \tcode{static_cast}\iref{expr.static.cast}, except when the conversion - is to pointer to \cv{}~\tcode{void}, or to pointer to \cv{}~\tcode{void} - and subsequently to pointer to - \cv{}~\tcode{char}, - \cv{}~\tcode{unsigned char}, or - \cv{}~\tcode{std::byte}\iref{cstddef.syn}, or -\item - the pointer is used as the operand of a - \tcode{dynamic_cast}\iref{expr.dynamic.cast}. -\end{itemize} +\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} @@ -122,79 +126,185 @@ ~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* p1 = &s; - S* p2 = new S; + S* p = &s; s.~S(); - p2->~S(); - delete p2; // undefined behavior, operand of delete, lifetime has ended and \tcode{S} - // has a non-trivial destructor - return p1->f; // Undefined behavior, accessing non-static data member after - // end of lifetime + 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 pointer is implicitly converted\iref{conv.ptr} to a pointer +to a virtual base class. + +\pnum \begin{example} \begin{codeblock} -#include -#include - -struct B { - virtual void f(); - void mutate(); - virtual ~B(); -}; +struct B {}; +struct D : virtual B {}; +void f() { + D d; + D* p = &d; + d.~D(); + B* b = p; // undefined behavior +} +\end{codeblock} +\end{example} -struct D1 : B { - void f(); -}; -struct D2 : B { - void f(); -}; +\pnum +\ubxref{lifetime.outside.pointer.static.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{static_cast}, except when the conversion +is to pointer to \cv{}~\tcode{void}, or to pointer to \cv{}~\tcode{void} +and subsequently to pointer to +\cv{}~\tcode{char}, +\cv{}~\tcode{unsigned char}, or +\cv{}~\tcode{std::byte}\iref{cstddef.syn}. -void B::mutate() { - new (this) D2; // reuses storage and ends the lifetime of *this - f(); // undefined behavior - B *b = this; // OK, this points to valid memory +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : B {}; +void f() +{ + D d; + B* bp = &d; + d.~D(); + void* vp = bp; // OK + D* dp = static_cast(bp); // undefined behavior } +\end{codeblock} +\end{example} -void g() { - void* p = std::malloc(sizeof(D1) + sizeof(D2)); - B* pb = new (p) D1; - pb->mutate(); - *pb; // OK, pb points to valid memory - void* q = pb; // OK, pb points to valid memory - pb->f(); // undefined behavior, lifetime of \tcode{*pb} has ended +\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} \\ -The behavior of some uses of a glvalue -that refers to an object outside its lifetime -are not defined. +\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} -struct A{void f(){} }; - void f() { int x = int{10}; - A a; using T = int; x.~T(); - a.~A(); - a.f(); // undefined behavior, glvalue used to access a - // non-static member function after the lifetime has ended 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} \\ @@ -266,7 +376,7 @@ \ubxref{basic.stc.alloc.dealloc.constraint} \\ If the behavior of an allocation or deallocation function does not satisfy the semantic constraints specified -in \iref{basic.stc.dynamic.allocation} and \iref{basic.stc.dynamic.deallocation}. +in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}. the behavior is undefined. @@ -357,9 +467,9 @@ \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 +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. +concurrent\iref{intro.multithread}, the behavior is undefined. \pnum \begin{example} @@ -380,7 +490,7 @@ \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 \iref{intro.races}. Any such data race results in undefined behavior. +signal handlers described in~\ref{intro.races}. Any such data race results in undefined behavior. \pnum \begin{example} @@ -388,7 +498,7 @@ 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 +// undefined behavior t1, t2 and t3 have a data race on access of variable count \end{codeblock} \end{example} @@ -456,9 +566,9 @@ \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. +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} @@ -491,9 +601,9 @@ \pnum \ubxref{expr.basic.lvalue.strict.aliasing.violation} \\ -If a program attempts to access \iref{defns.access} the stored value of an object +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) +similar\iref{conv.rval} to $T$ (or its corresponding signed or unsigned types) the behavior is undefined. \pnum @@ -602,8 +712,7 @@ \rSec2[ub.conv.fpint]{Floating-integral conversions} \pnum -\ubxref{conv.fpint.float.not.represented} \\ -%\ubxref{conv.fpint.int.not.represented} \\ % in same section +\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. @@ -617,11 +726,24 @@ // 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 + // representable values of float is [-max,+max] on system where + // represetable values are [-inf,+inf] this would not be UB } \end{codeblock} \end{example} @@ -725,10 +847,11 @@ \rSec2[ub.expr.dynamic.cast]{Dynamic cast} + \pnum -\ubxref{expr.dynamic.cast.lifetime} \\ -Evaluating a \keyword{dynamic_cast} on a non-null pointer or reference that -denotes an object (of polymorphic type) of the wrong type or that is +\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 @@ -738,6 +861,23 @@ 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} @@ -768,7 +908,7 @@ \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 +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 @@ -872,7 +1012,7 @@ \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. +function is a non-allocating form\iref{new.delete.placement} that returns null, the behavior is undefined. \pnum \begin{example} @@ -903,13 +1043,25 @@ \pnum \ubxref{expr.delete.mismatch} \\ -Using array delete on the result of a single object new expression and vice versa is undefined behavior. +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 +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} @@ -994,7 +1146,7 @@ \pnum \ubxref{expr.mptr.oper.member.func.null} \\ 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. \pnum \begin{example} @@ -1098,7 +1250,7 @@ \pnum \ubxref{expr.add.not.similar} \\ For addition or subtraction, if the expressions 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. +element type are not similar\iref{conv.rval}, the behavior is undefined. \pnum \begin{example} @@ -1679,34 +1831,51 @@ \end{codeblock} \end{example} - \pnum -\ubxref{class.cdtor.convert.or.form.pointer} \\ -When converting a pointer to a base class of an object or forming a pointer to a direct non-static -member of a class, construction must have started and destruction must not have finished otherwise +\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 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 }; -struct X { - X(A *); +\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 E : C, D, X { - E() - : D(this), // undefined: upcast from \tcode{E*} to \tcode{A*} might use path E->D->A - // but \tcode{D} is not constructed - // \tcode{D((C*)this)} would be defined: E->C is defined because - // \tcode{E()} has started, and C->A is defined because \tcode{C} is fully - // constructed - X(this) // well-defined: upon construction of \tcode{X}, C/B/D/A sublattice is fully constructed - {} +struct B { + int *p; + A a; + B() : p(&a.i) {} // undefined behavior }; \end{codeblock} \end{example} @@ -1717,7 +1886,7 @@ 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 +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. @@ -1858,7 +2027,7 @@ 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 + std::cout << "y: " << y << std::endl; // undefined behavior, referring to non-static member y in // the handler of function-try-block } int x; @@ -1961,7 +2130,7 @@ #define cat(x, y) x##y void f() { - cat(/, /) // Undefined behavior // is not a valid preprocessing token + cat(/, /) // undefined behavior // is not a valid preprocessing token } \end{codeblock} \end{example} From c1bac80c394e7e5e53fcdd216949279a6ef1e58c Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 26 Jul 2025 19:35:41 +0200 Subject: [PATCH 242/258] [ub] Adjust to undefined behavior removed by P2621R2 --- source/ub.tex | 143 -------------------------------------------------- 1 file changed, 143 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index 349fc30705..c248629560 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -2035,146 +2035,3 @@ }; \end{codeblock} \end{example} - - -\rSec1[ub.cpp]{\ref{cpp}: Preprocessing directives} - -\rSec2[ub.cpp.cond]{Conditional inclusion} - -\pnum -\ubxref{cpp.cond.defined} \\ -If the token defined is generated as a result of this replacement process or use of -the defined unary operator does not match one of the two specified forms prior to macro replacement, the -behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define A -#define B defined(A) -#if B // undefined behavior, \tcode{defined} is generated by macro replacement for controlling expression -#endif -\end{codeblock} -\end{example} - - -\rSec2[ub.cpp.include]{Source file inclusion} - -\pnum -\ubxref{cpp.include.one.of.two.forms} \\ -If the an include directive after replacement does not match one of the two forms -outlined [cpp.indlude]\iref{cpp.include} then the behavior is undefined - -\pnum -\begin{example} -\begin{codeblock} -#include " // undefined behavior, does not match one of the allowable forms -\end{codeblock} -\end{example} - - -\rSec2[ub.cpp.replace]{Macro replacement} - -\pnum -\ubxref{cpp.replace.macro.pptoken} \\ -If there are sequences of preprocessing tokens within the list of arguments to a function-like macro -that would otherwise act as preprocessing directives, the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define M(d, n) d = n - -void f(int x) { - M(x, -#ifdef D // undefined behavior, preprocessing directive - 16 -#else // undefined behavior, preprocessing directive - 32 -#endif // undefined behavior, preprocessing directive - ); -} - -int main() { - int x; - f(x); -} -\end{codeblock} -\end{example} - - -\rSec2[ub.cpp.stringize]{The \# operator} - -\pnum -\ubxref{cpp.stringize.invalid.char} \\ -If an invalid character results from using the stringize operator the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define s_lit(x) #x -s_lit( \ ) // stringizes to "\tcode{\textbackslash}"", which is not a valid token -\end{codeblock} -\end{example} - - -\rSec2[ub.cpp.concat]{The \#\# operator} - -\pnum -\ubxref{cpp.concat.invalid.preprocessing.token} \\ -If an invalid preprocessing token results from using the concat operator the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define cat(x, y) x##y - -void f() { - cat(/, /) // undefined behavior // is not a valid preprocessing token -} -\end{codeblock} -\end{example} - - -\rSec2[ub.cpp.line]{Line control} - -\pnum -\ubxref{cpp.line.zero.or.overflow} \\ -When using the \tcode{\#line} directive, if the digit sequence -specifies zero or a number greater than 2147483647, the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#line 4294967295 // undefined behavior, number greater than 2147483647 - -int main() { return notdefined; } -\end{codeblock} -\end{example} - -\pnum -\ubxref{cpp.line.pptoken.not.match} \\ -When using the \grammarterm{pp-tokens} variant of the \tcode{\#line} directive, if the directive resulting after all replacements does not match -one of the two previous forms, the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define cat(a, b) a##b -#line cat(10, e20) -\end{codeblock} -\end{example} - -\rSec2[ub.cpp.predefined]{Predefined macro names} - -\pnum -\ubxref{cpp.predefined.define.undef} \\ -If any of the pre-defined macro names in [cpp.predefined], or the identifier defined, is the subject of a \tcode{\#define} -or a \tcode{\#undef} preprocessing directive, the behavior is undefined. - -\pnum -\begin{example} -\begin{codeblock} -#define __cplusplus 300012L -\end{codeblock} -\end{example} From a90173f0f92378396a25e80132b038ce0d914013 Mon Sep 17 00:00:00 2001 From: Timur Doumler Date: Mon, 17 Nov 2025 10:33:37 -1000 Subject: [PATCH 243/258] [ub,intro.progress] Added entry for UB due to lack of forward progress (#8335) --- source/basic.tex | 4 ++-- source/ub.tex | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index c8341a6d07..55dca8963f 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -7075,8 +7075,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}, diff --git a/source/ub.tex b/source/ub.tex index c248629560..4adb6652e1 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -502,6 +502,29 @@ \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} From 0f1081c3f81a1b06e27e4b641715cf5f54bb671d Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sun, 11 Jan 2026 15:23:49 +0100 Subject: [PATCH 244/258] [ub] Remove lifetime.outside.pointer.static.cast This UB was removed in Kona 2025. --- source/ub.tex | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index 4adb6652e1..23da56cac6 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -178,33 +178,6 @@ \end{codeblock} \end{example} -\pnum -\ubxref{lifetime.outside.pointer.static.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{static_cast}, except when the conversion -is to pointer to \cv{}~\tcode{void}, or to pointer to \cv{}~\tcode{void} -and subsequently to pointer to -\cv{}~\tcode{char}, -\cv{}~\tcode{unsigned char}, or -\cv{}~\tcode{std::byte}\iref{cstddef.syn}. - -\pnum -\begin{example} -\begin{codeblock} -struct B {}; -struct D : B {}; -void f() -{ - D d; - B* bp = &d; - d.~D(); - void* vp = bp; // OK - D* dp = static_cast(bp); // 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 From 670789f1af493359a74a0ed2617d49c726dab7e1 Mon Sep 17 00:00:00 2001 From: Joshua Berne Date: Tue, 20 Jan 2026 16:50:58 -0500 Subject: [PATCH 245/258] [ub] and [ifndr] remove extra line breaks after ubxref and ifndrxref (#8716) --- source/ifndr.tex | 52 ++++++++--------- source/ub.tex | 145 +++++++++++++++++++++++------------------------ 2 files changed, 97 insertions(+), 100 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index dd9422b209..0185e2ccfa 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -14,7 +14,7 @@ \rSec2[ifndr.lex.name]{Identifiers} \pnum -\ifndrxref{lex.name.reserved} \\ +\ifndrxref{lex.name.reserved} Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no diagnostic is required. @@ -37,7 +37,7 @@ \rSec2[ifndr.basic.def.odr]{One-definition rule} \pnum -\ifndrxref{basic.def.odr.exact.one.def} \\ +\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. @@ -57,7 +57,7 @@ \pnum -\ifndrxref{basic.def.odr.unnamed.enum.same.type} \\ +\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. @@ -84,7 +84,7 @@ \rSec2[ifndr.class.member.lookup]{Member name lookup} \pnum -\ifndrxref{class.member.lookup.name.refers.diff.decl} \\ +\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 @@ -131,7 +131,7 @@ \rSec2[ifndr.expr.prim.req]{Requires expressions} \pnum -\ifndrxref{expr.prim.req.always.sub.fail} \\ +\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. @@ -151,7 +151,7 @@ \rSec2[ifndr.stmt.ambig]{Ambiguity resolution} \pnum -\ifndrxref{stmt.ambig.bound.diff.parse} \\ +\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. @@ -181,7 +181,7 @@ \rSec2[ifndr.dcl.align]{Alignment specifier} \pnum -\ifndrxref{dcl.align.diff.translation.units} \\ +\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. @@ -199,9 +199,7 @@ \rSec2[ifndr.dcl.attr.noreturn]{Noreturn attribute} \pnum -\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} \\ - -\pnum +\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} \begin{example} \begin{codeblocktu}{Translation unit \#1} [[noreturn]] void f() {} @@ -216,7 +214,7 @@ \rSec2[ifndr.module.unit]{Module units and purviews} \pnum -\ifndrxref{module.unit.reserved.identifiers} \\ +\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. @@ -234,7 +232,7 @@ \pnum -\ifndrxref{module.unit.named.module.no.partition} \\ +\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. @@ -253,7 +251,7 @@ \rSec2[ifndr.class.base.init]{Initializing bases and members} \pnum -\ifndrxref{class.base.init.delegate.itself} \\ +\ifndrxref{class.base.init.delegate.itself} If a constructor delegates to itself directly or indirectly, the program is ill-formed, no diagnostic required @@ -273,7 +271,7 @@ \rSec2[ifndr.class.virtual]{Virtual functions} \pnum -\ifndrxref{class.virtual.pure.or.defined} \\ +\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 @@ -296,7 +294,7 @@ \rSec2[ifndr.over.literal]{User-defined literals} \pnum -\ifndrxref{over.literal.reserved} \\ +\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. @@ -314,7 +312,7 @@ \rSec2[ifndr.temp.pre]{Preamble} \pnum -\ifndrxref{temp.pre.reach.def} \\ +\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 @@ -340,7 +338,7 @@ \rSec2[ifndr.temp.arg.template]{Template template arguments} \pnum -\ifndrxref{temp.arg.template.sat.constraints} \\ +\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 @@ -372,7 +370,7 @@ \rSec2[ifndr.constr.atomic]{Atomic constraints} \pnum -\ifndrxref{temp.constr.atomic.equiv.but.not.equiv} \\ +\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. @@ -392,7 +390,7 @@ \end{example} \pnum -\ifndrxref{temp.constr.atomic.sat.result.diff} \\ +\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 @@ -413,7 +411,7 @@ \rSec2[ifndr.temp.constr.normal]{Constraint normalization} \pnum -\ifndrxref{temp.constr.normal.invalid} \\ +\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 @@ -431,7 +429,7 @@ \rSec2[ifndr.temp.spec.partial]{Partial specialization} \pnum -\ifndrxref{temp.spec.partial.general.partial.reachable} \\ +\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. @@ -457,7 +455,7 @@ \rSec2[ifndr.temp.names]{Names of template specializations} \pnum -\ifndrxref{temp.names.sat.constraints} \\ +\ifndrxref{temp.names.sat.constraints} When the template-name of a simple-template-id names a constrained non-function template or a constrained template template-parameter, and all template-arguments in the simple-template-id are non-dependent\iref{temp.dep.temp}, the associated constraints\iref{temp.constr.decl} of the constrained template shall be satisfied\iref{temp.constr.constr}. @@ -481,7 +479,7 @@ \rSec3[ifndr.temp.over.link]{Function template overloading} \pnum -\ifndrxref{temp.over.link.equiv.not.equiv} \\ +\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. @@ -502,7 +500,7 @@ \rSec3[ifndr.temp.res.general]{General} \pnum -\ifndrxref{temp.res.general.default.but.not.found} \\ +\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 @@ -519,7 +517,7 @@ \rSec3[ifndr.temp.point]{Point of instantiation} \pnum -\ifndrxref{temp.point.diff.pt.diff.meaning} \\ +\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 @@ -553,7 +551,7 @@ \rSec2[ifndr.temp.explicit]{Explicit instantiation} \pnum -\ifndrxref{temp.explicit.decl.implicit.inst} \\ +\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 @@ -578,7 +576,7 @@ \rSec3[ifndr.temp.deduct.general]{General} \pnum -\ifndrxref{temp.deduct.general.diff.order} \\ +\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. diff --git a/source/ub.tex b/source/ub.tex index 23da56cac6..d913666ede 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -93,7 +93,7 @@ \rSec2[ub.basic.align]{Object alignment} \pnum -\ubxref{basic.align.object.alignment} \\ +\ubxref{basic.align.object.alignment} All instances of a type must be created in storage that meets the alignment requirement of that type. @@ -280,7 +280,7 @@ \end{example} \pnum -\ubxref{original.type.implicit.destructor} \\ +\ubxref{original.type.implicit.destructor} The behavior of an implicit destructor call when the type that is not the original type occupies the storage. @@ -302,7 +302,7 @@ \pnum -\ubxref{creating.within.const.complete.obj} \\ +\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 @@ -327,7 +327,7 @@ \rSec2[ub.basic.indet]{Indeterminate and erroneous values} \pnum -\ubxref{basic.indet.value} \\ +\ubxref{basic.indet.value} When the result of an evaluation is an indeterminate value (but not just an erroneous value) @@ -346,7 +346,7 @@ \rSec2[ub.basic.stc.dynamic]{Dynamic storage Duration} \pnum -\ubxref{basic.stc.alloc.dealloc.constraint} \\ +\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}. @@ -371,7 +371,7 @@ \end{example} \pnum -\ubxref{basic.stc.alloc.dealloc.throw} \\ +\ubxref{basic.stc.alloc.dealloc.throw} If a call to a deallocation function terminates by throwing an exception the behavior is undefined. @@ -394,7 +394,7 @@ \rSec2[ub.basic.stc.alloc.zero.dereference]{Zero-sized allocation dereference} \pnum -\ubxref{basic.stc.alloc.zero.dereference} \\ +\ubxref{basic.stc.alloc.zero.dereference} The pointer returned when invoking an allocation function with a size of zero cannot be dereferenced. @@ -412,7 +412,7 @@ \rSec2[ub.basic.compound]{Compound types} \pnum -\ubxref{basic.compound.invalid.pointer} \\ +\ubxref{basic.compound.invalid.pointer} Indirection or the invocation of a deallocation function with a pointer value referencing storage @@ -438,7 +438,7 @@ \rSec2[ub.intro.execution]{Sequential execution} \pnum -\ubxref{intro.execution.unsequenced.modification} \\ +\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 @@ -460,7 +460,7 @@ \rSec2[ub.intro.races]{Data races} \pnum -\ubxref{intro.races.data} \\ +\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. @@ -478,8 +478,7 @@ \rSec2[ub.intro.progress]{Forward progress} \pnum -\ubxref{intro.progress.stops} \\ - +\ubxref{intro.progress.stops} The behavior is undefined if a thread of execution that has not terminated stops making execution steps. @@ -502,7 +501,7 @@ \rSec2[ub.basic.start.main]{main function} \pnum -\ubxref{basic.start.main.exit.during.destruction} \\ +\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. @@ -527,7 +526,7 @@ \rSec2[ub.basic.start.term]{Termination} \pnum -\ubxref{basic.start.term.use.after.destruction} \\ +\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 @@ -561,7 +560,7 @@ \pnum -\ubxref{basic.start.term.signal.handler} \\ +\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. @@ -577,7 +576,7 @@ \rSec2[ub.expr.eval]{Result of Expression not Mathematically Defined/out of Range} \pnum -\ubxref{expr.expr.eval} \\ +\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. @@ -596,7 +595,7 @@ \rSec2[ub.basic.lval]{Value category} \pnum -\ubxref{expr.basic.lvalue.strict.aliasing.violation} \\ +\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) @@ -621,7 +620,7 @@ \end{example} \pnum -\ubxref{expr.basic.lvalue.union.initialization} \\ +\ubxref{expr.basic.lvalue.union.initialization} If a program invokes a defaulted copy/move constructor or 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. @@ -641,7 +640,7 @@ \rSec2[ub.expr.type]{Type} \pnum -\ubxref{expr.type.reference.lifetime} \\ +\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. @@ -661,7 +660,7 @@ \rSec2[ub.conv.lval]{Lvalue-to-rvalue conversion} \pnum -\ubxref{conv.lval.valid.representation} \\ +\ubxref{conv.lval.valid.representation} Performing an lvalue-to-rvalue conversion on an object whose @@ -685,7 +684,7 @@ \rSec2[ub.conv.double]{Floating-point conversions} \pnum -\ubxref{conv.double.out.of.range} \\ +\ubxref{conv.double.out.of.range} Converting a floating point value to a type that cannot represent the value is undefined behavior. \pnum @@ -708,7 +707,7 @@ \rSec2[ub.conv.fpint]{Floating-integral conversions} \pnum -\ubxref{conv.fpint.int.not.represented} \\ +\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. @@ -727,7 +726,7 @@ \end{example} \pnum -\ubxref{conv.fpint.float.not.represented} \\ +\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. @@ -747,7 +746,7 @@ \rSec2[ub.conv.ptr]{Pointer conversions} \pnum -\ubxref{conv.ptr.virtual.base} \\ +\ubxref{conv.ptr.virtual.base} Converting a pointer to a derived class \tcode{D} to @@ -773,7 +772,7 @@ \rSec2[ub.conv.mem]{Pointer-to-member conversions} \pnum -\ubxref{conv.member.missing.member} \\ +\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 @@ -800,7 +799,7 @@ \rSec2[ub.expr.call]{Function call} \pnum -\ubxref{expr.call.different.type} \\ +\ubxref{expr.call.different.type} Calling a function through an expression whose function type is different from the function type of the called function's definition results in undefined behavior. @@ -824,7 +823,7 @@ \rSec2[ub.expr.ref]{Class member access} \pnum -\ubxref{expr.ref.member.not.similar} \\ +\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. @@ -845,7 +844,7 @@ \pnum -\ubxref{expr.dynamic.cast.pointer.lifetime} \\ +\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. @@ -863,7 +862,7 @@ \pnum -\ubxref{expr.dynamic.cast.glvalue.lifetime} \\ +\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. @@ -882,7 +881,7 @@ \rSec2[ub.expr.static.cast]{Static cast} \pnum -\ubxref{expr.static.cast.base.class} \\ +\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. @@ -902,7 +901,7 @@ \end{example} \pnum -\ubxref{expr.static.cast.enum.outside.range} \\ +\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. @@ -919,7 +918,7 @@ \end{example} \pnum -\ubxref{expr.static.cast.fp.outside.range} \\ +\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. @@ -941,7 +940,7 @@ \pnum -\ubxref{expr.static.cast.downcast.wrong.derived.type} \\ +\ubxref{expr.static.cast.downcast.wrong.derived.type} Down-casting to the wrong derived type is undefined behavior. \pnum @@ -959,7 +958,7 @@ \end{example} \pnum -\ubxref{expr.static.cast.does.not.contain.orignal.member} \\ +\ubxref{expr.static.cast.does.not.contain.orignal.member} We can cast a pointer to mamber of dervied class D to a pointer to memeber of base class D (with certain restrictions wrt to cv qualifiers) as long B contains the original member, is a base or derived class of the class containing the original member, otherwise the behavior is undefined. @@ -987,7 +986,7 @@ \rSec2[ub.expr.unary.op]{Unary operators} \pnum -\ubxref{expr.unary.dereference} \\ +\ubxref{expr.unary.dereference} Dereferencing a pointer that does not point to an object or function has undefined behavior. @@ -1006,7 +1005,7 @@ \rSec2[ub.expr.new]{New} \pnum -\ubxref{expr.new.non.allocating.null} \\ +\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. @@ -1038,7 +1037,7 @@ \rSec2[ub.expr.delete]{Delete} \pnum -\ubxref{expr.delete.mismatch} \\ +\ubxref{expr.delete.mismatch} Using array delete on the result of a single object new expression is undefined behavior. \pnum @@ -1050,7 +1049,7 @@ \end{example} \pnum -\ubxref{expr.delete.array.mismatch} \\ +\ubxref{expr.delete.array.mismatch} Using single object delete on the result of an array new expression is undefined behavior. \pnum @@ -1063,7 +1062,7 @@ \pnum -\ubxref{expr.delete.dynamic.type.differ} \\ +\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 (see below) 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 @@ -1089,7 +1088,7 @@ \pnum -\ubxref{expr.delete.dynamic.array.dynamic.type.differ} \\ +\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 @@ -1117,7 +1116,7 @@ \rSec2[ub.expr.mptr.oper]{Pointer-to-member operators} \pnum -\ubxref{expr.mptr.oper.not.contain.member} \\ +\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. @@ -1140,7 +1139,7 @@ \pnum -\ubxref{expr.mptr.oper.member.func.null} \\ +\ubxref{expr.mptr.oper.member.func.null} If the second operand is the null member pointer value\iref{conv.mem}, the behavior is undefined. @@ -1163,7 +1162,7 @@ \rSec2[ub.expr.mul]{Multiplicative operators} \pnum -\ubxref{expr.mul.div.by.zero} \\ +\ubxref{expr.mul.div.by.zero} Division by zero is undefined behavior. \pnum @@ -1179,7 +1178,7 @@ \end{example} \pnum -\ubxref{expr.mul.representable.type.result} \\ +\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. @@ -1200,7 +1199,7 @@ \rSec2[ub.expr.add]{Additive operators} \pnum -\ubxref{expr.add.out.of.bounds} \\ +\ubxref{expr.add.out.of.bounds} Creating an out of bounds pointer is undefined behavior. \pnum @@ -1226,7 +1225,7 @@ \end{example} \pnum -\ubxref{expr.add.sub.diff.pointers} \\ +\ubxref{expr.add.sub.diff.pointers} Subtracting pointers that are not part of the same array is undefined behavior. \pnum @@ -1244,7 +1243,7 @@ \end{example} \pnum -\ubxref{expr.add.not.similar} \\ +\ubxref{expr.add.not.similar} For addition or subtraction, if the expressions 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. @@ -1276,7 +1275,7 @@ \rSec2[ub.expr.shift]{Shift operators} \pnum -\ubxref{expr.shift.neg.and.width} \\ +\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 @@ -1294,7 +1293,7 @@ \rSec2[ub.expr.assign]{Assignment and compound assignment operators} \pnum -\ubxref{expr.assign.overlap} \\ +\ubxref{expr.assign.overlap} Overlap in the storage between the source and destination may result in undefined behavior. \pnum @@ -1311,7 +1310,7 @@ \rSec2[ub.stmt.return]{The return statement} \pnum -\ubxref{stmt.return.flow.off} \\ +\ubxref{stmt.return.flow.off} Flowing off the end of a function other than main or a coroutine results in undefined behavior. @@ -1334,7 +1333,7 @@ \rSec2[ub.return.coroutine]{The co_return statement} \pnum -\ubxref{stmt.return.coroutine.flow.off} \\ +\ubxref{stmt.return.coroutine.flow.off} Falling off the end of a coroutine function body that does not return void is undefined behavior. \pnum @@ -1396,7 +1395,7 @@ \rSec2[ub.stmt.dcl]{Declaration statement} \pnum -\ubxref{stmt.dcl.local.static.init.recursive} \\ +\ubxref{stmt.dcl.local.static.init.recursive} If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined. @@ -1418,7 +1417,7 @@ \rSec2[ub.dcl.type.cv]{The cv-qualifiers} \pnum -\ubxref{dcl.type.cv.modify.const.obj} \\ +\ubxref{dcl.type.cv.modify.const.obj} Any attempt to modify a const object during its lifetime results in undefined behavior. @@ -1433,7 +1432,7 @@ \pnum -\ubxref{dcl.type.cv.access.volatile} \\ +\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 @@ -1450,7 +1449,7 @@ \rSec2[ub.dcl.ref]{References} \pnum -\ubxref{dcl.ref.incompatible.function} \\ +\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} @@ -1466,7 +1465,7 @@ \end{example} \pnum -\ubxref{dcl.ref.incompatible.type} \\ +\ubxref{dcl.ref.incompatible.type} Initializing a reference to an object with a value that is not type-accessible\iref{basic.lval} through @@ -1482,7 +1481,7 @@ \end{example} \pnum -\ubxref{dcl.ref.uninitialized.reference} \\ +\ubxref{dcl.ref.uninitialized.reference} Evaluating a reference prior to initializing that reference has undefined behavior. @@ -1503,7 +1502,7 @@ \rSec2[ub.dcl.fct.def.coroutine]{Coroutine definitions} \pnum -\ubxref{dcl.fct.def.coroutine.resume.not.suspended} \\ +\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 @@ -1560,7 +1559,7 @@ \pnum -\ubxref{dcl.fct.def.coroutine.destroy.not.suspended} \\ +\ubxref{dcl.fct.def.coroutine.destroy.not.suspended} Invoking destroy() on a coroutine that is not suspended is undefined behavior. \pnum @@ -1618,7 +1617,7 @@ \rSec2[ub.dcl.attr.assume]{Assumption attribute} \pnum -\ubxref{dcl.attr.assume.false} \\ +\ubxref{dcl.attr.assume.false} If am assumption expression would not evaluate to true at the point where it appears the behavior is undefined. @@ -1640,7 +1639,7 @@ \rSec2[ub.dcl.attr.noreturn]{Noreturn attribute} \pnum -\ubxref{dcl.attr.noreturn.eventually.returns} \\ +\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. @@ -1664,7 +1663,7 @@ \rSec2[ub.class.dtor]{Destructors} \pnum -\ubxref{class.dtor.no.longer.exists} \\ +\ubxref{class.dtor.no.longer.exists} Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended. @@ -1686,7 +1685,7 @@ \rSec2[ub.class.abstract]{Abstract classes} \pnum -\ubxref{class.abstract.pure.virtual} \\ +\ubxref{class.abstract.pure.virtual} Calling a pure virtual function from a constructor or destructor in an abstract class is undefined behavior. \pnum @@ -1709,7 +1708,7 @@ \rSec2[ub.class.base.init]{Initializing bases and members} \pnum -\ubxref{class.base.init.mem.fun} \\ +\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 @@ -1750,7 +1749,7 @@ \rSec2[ub.class.cdtor]{Construction and destruction} \pnum -\ubxref{class.cdtor.before.ctor} \\ +\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. 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 @@ -1800,7 +1799,7 @@ \pnum -\ubxref{class.cdtor.after.dtor} \\ +\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 @@ -1828,7 +1827,7 @@ \end{example} \pnum -\ubxref{class.cdtor.convert.pointer} \\ +\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. @@ -1855,7 +1854,7 @@ \end{example} \pnum -\ubxref{class.cdtor.form.pointer} \\ +\ubxref{class.cdtor.form.pointer} When forming a pointer to a direct non-static member of a class, construction must have started @@ -1877,7 +1876,7 @@ \end{example} \pnum -\ubxref{class.cdtor.virtual.not.x} \\ +\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 @@ -1920,7 +1919,7 @@ \pnum -\ubxref{class.cdtor.typeid} \\ +\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. @@ -1951,7 +1950,7 @@ \pnum -\ubxref{class.cdtor.dynamic.cast} \\ +\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} @@ -1985,7 +1984,7 @@ \rSec2[ub.temp.inst]{Implicit instantiation} \pnum -\ubxref{temp.inst.inf.recursion} \\ +\ubxref{temp.inst.inf.recursion} The result of an infinite recursion in template instantiation is undefined. \pnum @@ -2011,7 +2010,7 @@ \rSec2[ub.except.handle]{Handling an exception} \pnum -\ubxref{except.handle.handler.ctor.dtor} \\ +\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. From 1b3da55ff9d8542fbbd48ccd9400614812a903f2 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 13:10:12 -0500 Subject: [PATCH 246/258] [ub] and [ifndr] fixes and updates after feedback from Christof Meerwald --- source/ifndr.tex | 6 ++++++ source/ub.tex | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 0185e2ccfa..6fa7ecaac9 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -200,6 +200,12 @@ \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() {} diff --git a/source/ub.tex b/source/ub.tex index d913666ede..48760423f9 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -161,8 +161,8 @@ \pnum \ubxref{lifetime.outside.pointer.virtual} For a pointer pointing to an object outside of its lifetime, behavior is -undefined if pointer is implicitly converted\iref{conv.ptr} to a pointer -to a virtual base class. +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} @@ -282,7 +282,7 @@ \pnum \ubxref{original.type.implicit.destructor} The behavior of an implicit destructor call when the type that is not -the original type occupies the storage. +the original type occupies the storage is undefined. \pnum \begin{example} @@ -800,7 +800,9 @@ \pnum \ubxref{expr.call.different.type} -Calling a function through an expression whose function type is different from the function type of the called +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 @@ -941,7 +943,9 @@ \pnum \ubxref{expr.static.cast.downcast.wrong.derived.type} -Down-casting to the wrong derived type is undefined behavior. +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} @@ -959,8 +963,15 @@ \pnum \ubxref{expr.static.cast.does.not.contain.orignal.member} -We can cast a pointer to mamber of dervied class D to a pointer to memeber of base class D (with certain restrictions wrt to cv qualifiers) -as long B contains the original member, is a base or derived class of the class containing the original member, otherwise the behavior is undefined. +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 @@ -1244,7 +1255,8 @@ \pnum \ubxref{expr.add.not.similar} -For addition or subtraction, if the expressions P or Q have type ``pointer to cv T'', where T and the array +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 @@ -1312,7 +1324,8 @@ \pnum \ubxref{stmt.return.flow.off} Flowing off the end of a function other -than main or a coroutine results in undefined behavior. +than main or a coroutine results in undefined behavior if the return type +is not \cv{}~\keyword{void}. \pnum \begin{example} @@ -1334,7 +1347,9 @@ \pnum \ubxref{stmt.return.coroutine.flow.off} -Falling off the end of a coroutine function body that does not return void is undefined behavior. +Flowing off the end of a coroutine function body +that does not return void +has undefined behavior. \pnum \begin{example} @@ -1618,7 +1633,7 @@ \pnum \ubxref{dcl.attr.assume.false} -If am assumption expression would not evaluate to true at the point where it +If an assumption expression would not evaluate to true at the point where it appears the behavior is undefined. \pnum @@ -1751,9 +1766,7 @@ \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. 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. +before the constructor begins execution results in undefined behavior. \pnum \begin{example} @@ -1797,6 +1810,8 @@ \end{codeblock} \end{example} +%TODO: CM: Can this example be shortened? + \pnum \ubxref{class.cdtor.after.dtor} From 97d4ef4c529dfefee280bb078bd011337840cfbf Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 13:58:29 -0500 Subject: [PATCH 247/258] [*] made sure ubdef and ifndrdef do not have preceding whitespaces and come before full stops --- source/basic.tex | 6 +++--- source/declarations.tex | 4 ++-- source/expressions.tex | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 55dca8963f..e11c4f627d 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3840,7 +3840,7 @@ 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.\ubdef{basic.align.object.alignment} +is undefined behavior\ubdef{basic.align.object.alignment}. \pnum A \defnadj{fundamental}{alignment} is represented by an alignment @@ -4585,7 +4585,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.\ubdef{basic.stc.alloc.zero.dereference} +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 @@ -4708,7 +4708,7 @@ signature. \pnum -If a deallocation function terminates by throwing an exception, the behavior is undefined.\ubdef{basic.stc.alloc.dealloc.throw} +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. diff --git a/source/declarations.tex b/source/declarations.tex index d06863ebc7..b43175ebeb 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -3285,7 +3285,7 @@ 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.\ubdef{dcl.ref.incompatible.function} +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} @@ -3303,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.\ubdef{dcl.ref.uninitialized.reference} +is undefined\ubdef{dcl.ref.uninitialized.reference}. \begin{example} \begin{codeblock} int &f(int&); diff --git a/source/expressions.tex b/source/expressions.tex index 9303830899..70485761d1 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -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.\ubdef{expr.basic.lvalue.union.initialization} +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.\ubdef{expr.type.reference.lifetime} +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.\ubdef{conv.lval.valid.representation} +are not valid for the object's type, the behavior is undefined\ubdef{conv.lval.valid.representation}. \begin{example} \begin{codeblock} bool f() { @@ -1024,8 +1024,8 @@ 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. -\ubdef{conv.fpint.int.not.represented} +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. @@ -1079,7 +1079,7 @@ that is within its lifetime or within its period of construction or destruction\iref{class.cdtor}, -the behavior is undefined.\ubdef{conv.ptr.virtual.base} +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. @@ -1113,7 +1113,7 @@ \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.\ubdef{conv.member.missing.member} +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 @@ -4524,14 +4524,14 @@ that is within its lifetime or within its period of construction or destruction\iref{class.cdtor}, -the behavior is undefined.\ubdef{expr.dynamic.cast.pointer.lifetime} +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.\ubdef{expr.dynamic.cast.glvalue.lifetime} +the behavior is undefined\ubdef{expr.dynamic.cast.glvalue.lifetime}. \pnum If \tcode{T} is ``pointer to \cv{} \keyword{void}'', then the result From 50fe1b77ee96eeaedb667192c149778b9ccf3220 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 14:08:09 -0500 Subject: [PATCH 248/258] [ub] comment about library ub in the core wording --- source/ub.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/ub.tex b/source/ub.tex index 48760423f9..3a26d0ff30 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -571,6 +571,10 @@ \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? \rSec1[ub.expr]{\ref{expr}: Expressions} \rSec2[ub.expr.eval]{Result of Expression not Mathematically Defined/out of Range} From 0572e0f87a9298b91e7f94bdd0e0cbbbc1d0945b Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 15:25:29 -0500 Subject: [PATCH 249/258] [ub] feedback from Shafik on ub annex --- source/ub.tex | 66 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/source/ub.tex b/source/ub.tex index 3a26d0ff30..10fe4ce995 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -90,6 +90,11 @@ \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 @@ -105,7 +110,9 @@ void make_misaligned() { alignas(S) char s[sizeof(S) + 1]; - new (&s+1) S(); // undefined behavior + 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} @@ -281,8 +288,10 @@ \pnum \ubxref{original.type.implicit.destructor} -The behavior of an implicit destructor call when the type that is not -the original type occupies the storage is undefined. +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} @@ -515,7 +524,7 @@ ~Exiter() { std::exit(0); } }; -Exiter ex; // +Exiter ex; int main() {} // undefined behavior when destructor of static variable \tcode{ex} is called it will call \tcode{std::exit} @@ -549,7 +558,7 @@ }; C c; -B b; +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 @@ -575,6 +584,7 @@ %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} @@ -589,9 +599,11 @@ \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 + // 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} @@ -625,7 +637,8 @@ \pnum \ubxref{expr.basic.lvalue.union.initialization} -If a program invokes a defaulted copy/move constructor or copy/move assignment +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. @@ -701,7 +714,7 @@ 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 - // represetable values are [-inf,+inf] this would not be UB + // 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} @@ -721,10 +734,10 @@ #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 + // 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 + int x1 = d; // undefined behavior $2,147,483,647 + 1$ is not representable as int } \end{codeblock} \end{example} @@ -846,6 +859,9 @@ \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} @@ -894,7 +910,7 @@ \pnum \begin{example} \begin{codeblock} -truct B {}; +struct B {}; struct D1 : B {}; struct D2 : B {}; @@ -1079,7 +1095,7 @@ \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 (see below) is not a destroying operator delete, the static type +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. @@ -1155,7 +1171,7 @@ \pnum \ubxref{expr.mptr.oper.member.func.null} -If the second operand is the null +If the second operand in a \tcode{.*} expression is the null member pointer value\iref{conv.mem}, the behavior is undefined. \pnum @@ -1204,9 +1220,9 @@ #include int main() { - int x = - std::numeric_limits::min() / -1; // Assuming LP64 -2147483648 which when divided by -1 - // gives us 2147483648 which is not representable by int + 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} @@ -1683,7 +1699,9 @@ \pnum \ubxref{class.dtor.no.longer.exists} -Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the +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 @@ -1695,8 +1713,8 @@ int main() { A a; - a.~A(); // undefined behavior, destructor will be invoked again at scope exit -} + a.~A(); +} // undefined behavior, lifetime of \tcode{a} already ended before implicit destructor \end{codeblock} \end{example} @@ -1744,7 +1762,7 @@ public: int f(); B() - : A(f()), // undefined: calls member function but base Ac not yet initialized + : A(f()), // undefined: calls member function but base A not yet initialized j(f()) {} // well-defined: bases are all initialized }; @@ -1770,7 +1788,7 @@ \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. +before the constructor begins execution results in undefined behavior. \pnum \begin{example} From ef1f86509495731138abfd84a6a714e7edac80f2 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Wed, 11 Feb 2026 12:15:53 -0500 Subject: [PATCH 250/258] [ifndr] more feebdack from Shafik --- source/ifndr.tex | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 6fa7ecaac9..d8474847b9 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -518,6 +518,8 @@ \end{codeblock} \end{example} +%TODO: SY, JMB: We need to produce an example for this case. + \rSec2[ifndr.temp.dep.res]{Dependent name resolution} \rSec3[ifndr.temp.point]{Point of instantiation} @@ -584,18 +586,27 @@ \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. +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 typename T::X h(typename A::X); -template auto h(typename A::X) -> typename T::X; // redeclaration +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. From 3acf197d70f8f74035943eb00ff6c0036ca72fd5 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Wed, 18 Feb 2026 12:25:26 -0500 Subject: [PATCH 251/258] [ifndr]: added missing entries brought up by Alisdair --- source/ifndr.tex | 55 +++++++++++++++++++++++++++++++++++++++++ source/preprocessor.tex | 7 +++--- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index d8474847b9..480c890d15 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -610,3 +610,58 @@ %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} +\end{codeblock} +\end{example} + +%TODO: JMB: An example that reproduces this case should be provided (preferably +% one that illuminates why the diagnostic might not be produced) + +\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} +\end{codeblock} +\end{example} + +%TODO: JMB: An example that reproduces this case should be provided (preferably +% one that illuminates why the diagnostic might not be produced) + + +\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} +\end{codeblock} +\end{example} + +%TODO: JMB: An example that reproduces this case should be provided (preferably +% one that illuminates why the diagnostic might not be produced) diff --git a/source/preprocessor.tex b/source/preprocessor.tex index c2284a582c..1cec9096e5 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -536,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 @@ -766,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} From 3df5f6e8e34df656d536addcfddd8d997ad523f0 Mon Sep 17 00:00:00 2001 From: notadragon Date: Thu, 19 Feb 2026 22:25:53 -0500 Subject: [PATCH 252/258] [ifndr]: started with shafik's suggested examples and refined them a bit --- source/ifndr.tex | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 480c890d15..92601dc280 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -624,12 +624,13 @@ \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} -%TODO: JMB: An example that reproduces this case should be provided (preferably -% one that illuminates why the diagnostic might not be produced) - \pnum \ifndrxref{cpp.cond.defined.malformed} If the \tcode{defined} unary operator is used when it @@ -640,13 +641,14 @@ \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} -%TODO: JMB: An example that reproduces this case should be provided (preferably -% one that illuminates why the diagnostic might not be produced) - - \rSec2[ifndr.cpp.include]{Source file inclusion} \pnum @@ -660,8 +662,6 @@ \pnum \begin{example} \begin{codeblock} +#include `` // Ill-formed no diagnoatic required, does not match one of the two allowable forms \end{codeblock} \end{example} - -%TODO: JMB: An example that reproduces this case should be provided (preferably -% one that illuminates why the diagnostic might not be produced) From 4a5dc40a246ec5c6af69be9aeb217405c56643f3 Mon Sep 17 00:00:00 2001 From: notadragon Date: Thu, 19 Feb 2026 22:30:25 -0500 Subject: [PATCH 253/258] [ifndr] added comment on possibly non-NDR entry temp.names.sat.constraints --- source/ifndr.tex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/ifndr.tex b/source/ifndr.tex index 92601dc280..dd6c66b7d0 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -479,6 +479,8 @@ \end{codeblock} \end{example} +%TODO: AM: There does not seem to be something obvious in the wording itself that makes this case NDR + \rSec2[ifndr.temp.fct]{Function templates} From b59a30a2b90637c1a6ee563628fd9be31f1d7488 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 19 Feb 2026 22:48:25 -0500 Subject: [PATCH 254/258] [ifndr] fixing (hopefully) bad unary operator defined example --- source/ifndr.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index dd6c66b7d0..cbe1d97046 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -626,7 +626,7 @@ \pnum \begin{example} \begin{codeblock} -define A defined +#define A defined #if A // Ill-formed no diagnostic required, \tcode{defined} is generated by macro replacement // in controlling expression #endif @@ -643,9 +643,9 @@ \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 +#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} From 8818acca4eeaba4d2c724bf12ddd50aa524add85 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 20 Feb 2026 12:58:41 -0500 Subject: [PATCH 255/258] [ifndr]: added many missing ifndr types, removed temp.names.sat.constraints --- source/basic.tex | 7 +- source/declarations.tex | 16 +- source/ifndr.tex | 346 +++++++++++++++++++++++++++++++++++++--- source/modules.tex | 5 +- source/templates.tex | 8 +- 5 files changed, 340 insertions(+), 42 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index e11c4f627d..3ec230de1e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3166,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} @@ -7794,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} @@ -8200,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/declarations.tex b/source/declarations.tex index b43175ebeb..088cfa0a6c 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -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 @@ -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. @@ -4375,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 @@ -4680,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$ @@ -7589,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 @@ -9310,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. @@ -9898,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} diff --git a/source/ifndr.tex b/source/ifndr.tex index cbe1d97046..bfff4e10fe 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -34,6 +34,58 @@ \rSec1[ifndr.basic]{\ref{basic}: Basics} +\rSec2[ifndr.basic.link]{Program and linkage} + +\pnum +\ifndrxref{basic.link.entity.same.module} +If an entity has multiple declarations +attached to different modules +where neither is reachable from the other +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{\tcode{"decls.h"}} +int h(); // \#1, attached to the global module +\end{codeblocktu} +\begin{codeblocktu}{Module interface of \tcode{M}} +module; +export moodule M; +export int h(); // \#1, attached to \tcode{M} +\end{codeblocktu} +\begin{codeblocktu}{Other translation unit} +#include "decls.h" +import M; + // ill-formed, no diagnostic required, the declarations of `h` cannot + // reach one another +\end{codeblocktu} +\end{example} + +\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 @@ -81,6 +133,47 @@ \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 @@ -178,7 +271,126 @@ \rSec1[ifndr.dcl.dcl]{\ref{dcl}: Declarations} -\rSec2[ifndr.dcl.align]{Alignment specifier} +\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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an 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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an 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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an 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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an 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} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an 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} @@ -196,7 +408,24 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.dcl.attr.noreturn]{Noreturn attribute} +\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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + +\rSec3[ifndr.dcl.attr.noreturn]{Noreturn attribute} \pnum \ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} @@ -251,6 +480,38 @@ \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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an 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{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + \rSec1[ifndr.class]{\ref{class}: Classes} @@ -432,6 +693,9 @@ \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 @@ -460,27 +724,6 @@ \rSec2[ifndr.temp.names]{Names of template specializations} -\pnum -\ifndrxref{temp.names.sat.constraints} -When the template-name of a simple-template-id names a constrained non-function template or a constrained -template template-parameter, and all template-arguments in the simple-template-id are non-dependent\iref{temp.dep.temp}, -the associated constraints\iref{temp.constr.decl} of the constrained template shall be satisfied\iref{temp.constr.constr}. - -\pnum -\begin{example} -\begin{codeblock} -template concept C1 = sizeof(T) != sizeof(int); -template using Ptr = T*; - -Ptr p; // error: constraints not satisfied - -template -struct S2 { Ptr x; }; // ill-formed, no diagnostic required -\end{codeblock} -\end{example} - -%TODO: AM: There does not seem to be something obvious in the wording itself that makes this case NDR - \rSec2[ifndr.temp.fct]{Function templates} @@ -522,9 +765,9 @@ %TODO: SY, JMB: We need to produce an example for this case. -\rSec2[ifndr.temp.dep.res]{Dependent name resolution} +\rSec3[ifndr.temp.dep.res]{Dependent name resolution} -\rSec3[ifndr.temp.point]{Point of instantiation} +\rSec4[ifndr.temp.point]{Point of instantiation} \pnum \ifndrxref{temp.point.diff.pt.diff.meaning} @@ -557,8 +800,27 @@ \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 + -\rSec2[ifndr.temp.explicit]{Explicit instantiation} +\rSec3[ifndr.temp.explicit]{Explicit instantiation} \pnum \ifndrxref{temp.explicit.decl.implicit.inst} @@ -580,6 +842,38 @@ \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} diff --git a/source/modules.tex b/source/modules.tex index fea1cc14e3..9ecef29d77 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -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. @@ -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} diff --git a/source/templates.tex b/source/templates.tex index d1f3312db6..e13dd204ad 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -987,7 +987,7 @@ are non-dependent\iref{temp.dep.temp}, the associated constraints\iref{temp.constr.decl} of the constrained template -shall be satisfied\iref{temp.constr.constr}\ifndrdef{temp.names.sat.constraints}. +shall be satisfied\iref{temp.constr.constr}. \begin{example} \begin{codeblock} template concept C1 = sizeof(T) != sizeof(int); @@ -6281,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} @@ -7370,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} From c50ae0513329e9f63eb9fa8ac97931e6f7b82234 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 16 Apr 2026 12:33:36 -0400 Subject: [PATCH 256/258] ifndr: removing module ownership related ifndr (cwg3171) --- source/ifndr.tex | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index bfff4e10fe..2ef0d644a4 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -36,31 +36,6 @@ \rSec2[ifndr.basic.link]{Program and linkage} -\pnum -\ifndrxref{basic.link.entity.same.module} -If an entity has multiple declarations -attached to different modules -where neither is reachable from the other -the program is ill-formed, no diagnostic required. - -\pnum -\begin{example} -\begin{codeblocktu}{\tcode{"decls.h"}} -int h(); // \#1, attached to the global module -\end{codeblocktu} -\begin{codeblocktu}{Module interface of \tcode{M}} -module; -export moodule M; -export int h(); // \#1, attached to \tcode{M} -\end{codeblocktu} -\begin{codeblocktu}{Other translation unit} -#include "decls.h" -import M; - // ill-formed, no diagnostic required, the declarations of `h` cannot - // reach one another -\end{codeblocktu} -\end{example} - \pnum \ifndrxref{basic.link.consistent.types} Multiple declarations of an entity must be consistent, From b2caddbf0ce09a756996cb970a4b04c0290daffe Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 16 Apr 2026 14:07:10 -0400 Subject: [PATCH 257/258] ifndr: filled in many of the missing examples/TODOs --- source/ifndr.tex | 95 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 2ef0d644a4..38276dba68 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -260,12 +260,14 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\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} -%TODO: JMB: produce an example - \rSec3[ifndr.dcl.inline]{The \keyword{inline} specifier} \pnum @@ -279,12 +281,15 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\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} -%TODO: JMB: produce an example - \rSec2[ifndr.dcl.fct]{Functions} \rSec3[ifndr.dcl.fct.default]{Default arguments} @@ -300,12 +305,17 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\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} -%TODO: JMB: produce an example - \rSec2[ifndr.dcl.contract]{Function contract specifiers} \rSec3[ifndr.dcl.contract.func]{General} @@ -319,12 +329,18 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\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} -%TODO: JMB: produce an example - \rSec2[ifndr.dcl.fct.def]{Function definitions} \rSec3[ifndr.dcl.fct.def.replace]{Replaceable function definitions} @@ -343,11 +359,15 @@ \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} -%TODO: JMB: produce an example - \rSec2[ifndr.dcl.link]{Linkage specifications} \pnum @@ -394,12 +414,14 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\begin{codeblocktu}{Translation unit \#1} +int h(int x [[indeterminate]]; // IFNDR, mismatched \tcode{[[indeterminate]]} on first parameter to other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int h(int x); // IFNDR, mismatched \tcode{[[indeterminate]]} on first parameter to other first declaration of \tcode{h} +\end{codeblocktu} \end{example} -%TODO: JMB: produce an example - \rSec3[ifndr.dcl.attr.noreturn]{Noreturn attribute} \pnum @@ -465,12 +487,22 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\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} -%TODO: JMB: produce an example - \rSec2[ifndr.module.private.frag]{Private module fragment} \pnum @@ -481,12 +513,15 @@ \pnum \begin{example} -\begin{codeblock} -\end{codeblock} +\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} -%TODO: JMB: produce an example - \rSec1[ifndr.class]{\ref{class}: Classes} From 1872212f3dee9fc9a993d16ea532a971ed2033dd Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 16 Apr 2026 16:01:39 -0400 Subject: [PATCH 258/258] [ifndr]: cleaned up line wrapping of some comments --- source/ifndr.tex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 38276dba68..651918b3b6 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -364,7 +364,8 @@ 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{} +void* operator new(decltype(sizeof(0)) noexcept; // IFNDR, mismatched exception specification to declaration + // in \tcode{} \end{codeblock} \end{example} @@ -415,10 +416,10 @@ \pnum \begin{example} \begin{codeblocktu}{Translation unit \#1} -int h(int x [[indeterminate]]; // IFNDR, mismatched \tcode{[[indeterminate]]} on first parameter to other first declaration of \tcode{h} +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]]} on first parameter to other first declaration of \tcode{h} +int h(int x); // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} \end{codeblocktu} \end{example}