From 4ef8aa3ab6c0d7fdaf401abb95171716487e8055 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 13:10:12 -0500 Subject: [PATCH 01/27] [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 39922f7a281875aa5b7484963fab5aa3e076f7cb Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 13:58:29 -0500 Subject: [PATCH 02/27] [*] 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 bf53cb3f67..caeee9ce55 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 ae650118b0..561b41d512 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -3286,7 +3286,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} @@ -3304,7 +3304,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 90b9336eed..0da914b30f 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 @@ -4523,14 +4523,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 4fe50a6659b205402a6b3e871738e1778e5a897f Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 14:08:09 -0500 Subject: [PATCH 03/27] [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 1ea109efd17b1c54c6fe13cd5ed36ffcb000a47b Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 15:25:29 -0500 Subject: [PATCH 04/27] [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 16b3c61ee1889df4565d4ab46e1ef00676999baf Mon Sep 17 00:00:00 2001 From: jberne4 Date: Wed, 11 Feb 2026 12:15:53 -0500 Subject: [PATCH 05/27] [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 69b8ab14f67296b950bce6c3e506a244799b3d80 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Wed, 18 Feb 2026 12:25:26 -0500 Subject: [PATCH 06/27] [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 0bfb7f194f..c05a798b76 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -527,12 +527,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 @@ -757,7 +757,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 a5afc2eaac4a40bb294f70edacfc3d86467680e7 Mon Sep 17 00:00:00 2001 From: notadragon Date: Thu, 19 Feb 2026 22:25:53 -0500 Subject: [PATCH 07/27] [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 c4122b94168ef0c3bd5cd4577dae49ffaca026da Mon Sep 17 00:00:00 2001 From: notadragon Date: Thu, 19 Feb 2026 22:30:25 -0500 Subject: [PATCH 08/27] [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 593d5442144b138219ccf389c64c05235a9d0861 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 19 Feb 2026 22:48:25 -0500 Subject: [PATCH 09/27] [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 c3d6fee9c1ebe659d9b2b993ec097990ca7f4c7a Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 20 Feb 2026 12:58:41 -0500 Subject: [PATCH 10/27] [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 caeee9ce55..973edfcd2b 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 561b41d512..88830bfea2 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1065,7 +1065,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 @@ -1140,7 +1140,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. @@ -4376,7 +4376,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 @@ -4681,7 +4682,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$ @@ -7590,7 +7592,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 @@ -9311,7 +9313,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. @@ -9899,7 +9901,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 8ce89369d1..f2d3172095 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 02095d4c8bd6570e226eb267b91e8d3e025f52ea Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 16 Apr 2026 12:33:36 -0400 Subject: [PATCH 11/27] 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 ab8ff536d865a9a65707c5f7755e5627003f93aa Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 16 Apr 2026 14:07:10 -0400 Subject: [PATCH 12/27] 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 b34f3cebd3372dbf054a2e23584cddecf9c5e8ae Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 16 Apr 2026 16:01:39 -0400 Subject: [PATCH 13/27] [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} From e8abba509b9fbf0746cdd4e5c9b669898815583f Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 5 May 2026 20:14:56 -0400 Subject: [PATCH 14/27] [templates.tex]: typo fix --- source/templates.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/templates.tex b/source/templates.tex index f2d3172095..de6fd2c460 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -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 requiredi\ifndrdef{temp.explicit.decl.implicit.inst}. +program; otherwise the program is ill-formed, no diagnostic required\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 From b0895803a9e4e45a417875efe0f4291b0238b545 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 5 May 2026 20:30:36 -0400 Subject: [PATCH 15/27] [ub/ifndr]: minor todo cleanup --- source/ifndr.tex | 10 +++++----- source/ub.tex | 6 ------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 651918b3b6..8def5e2229 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -704,8 +704,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. +%TODO: JMB: 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, as they +% are all variations on producing an invalid construct upon substitution \rSec2[ifndr.temp.spec.partial]{Partial specialization} @@ -880,12 +881,11 @@ \pnum \begin{example} \begin{codeblock} +template struct S; +template <> struct S; // IFNDR, no definition provided. \end{codeblock} \end{example} -%TODO: JMB: produce an example - - \rSec2[ifndr.temp.deduct]{Template argument deduction} \rSec3[ifndr.temp.deduct.general]{General} diff --git a/source/ub.tex b/source/ub.tex index 10fe4ce995..6e513fa624 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -574,12 +574,6 @@ does not happen before\iref{intro.multithread} completion of destruction of objects with static storage duration and execution of std::atexit registered functions\iref{support.start.term}, the program has undefined behavior. -\pnum -\begin{example} -\begin{codeblock} -\end{codeblock} -\end{example} - %TODO: JMB/TD: This is really a general precondition imposed on the Standard %Library, not a piece of core language undefined behavior. It is also currently %missing an example. Should we retain this UB? Should we have a core issue From 0123f0660e6b4f0ccbf2c679a1bca6a4c7089a16 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 7 May 2026 08:18:17 -0400 Subject: [PATCH 16/27] [ifndr]: odr-using a function in example --- source/ifndr.tex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 8def5e2229..914f6b679c 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -881,8 +881,9 @@ \pnum \begin{example} \begin{codeblock} -template struct S; -template <> struct S; // IFNDR, no definition provided. +template int f(T&&) { return 0; } +template <> int f(int&&); +int j = f(1); // IFNDR, odr-use of \tcode{f} with no defintion \end{codeblock} \end{example} From 3b56986cee9262ebf9f3b1906948d6603474fa07 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 7 May 2026 09:02:59 -0400 Subject: [PATCH 17/27] [ifndr]: fix to comment formatting --- source/ifndr.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 914f6b679c..f03516da55 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -883,7 +883,7 @@ \begin{codeblock} template int f(T&&) { return 0; } template <> int f(int&&); -int j = f(1); // IFNDR, odr-use of \tcode{f} with no defintion +int j = f(1); // IFNDR, odr-use of \tcode{f} with no defintion \end{codeblock} \end{example} From 5b795791720c9fd3405af769cf9bebddcea3a7e8 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 8 May 2026 17:01:51 -0400 Subject: [PATCH 18/27] [ub] and [ifndr]: added missing intermediate rSec commands and synched up with main text body --- source/ifndr.tex | 133 +++++++++++++++++++++++++---------------------- source/ub.tex | 120 +++++++++++++++++++++++++++--------------- 2 files changed, 149 insertions(+), 104 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index f03516da55..0c46c0a437 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -149,54 +149,11 @@ \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} +\rSec2[ifndr.expr.prim]{Primary expressions} + +\rSec3[ifndr.expr.prim.req]{Requires expressions} \pnum \ifndrxref{expr.prim.req.always.sub.fail} @@ -290,9 +247,13 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.dcl.fct]{Functions} +\rSec2[ifndr.dcl.decl]{Declarators} + +\rSec3[ifndr.dcl.meaning]{Meaning of declarators} + +\rSec4[ifndr.dcl.fct]{Functions} -\rSec3[ifndr.dcl.fct.default]{Default arguments} +\rSec4[ifndr.dcl.fct.default]{Default arguments} \pnum \ifndrxref{dcl.fct.default.inline.same.defaults} @@ -526,7 +487,55 @@ \rSec1[ifndr.class]{\ref{class}: Classes} -\rSec2[ifndr.class.base.init]{Initializing bases and members} +\rSec2[ifndr.basic.lookup]{Name lookup} + +\rSec3[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} + +\rSec2[ifndr.class.init]{Initialization} + +\rSec3[ifndr.class.base.init]{Initializing bases and members} \pnum \ifndrxref{class.base.init.delegate.itself} @@ -546,7 +555,9 @@ \end{example} -\rSec2[ifndr.class.virtual]{Virtual functions} +\rSec2[ifndr.class.derived]{Derived classes} + +\rSec3[ifndr.class.virtual]{Virtual functions} \pnum \ifndrxref{class.virtual.pure.or.defined} @@ -613,7 +624,7 @@ \end{example} -\rSec2[ifndr.temp.arg.template]{Template template arguments} +\rSec3[ifndr.temp.arg.template]{Template template arguments} \pnum \ifndrxref{temp.arg.template.sat.constraints} @@ -645,7 +656,7 @@ \end{example} -\rSec2[ifndr.constr.atomic]{Atomic constraints} +\rSec4[ifndr.constr.atomic]{Atomic constraints} \pnum \ifndrxref{temp.constr.atomic.equiv.but.not.equiv} @@ -686,7 +697,7 @@ \end{example} -\rSec2[ifndr.temp.constr.normal]{Constraint normalization} +\rSec3[ifndr.temp.constr.normal]{Constraint normalization} \pnum \ifndrxref{temp.constr.normal.invalid} @@ -708,7 +719,7 @@ % not sure if they a really are worth calling distinct cases of ifndr, as they % are all variations on producing an invalid construct upon substitution -\rSec2[ifndr.temp.spec.partial]{Partial specialization} +\rSec4[ifndr.temp.spec.partial]{Partial specialization} \pnum \ifndrxref{temp.spec.partial.general.partial.reachable} @@ -734,12 +745,12 @@ \end{example} -\rSec2[ifndr.temp.names]{Names of template specializations} +\rSec3[ifndr.temp.names]{Names of template specializations} -\rSec2[ifndr.temp.fct]{Function templates} +\rSec3[ifndr.temp.fct]{Function templates} -\rSec3[ifndr.temp.over.link]{Function template overloading} +\rSec4[ifndr.temp.over.link]{Function template overloading} \pnum \ifndrxref{temp.over.link.equiv.not.equiv} @@ -758,7 +769,7 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.res]{Name resolution} +\rSec3[ifndr.temp.res]{Name resolution} \rSec3[ifndr.temp.res.general]{General} @@ -777,7 +788,7 @@ %TODO: SY, JMB: We need to produce an example for this case. -\rSec3[ifndr.temp.dep.res]{Dependent name resolution} +\rSec4[ifndr.temp.dep.res]{Dependent name resolution} \rSec4[ifndr.temp.point]{Point of instantiation} @@ -887,9 +898,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.deduct]{Template argument deduction} +\rSec3[ifndr.temp.deduct]{Template argument deduction} -\rSec3[ifndr.temp.deduct.general]{General} +\rSec4[ifndr.temp.deduct.general]{General} \pnum \ifndrxref{temp.deduct.general.diff.order} diff --git a/source/ub.tex b/source/ub.tex index 6e513fa624..b9aeab60df 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -13,7 +13,9 @@ \rSec1[ub.basic]{\ref{basic}: Basics} -\rSec2[ub.intro.object]{Implicitly creating object and undefined behavior} +\rSec2[ub.basic.memobj]{Memory and objects} + +\rSec3[ub.intro.object]{Implicitly creating object and undefined behavior} \pnum \ubxref{intro.object.implicit.create} @@ -95,7 +97,7 @@ %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} +\rSec3[ub.basic.align]{Object alignment} \pnum \ubxref{basic.align.object.alignment} @@ -117,7 +119,7 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.life]{Object lifetime} +\rSec3[ub.basic.life]{Object lifetime} \pnum \ubxref{lifetime.outside.pointer.delete} @@ -333,7 +335,8 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.indet]{Indeterminate and erroneous values} +\rSec3[ub.basic.indet]{Indeterminate and erroneous values} + \pnum \ubxref{basic.indet.value} @@ -352,7 +355,9 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.stc.dynamic]{Dynamic storage Duration} +\rSec3[ub.basic.stc]{Storage duration} + +\rSec4[ub.basic.stc.dynamic]{Dynamic storage Duration} \pnum \ubxref{basic.stc.alloc.dealloc.constraint} @@ -400,7 +405,7 @@ -\rSec2[ub.basic.stc.alloc.zero.dereference]{Zero-sized allocation dereference} +\rSec5[ub.basic.stc.alloc.zero.dereference]{Zero-sized allocation dereference} \pnum \ubxref{basic.stc.alloc.zero.dereference} @@ -418,7 +423,9 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.compound]{Compound types} +\rSec2[ub.basic.types]{Types} + +\rSec3[ub.basic.compound]{Compound types} \pnum \ubxref{basic.compound.invalid.pointer} @@ -444,7 +451,9 @@ \end{example} -\rSec2[ub.intro.execution]{Sequential execution} +\rSec2[ub.basic.exec]{Program execution} + +\rSec3[ub.intro.execution]{Sequential execution} \pnum \ubxref{intro.execution.unsequenced.modification} @@ -466,7 +475,7 @@ \end{codeblock} \end{example} -\rSec2[ub.intro.races]{Data races} +\rSec4[ub.intro.races]{Data races} \pnum \ubxref{intro.races.data} @@ -484,7 +493,7 @@ \end{codeblock} \end{example} -\rSec2[ub.intro.progress]{Forward progress} +\rSec4[ub.intro.progress]{Forward progress} \pnum \ubxref{intro.progress.stops} @@ -507,7 +516,9 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.start.main]{main function} +\rSec3[ub.basic.start]{Start and termination} + +\rSec4[ub.basic.start.main]{main function} \pnum \ubxref{basic.start.main.exit.during.destruction} @@ -532,7 +543,7 @@ \end{example} -\rSec2[ub.basic.start.term]{Termination} +\rSec4[ub.basic.start.term]{Termination} \pnum \ubxref{basic.start.term.use.after.destruction} @@ -602,7 +613,7 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.lval]{Value category} +\rSec3[ub.basic.lval]{Value category} \pnum \ubxref{expr.basic.lvalue.strict.aliasing.violation} @@ -648,7 +659,7 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.type]{Type} +\rSec3[ub.expr.type]{Type} \pnum \ubxref{expr.type.reference.lifetime} @@ -668,7 +679,7 @@ \end{codeblock} \end{example} -\rSec2[ub.conv.lval]{Lvalue-to-rvalue conversion} +\rSec3[ub.conv.lval]{Lvalue-to-rvalue conversion} \pnum \ubxref{conv.lval.valid.representation} @@ -692,7 +703,7 @@ \end{example} -\rSec2[ub.conv.double]{Floating-point conversions} +\rSec3[ub.conv.double]{Floating-point conversions} \pnum \ubxref{conv.double.out.of.range} @@ -715,7 +726,7 @@ \end{example} -\rSec2[ub.conv.fpint]{Floating-integral conversions} +\rSec3[ub.conv.fpint]{Floating-integral conversions} \pnum \ubxref{conv.fpint.int.not.represented} @@ -754,7 +765,7 @@ \end{codeblock} \end{example} -\rSec2[ub.conv.ptr]{Pointer conversions} +\rSec3[ub.conv.ptr]{Pointer conversions} \pnum \ubxref{conv.ptr.virtual.base} @@ -780,7 +791,7 @@ \end{codeblock} \end{example} -\rSec2[ub.conv.mem]{Pointer-to-member conversions} +\rSec3[ub.conv.mem]{Pointer-to-member conversions} \pnum \ubxref{conv.member.missing.member} @@ -807,7 +818,7 @@ -\rSec2[ub.expr.call]{Function call} +\rSec4[ub.expr.call]{Function call} \pnum \ubxref{expr.call.different.type} @@ -833,7 +844,7 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.ref]{Class member access} +\rSec4[ub.expr.ref]{Class member access} \pnum \ubxref{expr.ref.member.not.similar} @@ -856,7 +867,7 @@ %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} +\rSec4[ub.expr.dynamic.cast]{Dynamic cast} \pnum @@ -894,7 +905,7 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.static.cast]{Static cast} +\rSec4[ub.expr.static.cast]{Static cast} \pnum \ubxref{expr.static.cast.base.class} @@ -1008,7 +1019,7 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.unary.op]{Unary operators} +\rSec4[ub.expr.unary.op]{Unary operators} \pnum \ubxref{expr.unary.dereference} @@ -1027,7 +1038,7 @@ \end{example} -\rSec2[ub.expr.new]{New} +\rSec4[ub.expr.new]{New} \pnum \ubxref{expr.new.non.allocating.null} @@ -1059,7 +1070,7 @@ \end{example} -\rSec2[ub.expr.delete]{Delete} +\rSec4[ub.expr.delete]{Delete} \pnum \ubxref{expr.delete.mismatch} @@ -1138,7 +1149,7 @@ \end{example} -\rSec2[ub.expr.mptr.oper]{Pointer-to-member operators} +\rSec3[ub.expr.mptr.oper]{Pointer-to-member operators} \pnum \ubxref{expr.mptr.oper.not.contain.member} @@ -1184,7 +1195,7 @@ \end{example} -\rSec2[ub.expr.mul]{Multiplicative operators} +\rSec3[ub.expr.mul]{Multiplicative operators} \pnum \ubxref{expr.mul.div.by.zero} @@ -1221,7 +1232,7 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.add]{Additive operators} +\rSec3[ub.expr.add]{Additive operators} \pnum \ubxref{expr.add.out.of.bounds} @@ -1298,7 +1309,7 @@ \end{example} -\rSec2[ub.expr.shift]{Shift operators} +\rSec3[ub.expr.shift]{Shift operators} \pnum \ubxref{expr.shift.neg.and.width} @@ -1316,7 +1327,7 @@ \end{example} -\rSec2[ub.expr.assign]{Assignment and compound assignment operators} +\rSec3[ub.expr.assign]{Assignment and compound assignment operators} \pnum \ubxref{expr.assign.overlap} @@ -1333,7 +1344,9 @@ \rSec1[ub.stmt.stmt]{\ref{stmt}: Statements} -\rSec2[ub.stmt.return]{The return statement} +\rSec2[ub.stmt.jump]{Jump statements} + +\rSec3[ub.stmt.return]{The return statement} \pnum \ubxref{stmt.return.flow.off} @@ -1357,7 +1370,7 @@ \end{codeblock} \end{example} -\rSec2[ub.return.coroutine]{The co_return statement} +\rSec3[ub.return.coroutine]{The co_return statement} \pnum \ubxref{stmt.return.coroutine.flow.off} @@ -1443,7 +1456,11 @@ \rSec1[ub.dcl.dcl]{\ref{dcl}: Declarations} -\rSec2[ub.dcl.type.cv]{The cv-qualifiers} +\rSec2[ub.dcl.spec]{Specifiers} + +\rSec3[ub.dcl.type]{Type specifiers} + +\rSec4[ub.dcl.type.cv]{The cv-qualifiers} \pnum \ubxref{dcl.type.cv.modify.const.obj} @@ -1475,7 +1492,11 @@ \end{codeblock} \end{example} -\rSec2[ub.dcl.ref]{References} +\rSec2[ub.dcl.decl]{Declarators} + +\rSec3[ub.dcl.meaning]{Meaning of declarators} + +\rSec4[ub.dcl.ref]{References} \pnum \ubxref{dcl.ref.incompatible.function} @@ -1528,7 +1549,9 @@ -\rSec2[ub.dcl.fct.def.coroutine]{Coroutine definitions} +\rSec2[ub.dcl.fct.def]{Function definitions} + +\rSec3[ub.dcl.fct.def.coroutine]{Coroutine definitions} \pnum \ubxref{dcl.fct.def.coroutine.resume.not.suspended} @@ -1643,7 +1666,9 @@ \end{codeblock} \end{example} -\rSec2[ub.dcl.attr.assume]{Assumption attribute} +\rSec2[ub.dcl.attr]{Attributes} + +\rSec3[ub.dcl.attr.assume]{Assumption attribute} \pnum \ubxref{dcl.attr.assume.false} @@ -1665,7 +1690,7 @@ \end{example} -\rSec2[ub.dcl.attr.noreturn]{Noreturn attribute} +\rSec3[ub.dcl.attr.noreturn]{Noreturn attribute} \pnum \ubxref{dcl.attr.noreturn.eventually.returns} @@ -1689,7 +1714,9 @@ \rSec1[ub.class]{\ref{class}: Classes} -\rSec2[ub.class.dtor]{Destructors} +\rSec2[ub.class.mem]{Class members} + +\rSec3[ub.class.dtor]{Destructors} \pnum \ubxref{class.dtor.no.longer.exists} @@ -1713,7 +1740,9 @@ \end{example} -\rSec2[ub.class.abstract]{Abstract classes} +\rSec2[ub.class.derived]{Derived classes} + +\rSec3[ub.class.abstract]{Abstract classes} \pnum \ubxref{class.abstract.pure.virtual} @@ -1736,7 +1765,9 @@ \end{example} -\rSec2[ub.class.base.init]{Initializing bases and members} +\rSec2[ub.class.init]{Initialization} + +\rSec3[ub.class.base.init]{Initializing bases and members} \pnum \ubxref{class.base.init.mem.fun} @@ -1777,7 +1808,7 @@ \end{example} -\rSec2[ub.class.cdtor]{Construction and destruction} +\rSec3[ub.class.cdtor]{Construction and destruction} \pnum \ubxref{class.cdtor.before.ctor} @@ -2012,7 +2043,10 @@ \rSec1[ub.temp]{\ref{temp}: Templates} -\rSec2[ub.temp.inst]{Implicit instantiation} + +\rSec2[ub.temp.spec]{Template instantiation and specialization} + +\rSec3[ub.temp.inst]{Implicit instantiation} \pnum \ubxref{temp.inst.inf.recursion} From e34badb203102a38536e6790db4740677cc16a5c Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 8 May 2026 19:56:38 -0400 Subject: [PATCH 19/27] [ub] and [ifndr]: section titles in sync with main doc --- source/ifndr.tex | 2 +- source/ub.tex | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 0c46c0a437..216a79a928 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -771,7 +771,7 @@ \rSec3[ifndr.temp.res]{Name resolution} -\rSec3[ifndr.temp.res.general]{General} +\rSec4[ifndr.temp.res.general]{General} \pnum \ifndrxref{temp.res.general.default.but.not.found} diff --git a/source/ub.tex b/source/ub.tex index b9aeab60df..7df8121a35 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -15,7 +15,7 @@ \rSec2[ub.basic.memobj]{Memory and objects} -\rSec3[ub.intro.object]{Implicitly creating object and undefined behavior} +\rSec3[ub.intro.object]{Object model} \pnum \ubxref{intro.object.implicit.create} @@ -97,7 +97,7 @@ %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 ..." -\rSec3[ub.basic.align]{Object alignment} +\rSec3[ub.basic.align]{Alignment} \pnum \ubxref{basic.align.object.alignment} @@ -119,7 +119,7 @@ \end{codeblock} \end{example} -\rSec3[ub.basic.life]{Object lifetime} +\rSec3[ub.basic.life]{Lifetime} \pnum \ubxref{lifetime.outside.pointer.delete} @@ -357,7 +357,7 @@ \rSec3[ub.basic.stc]{Storage duration} -\rSec4[ub.basic.stc.dynamic]{Dynamic storage Duration} +\rSec4[ub.basic.stc.dynamic]{Dynamic storage duration} \pnum \ubxref{basic.stc.alloc.dealloc.constraint} @@ -518,7 +518,7 @@ \rSec3[ub.basic.start]{Start and termination} -\rSec4[ub.basic.start.main]{main function} +\rSec4[ub.basic.start.main]{\tcode{main} function} \pnum \ubxref{basic.start.main.exit.during.destruction} @@ -1346,7 +1346,7 @@ \rSec2[ub.stmt.jump]{Jump statements} -\rSec3[ub.stmt.return]{The return statement} +\rSec3[ub.stmt.return]{The \keyword{return} statement} \pnum \ubxref{stmt.return.flow.off} @@ -1370,7 +1370,7 @@ \end{codeblock} \end{example} -\rSec3[ub.return.coroutine]{The co_return statement} +\rSec3[ub.return.coroutine]{The \keyword{co_return} statement} \pnum \ubxref{stmt.return.coroutine.flow.off} @@ -1460,7 +1460,7 @@ \rSec3[ub.dcl.type]{Type specifiers} -\rSec4[ub.dcl.type.cv]{The cv-qualifiers} +\rSec4[ub.dcl.type.cv]{The \fakegrammarterm{cv-qualifier}{s}} \pnum \ubxref{dcl.type.cv.modify.const.obj} From 470098fc168234a6edb1b3fe62e4025706467af6 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 8 May 2026 23:58:25 -0400 Subject: [PATCH 20/27] [ub] and [ifndr] - fixed sections --- source/ifndr.tex | 127 +++++++++++++++++++++++++---------------------- source/ub.tex | 63 ++++++++--------------- 2 files changed, 87 insertions(+), 103 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 216a79a928..267440c6a7 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -148,6 +148,52 @@ \end{codeblock} \end{example} +\rSec2[ifndr.basic.lookup]{Name lookup} + +\rSec3[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} @@ -155,6 +201,8 @@ \rSec3[ifndr.expr.prim.req]{Requires expressions} +\rSec4[ifndr.expr.prim.req.general]{General} + \pnum \ifndrxref{expr.prim.req.always.sub.fail} If the substitution of template arguments into a \grammarterm{requirement} @@ -171,7 +219,7 @@ \end{example} -\rSec1[ifndr.stmt.stmt]{\ref{stmt}: Statements} +\rSec1[ifndr.stmt]{\ref{stmt}: Statements} \rSec2[ifndr.stmt.ambig]{Ambiguity resolution} @@ -201,7 +249,7 @@ \end{example} -\rSec1[ifndr.dcl.dcl]{\ref{dcl}: Declarations} +\rSec1[ifndr.dcl]{\ref{dcl}: Declarations} \rSec2[ifndr.dcl.spec]{Specifiers} @@ -251,8 +299,6 @@ \rSec3[ifndr.dcl.meaning]{Meaning of declarators} -\rSec4[ifndr.dcl.fct]{Functions} - \rSec4[ifndr.dcl.fct.default]{Default arguments} \pnum @@ -487,52 +533,6 @@ \rSec1[ifndr.class]{\ref{class}: Classes} -\rSec2[ifndr.basic.lookup]{Name lookup} - -\rSec3[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} - \rSec2[ifndr.class.init]{Initialization} \rSec3[ifndr.class.base.init]{Initializing bases and members} @@ -554,7 +554,6 @@ \end{codeblock} \end{example} - \rSec2[ifndr.class.derived]{Derived classes} \rSec3[ifndr.class.virtual]{Virtual functions} @@ -623,6 +622,7 @@ \end{codeblock} \end{example} +\rSec2[ifndr.temp.arg]{Template arguments} \rSec3[ifndr.temp.arg.template]{Template template arguments} @@ -655,8 +655,11 @@ \end{codeblock} \end{example} +\rSec2[ifndr.temp.constr]{Template constraints} + +\rSec3[ifndr.temp.constr.constr]{Constraints} -\rSec4[ifndr.constr.atomic]{Atomic constraints} +\rSec4[ifndr.temp.constr.atomic]{Atomic constraints} \pnum \ifndrxref{temp.constr.atomic.equiv.but.not.equiv} @@ -696,7 +699,6 @@ \end{codeblock} \end{example} - \rSec3[ifndr.temp.constr.normal]{Constraint normalization} \pnum @@ -719,7 +721,11 @@ % not sure if they a really are worth calling distinct cases of ifndr, as they % are all variations on producing an invalid construct upon substitution -\rSec4[ifndr.temp.spec.partial]{Partial specialization} +\rSec2[ifndr.temp.decls]{Template declarations} + +\rSec3[ifndr.temp.spec.partial]{Partial specialization} + +\rSec4[ifndr.temp.spec.partial.general]{General} \pnum \ifndrxref{temp.spec.partial.general.partial.reachable} @@ -745,9 +751,6 @@ \end{example} -\rSec3[ifndr.temp.names]{Names of template specializations} - - \rSec3[ifndr.temp.fct]{Function templates} \rSec4[ifndr.temp.over.link]{Function template overloading} @@ -769,9 +772,9 @@ \end{codeblock} \end{example} -\rSec3[ifndr.temp.res]{Name resolution} +\rSec2[ifndr.temp.res]{Name resolution} -\rSec4[ifndr.temp.res.general]{General} +\rSec3[ifndr.temp.res.general]{General} \pnum \ifndrxref{temp.res.general.default.but.not.found} @@ -788,7 +791,7 @@ %TODO: SY, JMB: We need to produce an example for this case. -\rSec4[ifndr.temp.dep.res]{Dependent name resolution} +\rSec3[ifndr.temp.dep.res]{Dependent name resolution} \rSec4[ifndr.temp.point]{Point of instantiation} @@ -843,6 +846,8 @@ %TODO: JMB: produce an example +\rSec2[ifndr.temp.spec]{Template instantiation and specialization} + \rSec3[ifndr.temp.explicit]{Explicit instantiation} \pnum @@ -898,6 +903,8 @@ \end{codeblock} \end{example} +\rSec2[ifndr.temp.fct.spec]{Function template specializations} + \rSec3[ifndr.temp.deduct]{Template argument deduction} \rSec4[ifndr.temp.deduct.general]{General} diff --git a/source/ub.tex b/source/ub.tex index 7df8121a35..f446787123 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -38,7 +38,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{intro.object.implicit.pointer} After implicitly creating objects within a specified region of storage, @@ -311,7 +310,6 @@ \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 @@ -337,7 +335,6 @@ \rSec3[ub.basic.indet]{Indeterminate and erroneous values} - \pnum \ubxref{basic.indet.value} When the result of an evaluation is @@ -359,6 +356,8 @@ \rSec4[ub.basic.stc.dynamic]{Dynamic storage duration} +\rSec5[ub.basic.stc.dynamic.general]{General} + \pnum \ubxref{basic.stc.alloc.dealloc.constraint} If the behavior of an allocation or deallocation function does not satisfy the semantic constraints @@ -366,7 +365,6 @@ in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}. the behavior is undefined. - \pnum \begin{example} \begin{codeblock} @@ -384,6 +382,8 @@ \end{codeblock} \end{example} +\rSec5[ub.basic.stc.dynamic.deallocation]{Deallocation functions} + \pnum \ubxref{basic.stc.alloc.dealloc.throw} If a call to a deallocation function @@ -403,9 +403,7 @@ \end{codeblock} \end{example} - - -\rSec5[ub.basic.stc.alloc.zero.dereference]{Zero-sized allocation dereference} +\rSec5[ub.basic.stc.dynamic.allocation]{Allocation functions} \pnum \ubxref{basic.stc.alloc.zero.dereference} @@ -450,7 +448,6 @@ \end{codeblock} \end{example} - \rSec2[ub.basic.exec]{Program execution} \rSec3[ub.intro.execution]{Sequential execution} @@ -475,6 +472,8 @@ \end{codeblock} \end{example} +\rSec3[ub.intro.multithread]{Multi-threaded executions and data races} + \rSec4[ub.intro.races]{Data races} \pnum @@ -542,7 +541,6 @@ \end{codeblock} \end{example} - \rSec4[ub.basic.start.term]{Termination} \pnum @@ -578,7 +576,6 @@ \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 @@ -592,7 +589,7 @@ %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} +\rSec2[ub.expr.pre]{Preamble} \pnum \ubxref{expr.expr.eval} @@ -613,6 +610,8 @@ \end{codeblock} \end{example} +\rSec2[ub.expr.prop]{Properties of expressions} + \rSec3[ub.basic.lval]{Value category} \pnum @@ -679,6 +678,8 @@ \end{codeblock} \end{example} +\rSec2[ub.conv]{Standard conversions} + \rSec3[ub.conv.lval]{Lvalue-to-rvalue conversion} \pnum @@ -702,7 +703,6 @@ \end{codeblock} \end{example} - \rSec3[ub.conv.double]{Floating-point conversions} \pnum @@ -725,7 +725,6 @@ \end{codeblock} \end{example} - \rSec3[ub.conv.fpint]{Floating-integral conversions} \pnum @@ -817,6 +816,9 @@ \end{example} +\rSec2[ub.expr.compound]{Compound expressions} + +\rSec3[ub.expr.post]{Postfix expressions} \rSec4[ub.expr.call]{Function call} @@ -869,7 +871,6 @@ \rSec4[ub.expr.dynamic.cast]{Dynamic cast} - \pnum \ubxref{expr.dynamic.cast.pointer.lifetime} Evaluating a \keyword{dynamic_cast} on a non-null pointer that points to @@ -887,7 +888,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{expr.dynamic.cast.glvalue.lifetime} Evaluating a \keyword{dynamic_cast} on a reference that @@ -965,7 +965,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{expr.static.cast.downcast.wrong.derived.type} Casting from a pointer to a base class to a pointer to a derived class @@ -998,7 +997,6 @@ containing the original member; otherwise the behavior is undefined. - \pnum \begin{example} \begin{codeblock} @@ -1019,6 +1017,8 @@ \end{codeblock} \end{example} +\rSec3[ub.expr.unary]{Unary expressions} + \rSec4[ub.expr.unary.op]{Unary operators} \pnum @@ -1037,7 +1037,6 @@ \end{codeblock} \end{example} - \rSec4[ub.expr.new]{New} \pnum @@ -1069,7 +1068,6 @@ \end{codeblock} \end{example} - \rSec4[ub.expr.delete]{Delete} \pnum @@ -1096,7 +1094,6 @@ \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 @@ -1122,7 +1119,6 @@ \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. @@ -1148,7 +1144,6 @@ \end{codeblock} \end{example} - \rSec3[ub.expr.mptr.oper]{Pointer-to-member operators} \pnum @@ -1173,7 +1168,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{expr.mptr.oper.member.func.null} If the second operand in a \tcode{.*} expression is the null @@ -1194,7 +1188,6 @@ \end{codeblock} \end{example} - \rSec3[ub.expr.mul]{Multiplicative operators} \pnum @@ -1308,7 +1301,6 @@ \end{codeblock} \end{example} - \rSec3[ub.expr.shift]{Shift operators} \pnum @@ -1326,7 +1318,6 @@ \end{codeblock} \end{example} - \rSec3[ub.expr.assign]{Assignment and compound assignment operators} \pnum @@ -1342,7 +1333,7 @@ \end{codeblock} \end{example} -\rSec1[ub.stmt.stmt]{\ref{stmt}: Statements} +\rSec1[ub.stmt]{\ref{stmt}: Statements} \rSec2[ub.stmt.jump]{Jump statements} @@ -1370,7 +1361,7 @@ \end{codeblock} \end{example} -\rSec3[ub.return.coroutine]{The \keyword{co_return} statement} +\rSec3[ub.stmt.return.coroutine]{The \keyword{co_return} statement} \pnum \ubxref{stmt.return.coroutine.flow.off} @@ -1453,8 +1444,7 @@ - -\rSec1[ub.dcl.dcl]{\ref{dcl}: Declarations} +\rSec1[ub.dcl]{\ref{dcl}: Declarations} \rSec2[ub.dcl.spec]{Specifiers} @@ -1476,7 +1466,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{dcl.type.cv.access.volatile} If an attempt is made to @@ -1548,7 +1537,6 @@ - \rSec2[ub.dcl.fct.def]{Function definitions} \rSec3[ub.dcl.fct.def.coroutine]{Coroutine definitions} @@ -1609,7 +1597,6 @@ \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. @@ -1689,7 +1676,6 @@ \end{codeblock} \end{example} - \rSec3[ub.dcl.attr.noreturn]{Noreturn attribute} \pnum @@ -1711,7 +1697,6 @@ \end{codeblock} \end{example} - \rSec1[ub.class]{\ref{class}: Classes} \rSec2[ub.class.mem]{Class members} @@ -1739,7 +1724,6 @@ \end{codeblock} \end{example} - \rSec2[ub.class.derived]{Derived classes} \rSec3[ub.class.abstract]{Abstract classes} @@ -1764,7 +1748,6 @@ \end{codeblock} \end{example} - \rSec2[ub.class.init]{Initialization} \rSec3[ub.class.base.init]{Initializing bases and members} @@ -1807,7 +1790,6 @@ \end{codeblock} \end{example} - \rSec3[ub.class.cdtor]{Construction and destruction} \pnum @@ -1859,7 +1841,6 @@ %TODO: CM: Can this example be shortened? - \pnum \ubxref{class.cdtor.after.dtor} For an object with a non-trivial destructor, @@ -1979,7 +1960,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{class.cdtor.typeid} If the operand of \tcode{typeid} refers to @@ -2010,7 +1990,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{class.cdtor.dynamic.cast} If the operand of the @@ -2041,7 +2020,6 @@ \end{codeblock} \end{example} - \rSec1[ub.temp]{\ref{temp}: Templates} \rSec2[ub.temp.spec]{Template instantiation and specialization} @@ -2069,7 +2047,6 @@ \end{codeblock} \end{example} - \rSec1[ub.except]{\ref{except}: Exception handling} \rSec2[ub.except.handle]{Handling an exception} From 93c058829ef3cc595cb66e0a225240cf59265d95 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Mon, 18 May 2026 14:19:12 -0400 Subject: [PATCH 21/27] macros.tex; added missing newline after \ifndrxref to match \ubxref --- source/macros.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/macros.tex b/source/macros.tex index dad5db884e..53d350fac1 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -395,7 +395,7 @@ % 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}} +\newcommand{\ifndrxref}[1]{\label{ifndrx:#1}\textbf{Specified in:}\space\ref{ifndr:#1}\newline} %% Cross-reference \newcommand{\xref}[1]{\textsc{See also:}\space #1} From f9d56c0452126d438ca764671fee065bfe0a8757 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 19 May 2026 08:10:11 -0400 Subject: [PATCH 22/27] [ub] and [ifndr] - remaining wording todos reformatted slightly, some cleaned up --- source/ifndr.tex | 13 ++++--------- source/ub.tex | 10 +++++----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 267440c6a7..9fb6dd31ff 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -716,11 +716,6 @@ \end{codeblock} \end{example} - -%TODO: JMB: 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, as they -% are all variations on producing an invalid construct upon substitution - \rSec2[ifndr.temp.decls]{Template declarations} \rSec3[ifndr.temp.spec.partial]{Partial specialization} @@ -789,7 +784,7 @@ \end{codeblock} \end{example} -%TODO: SY, JMB: We need to produce an example for this case. +%WORDINGTODO: SY, JMB: We need to produce an example for this case. \rSec3[ifndr.temp.dep.res]{Dependent name resolution} @@ -843,7 +838,7 @@ \end{codeblock} \end{example} -%TODO: JMB: produce an example +%WORDINGTODO: JMB: produce an example \rSec2[ifndr.temp.spec]{Template instantiation and specialization} @@ -885,7 +880,7 @@ \end{codeblock} \end{example} -%TODO: JMB: produce an example +%WORDINGTODO: JMB: produce an example \pnum \ifndrxref{temp.expl.spec.missing.definition} @@ -934,7 +929,7 @@ \end{codeblock} \end{example} -%TODO: JMB: Someone should confirm that the comments correctly describe why +%WORDINGTODO: JMB: Someone should confirm that the comments correctly describe why %this example is ill-formed. diff --git a/source/ub.tex b/source/ub.tex index f446787123..241b06512d 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -91,7 +91,7 @@ \end{codeblock} \end{example} -%TODO: SY: These comments feel too loose. +%WORDINGTODO: 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 ..." @@ -582,11 +582,11 @@ 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. -%TODO: JMB/TD: This is really a general precondition imposed on the Standard +%WORDINGTODO: JMB/TD: This is really a general precondition imposed on the Standard %Library, not a piece of core language undefined behavior. It is also currently %missing an example. Should we retain this UB? Should we have a core issue %to move this wording into the library section somewhere? -%TODO: SY: If we keep this, we should have an example. +%WORDINGTODO: SY: If we keep this, we should have an example. \rSec1[ub.expr]{\ref{expr}: Expressions} \rSec2[ub.expr.pre]{Preamble} @@ -866,7 +866,7 @@ \end{codeblock} \end{example} -%TODO: SY: The wording is not great, I don't have a good suggestion but we should +%WORDINGTODO: SY: The wording is not great, I don't have a good suggestion but we should %get some opinions \rSec4[ub.expr.dynamic.cast]{Dynamic cast} @@ -1839,7 +1839,7 @@ \end{codeblock} \end{example} -%TODO: CM: Can this example be shortened? +%WORDINGTODO: CM: Can this example be shortened? \pnum \ubxref{class.cdtor.after.dtor} From 095c1878c46998115338487539606eae912f81f4 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 28 May 2026 19:16:35 -0400 Subject: [PATCH 23/27] [ub] and [ifndr] - changed structure of ubxref and ifndrxref macros to be like \definition --- source/ifndr.tex | 181 +++++++--------------------- source/macros.tex | 53 +++++++-- source/ub.tex | 298 ++++++++++++++++++---------------------------- 3 files changed, 206 insertions(+), 326 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 9fb6dd31ff..4260712670 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -11,10 +11,9 @@ \rSec1[ifndr.lex]{\ref{lex}: Lexical conventions} -\rSec2[ifndr.lex.name]{Identifiers} +\ifndrxref{lex.name.reserved} \pnum -\ifndrxref{lex.name.reserved} Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no diagnostic is required. @@ -31,13 +30,11 @@ \end{codeblock} \end{example} - \rSec1[ifndr.basic]{\ref{basic}: Basics} -\rSec2[ifndr.basic.link]{Program and linkage} +\ifndrxref{basic.link.consistent.types} \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. @@ -61,10 +58,9 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.basic.def.odr]{One-definition rule} +\ifndrxref{basic.def.odr.exact.one.def} \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. @@ -82,14 +78,13 @@ \end{codeblock} \end{example} +\ifndrxref{basic.def.odr.unnamed.enum.same.type} \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} @@ -107,13 +102,9 @@ \end{codeblock} \end{example} - -\rSec2[ifndr.basic.contract]{Contract assertions} - -\rSec3[ifndr.basic.contract.general]{General} +\ifndrxref{basic.contract.vastart.contract.predicate} \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; @@ -129,10 +120,9 @@ \end{codeblock} \end{example} -\rSec3[ifndr.basic.contract.handler]{Contract-violation handler} +\ifndrxref{basic.contract.handler.replacing.nonreplaceable} \pnum -\ifndrxref{basic.contract.handler.replacing.nonreplaceable} On platforms where the contract-violation handler is not replaceable\iref{term.replaceable.function} @@ -148,12 +138,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.basic.lookup]{Name lookup} - -\rSec3[ifndr.class.member.lookup]{Member name lookup} +\ifndrxref{class.member.lookup.name.refers.diff.decl} \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 @@ -194,17 +181,11 @@ \end{codeblock} \end{example} - \rSec1[ifndr.expr]{\ref{expr}: Expressions} -\rSec2[ifndr.expr.prim]{Primary expressions} - -\rSec3[ifndr.expr.prim.req]{Requires expressions} - -\rSec4[ifndr.expr.prim.req.general]{General} +\ifndrxref{expr.prim.req.always.sub.fail} \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. @@ -218,13 +199,11 @@ \end{codeblock} \end{example} - \rSec1[ifndr.stmt]{\ref{stmt}: Statements} -\rSec2[ifndr.stmt.ambig]{Ambiguity resolution} +\ifndrxref{stmt.ambig.bound.diff.parse} \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. @@ -248,15 +227,11 @@ \end{codeblock} \end{example} - \rSec1[ifndr.dcl]{\ref{dcl}: Declarations} -\rSec2[ifndr.dcl.spec]{Specifiers} - -\rSec3[ifndr.dcl.constinit]{The \keyword{constinit} specifier} +\ifndrxref{dcl.constinit.specifier.not.reachable} \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 @@ -273,10 +248,9 @@ \end{codeblocktu} \end{example} -\rSec3[ifndr.dcl.inline]{The \keyword{inline} specifier} +\ifndrxref{dcl.inline.missing.on.definition} \pnum -\ifndrxref{dcl.inline.missing.on.definition} If a function or variable with external or module linkage is declared inline @@ -295,14 +269,9 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.dcl.decl]{Declarators} - -\rSec3[ifndr.dcl.meaning]{Meaning of declarators} - -\rSec4[ifndr.dcl.fct.default]{Default arguments} +\ifndrxref{dcl.fct.default.inline.same.defaults} \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 @@ -323,12 +292,9 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.dcl.contract]{Function contract specifiers} - -\rSec3[ifndr.dcl.contract.func]{General} +\ifndrxref{dcl.contract.func.mismatched.contract.specifiers} \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 @@ -348,12 +314,9 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.dcl.fct.def]{Function definitions} - -\rSec3[ifndr.dcl.fct.def.replace]{Replaceable function definitions} +\ifndrxref{dcl.fct.def.replace.bad.replacement} \pnum -\ifndrxref{dcl.fct.def.replace.bad.replacement} A declaration of a replaceable function that is inline, not attached to the global module, @@ -376,10 +339,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.dcl.link]{Linkage specifications} +\ifndrxref{dcl.link.mismatched.language.linkage} \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 @@ -391,12 +353,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.dcl.attr]{Attributes} - -\rSec3[ifndr.dcl.align]{Alignment specifier} +\ifndrxref{dcl.align.diff.translation.units} \pnum -\ifndrxref{dcl.align.diff.translation.units} No diagnostic is required if declarations of an entity have different \grammarterm{alignment-specifier}s in different translation units. @@ -411,10 +370,9 @@ \end{codeblocktu} \end{example} -\rSec3[ifndr.dcl.attr.indet]{Indeterminate storage} +\ifndrxref{dcl.attr.indet.mismatched.declarations} \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, @@ -430,10 +388,9 @@ \end{codeblocktu} \end{example} -\rSec3[ifndr.dcl.attr.noreturn]{Noreturn attribute} +\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} \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 @@ -451,10 +408,9 @@ \rSec1[ifndr.module]{\ref{module}: Modules} -\rSec2[ifndr.module.unit]{Module units and purviews} +\ifndrxref{module.unit.reserved.identifiers} \pnum -\ifndrxref{module.unit.reserved.identifiers} All \grammarterm{module-name}s either beginning with an identifier consisting of std followed by zero or more digits or containing a reserved identifier\iref{lex.token} are reserved and shall not be specified in a \grammarterm{module-declaration}; no diagnostic is required. @@ -470,9 +426,9 @@ \end{codeblock} \end{example} +\ifndrxref{module.unit.named.module.no.partition} \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. @@ -485,8 +441,9 @@ \end{codeblock} \end{example} -\pnum \ifndrxref{module.unit.unexported.module.partition} + +\pnum If a module partition of a module that is a module interface unit but is not directly or indirectly exported @@ -511,10 +468,9 @@ \end{codeblocktu} \end{example} -\rSec2[ifndr.module.private.frag]{Private module fragment} +\ifndrxref{module.private.frag.other.module.units} \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. @@ -530,15 +486,11 @@ \end{codeblocktu} \end{example} - \rSec1[ifndr.class]{\ref{class}: Classes} -\rSec2[ifndr.class.init]{Initialization} - -\rSec3[ifndr.class.base.init]{Initializing bases and members} +\ifndrxref{class.base.init.delegate.itself} \pnum -\ifndrxref{class.base.init.delegate.itself} If a constructor delegates to itself directly or indirectly, the program is ill-formed, no diagnostic required @@ -554,12 +506,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.class.derived]{Derived classes} - -\rSec3[ifndr.class.virtual]{Virtual functions} +\ifndrxref{class.virtual.pure.or.defined} \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 @@ -576,13 +525,11 @@ \end{codeblock} \end{example} - \rSec1[ifndr.over]{\ref{over}: Overloading} -\rSec2[ifndr.over.literal]{User-defined literals} +\ifndrxref{over.literal.reserved} \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. @@ -597,10 +544,9 @@ \rSec1[ifndr.temp]{\ref{temp}: Templates} -\rSec2[ifndr.temp.pre]{Preamble} +\ifndrxref{temp.pre.reach.def} \pnum -\ifndrxref{temp.pre.reach.def} A definition of a function template, member function of a class template, variable template, or static data member of a class template shall be reachable from the end of every definition domain\iref{basic.def.odr} in which it is implicitly instantiated\iref{temp.inst} unless the corresponding specialization is explicitly instantiated\iref{temp.explicit} in @@ -622,12 +568,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.arg]{Template arguments} - -\rSec3[ifndr.temp.arg.template]{Template template arguments} +\ifndrxref{temp.arg.template.sat.constraints} \pnum -\ifndrxref{temp.arg.template.sat.constraints} Any partial specializations\iref{temp.spec.partial} associated with the primary template are considered when a specialization based on the template template-parameter is instantiated. If a specialization is not reachable from the point of instantiation, and it would have been selected had it been reachable, the program is ill-formed, no diagnostic @@ -655,14 +598,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.constr]{Template constraints} - -\rSec3[ifndr.temp.constr.constr]{Constraints} - -\rSec4[ifndr.temp.constr.atomic]{Atomic constraints} +\ifndrxref{temp.constr.atomic.equiv.but.not.equiv} \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. @@ -681,8 +619,9 @@ \end{codeblock} \end{example} -\pnum \ifndrxref{temp.constr.atomic.sat.result.diff} + +\pnum 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 @@ -699,10 +638,9 @@ \end{codeblock} \end{example} -\rSec3[ifndr.temp.constr.normal]{Constraint normalization} +\ifndrxref{temp.constr.normal.invalid} \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 @@ -716,14 +654,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.decls]{Template declarations} - -\rSec3[ifndr.temp.spec.partial]{Partial specialization} - -\rSec4[ifndr.temp.spec.partial.general]{General} +\ifndrxref{temp.spec.partial.general.partial.reachable} \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. @@ -745,13 +678,9 @@ \end{codeblock} \end{example} - -\rSec3[ifndr.temp.fct]{Function templates} - -\rSec4[ifndr.temp.over.link]{Function template overloading} +\ifndrxref{temp.over.link.equiv.not.equiv} \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. @@ -767,12 +696,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.res]{Name resolution} - -\rSec3[ifndr.temp.res.general]{General} +\ifndrxref{temp.res.general.default.but.not.found} \pnum -\ifndrxref{temp.res.general.default.but.not.found} If the validity or meaning of the program would be changed by considering a default argument or default template argument introduced in a declaration that is reachable from the point of instantiation of a specialization\iref{temp.point} but is not found by lookup for the specialization, the program is ill-formed, no @@ -786,12 +712,9 @@ %WORDINGTODO: SY, JMB: We need to produce an example for this case. -\rSec3[ifndr.temp.dep.res]{Dependent name resolution} - -\rSec4[ifndr.temp.point]{Point of instantiation} +\ifndrxref{temp.point.diff.pt.diff.meaning} \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 @@ -821,10 +744,9 @@ \end{codeblock} \end{example} -\rSec4[ifndr.temp.dep.candidate]{Candidate functions} +\ifndrxref{temp.dep.candidate.different.lookup.different} \pnum -\ifndrxref{temp.dep.candidate.different.lookup.different} If considering all function declarations with external linkage in the associated namespaces in all translations @@ -840,13 +762,9 @@ %WORDINGTODO: JMB: produce an example - -\rSec2[ifndr.temp.spec]{Template instantiation and specialization} - -\rSec3[ifndr.temp.explicit]{Explicit instantiation} +\ifndrxref{temp.explicit.decl.implicit.inst} \pnum -\ifndrxref{temp.explicit.decl.implicit.inst} An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation\iref{temp.inst} in the translation unit shall be the subject of an explicit instantiation definition @@ -865,10 +783,9 @@ \end{codeblock} \end{example} -\rSec3[ifndr.temp.expl.spec]{Explicit specialization} +\ifndrxref{temp.expl.spec.unreachable.declaration} \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, @@ -882,8 +799,9 @@ %WORDINGTODO: JMB: produce an example -\pnum \ifndrxref{temp.expl.spec.missing.definition} + +\pnum If an explicit specialization of a template is declared but there is no definition provided for that specialization, @@ -898,14 +816,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.fct.spec]{Function template specializations} - -\rSec3[ifndr.temp.deduct]{Template argument deduction} - -\rSec4[ifndr.temp.deduct.general]{General} +\ifndrxref{temp.deduct.general.diff.order} \pnum -\ifndrxref{temp.deduct.general.diff.order} If substitution into different declarations of the same function template @@ -932,13 +845,11 @@ %WORDINGTODO: 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} +\ifndrxref{cpp.cond.defined.after.macro} \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. @@ -952,8 +863,9 @@ \end{codeblock} \end{example} -\pnum \ifndrxref{cpp.cond.defined.malformed} + +\pnum If the \tcode{defined} unary operator is used when it does not match one of the specified grammatical forms, @@ -970,10 +882,9 @@ \end{codeblock} \end{example} -\rSec2[ifndr.cpp.include]{Source file inclusion} +\ifndrxref{cpp.include.malformed.headername} \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} diff --git a/source/macros.tex b/source/macros.tex index 53d350fac1..c38df98737 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -386,17 +386,6 @@ \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}\newline} - %% Cross-reference \newcommand{\xref}[1]{\textsc{See also:}\space #1} \newcommand{\xrefc}[1]{\xref{\IsoC{}, #1}} @@ -812,3 +801,45 @@ } \newcommand{\defncontext}[1]{\textlangle#1\textrangle} \newnoteenvironment{defnote}{Note \arabic{defnote} to entry}{end note} + +%%---------------------------------- +%% UB and IFNDR sections for annexes +%%---------------------------------- +%% 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 for sections describing each individual IFNDR +\newcommand{\ubxref}[1]{% +\let\oldcontentsline\addcontentsline% +\let\addcontentsline\nocontentsline% +\ifcase\value{SectionDepth} + \let\s=\section + \or\let\s=\subsection + \or\let\s=\subsubsection + \or\let\s=\paragraph + \or\let\s=\subparagraph + \fi% +\s[#1]{\hfill[#1]}\vspace{-.3\onelineskip}\label{ubx:#1} % +\textbf{Specified in:}\space\ref{ub:#1}% +\let\addcontentsline\oldcontentsline% +\vspace{-\parskip}% +} + +% Use in main body of text to mark IFNDR +\newcommand{\ifndrdef}[1]{\nolinebreak[3] (\label{ifndr:#1}\ref{ifndrx:#1})} +\newcommand{\ifndrxref}[1]{% +\let\oldcontentsline\addcontentsline% +\let\addcontentsline\nocontentsline% +\ifcase\value{SectionDepth} + \let\s=\section + \or\let\s=\subsection + \or\let\s=\subsubsection + \or\let\s=\paragraph + \or\let\s=\subparagraph + \fi% +\s[#1]{\hfill[#1]}\vspace{-.3\onelineskip}\label{ifndrx:#1} % +\textbf{Specified in:}\space\ref{ifndr:#1}% +\let\addcontentsline\oldcontentsline% +\vspace{-\parskip}% +} diff --git a/source/ub.tex b/source/ub.tex index 241b06512d..ec7db7dc2f 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -13,12 +13,9 @@ \rSec1[ub.basic]{\ref{basic}: Basics} -\rSec2[ub.basic.memobj]{Memory and objects} - -\rSec3[ub.intro.object]{Object model} +\ubxref{intro.object.implicit.create} \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 @@ -38,8 +35,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{intro.object.implicit.pointer} + +\pnum 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}. @@ -96,10 +94,9 @@ %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 ..." -\rSec3[ub.basic.align]{Alignment} +\ubxref{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. @@ -118,10 +115,9 @@ \end{codeblock} \end{example} -\rSec3[ub.basic.life]{Lifetime} +\ubxref{lifetime.outside.pointer.delete} \pnum -\ubxref{lifetime.outside.pointer.delete} For a pointer pointing to an object outside of its lifetime, behavior is undefined if the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a \grammarterm{delete-expression}. @@ -143,8 +139,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.pointer.member} + +\pnum 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. @@ -166,8 +163,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.pointer.virtual} + +\pnum For a pointer pointing to an object outside of its lifetime, behavior is undefined if the pointer is implicitly converted\iref{conv.ptr} to a pointer to a virtual base class (or base class of a virtual base class). @@ -186,8 +184,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.pointer.dynamic.cast} + +\pnum 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}. @@ -207,8 +206,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.glvalue.access} + +\pnum Behavior is undefined if a glvalue referring to an object outside of its lifetime is used to access the object. @@ -225,8 +225,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.glvalue.member} + +\pnum 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. @@ -246,8 +247,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.glvalue.virtual} + +\pnum Behavior is undefined if a glvalue referring to an object outside of its lifetime is bound to a reference to a virtual base class. @@ -266,8 +268,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{lifetime.outside.glvalue.dynamic.cast} + +\pnum 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}. @@ -287,8 +290,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{original.type.implicit.destructor} + +\pnum The behavior is undefined if a non-trivial implicit destructor call occurs when the type of the object inhabiting the associated storage @@ -310,8 +314,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{creating.within.const.complete.obj} + +\pnum 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 @@ -333,10 +338,9 @@ \end{codeblock} \end{example} -\rSec3[ub.basic.indet]{Indeterminate and erroneous values} +\ubxref{basic.indet.value} \pnum -\ubxref{basic.indet.value} When the result of an evaluation is an indeterminate value (but not just an erroneous value) @@ -352,14 +356,9 @@ \end{codeblock} \end{example} -\rSec3[ub.basic.stc]{Storage duration} - -\rSec4[ub.basic.stc.dynamic]{Dynamic storage duration} - -\rSec5[ub.basic.stc.dynamic.general]{General} +\ubxref{basic.stc.alloc.dealloc.constraint} \pnum -\ubxref{basic.stc.alloc.dealloc.constraint} If the behavior of an allocation or deallocation function does not satisfy the semantic constraints specified in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}. @@ -382,10 +381,9 @@ \end{codeblock} \end{example} -\rSec5[ub.basic.stc.dynamic.deallocation]{Deallocation functions} +\ubxref{basic.stc.alloc.dealloc.throw} \pnum -\ubxref{basic.stc.alloc.dealloc.throw} If a call to a deallocation function terminates by throwing an exception the behavior is undefined. @@ -403,10 +401,9 @@ \end{codeblock} \end{example} -\rSec5[ub.basic.stc.dynamic.allocation]{Allocation functions} +\ubxref{basic.stc.alloc.zero.dereference} \pnum -\ubxref{basic.stc.alloc.zero.dereference} The pointer returned when invoking an allocation function with a size of zero cannot be dereferenced. @@ -421,12 +418,9 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.types]{Types} - -\rSec3[ub.basic.compound]{Compound types} +\ubxref{basic.compound.invalid.pointer} \pnum -\ubxref{basic.compound.invalid.pointer} Indirection or the invocation of a deallocation function with a pointer value referencing storage @@ -448,12 +442,9 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.exec]{Program execution} - -\rSec3[ub.intro.execution]{Sequential execution} +\ubxref{intro.execution.unsequenced.modification} \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 @@ -472,12 +463,9 @@ \end{codeblock} \end{example} -\rSec3[ub.intro.multithread]{Multi-threaded executions and data races} - -\rSec4[ub.intro.races]{Data races} +\ubxref{intro.races.data} \pnum -\ubxref{intro.races.data} The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, at least one of which is not atomic, and neither happens before the other, except for the special case for signal handlers described in~\ref{intro.races}. Any such data race results in undefined behavior. @@ -492,10 +480,9 @@ \end{codeblock} \end{example} -\rSec4[ub.intro.progress]{Forward progress} +\ubxref{intro.progress.stops} \pnum -\ubxref{intro.progress.stops} The behavior is undefined if a thread of execution that has not terminated stops making execution steps. @@ -515,12 +502,9 @@ \end{codeblock} \end{example} -\rSec3[ub.basic.start]{Start and termination} - -\rSec4[ub.basic.start.main]{\tcode{main} function} +\ubxref{basic.start.main.exit.during.destruction} \pnum -\ubxref{basic.start.main.exit.during.destruction} If \tcode{std::exit} is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior. @@ -541,10 +525,9 @@ \end{codeblock} \end{example} -\rSec4[ub.basic.start.term]{Termination} +\ubxref{basic.start.term.use.after.destruction} \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 @@ -576,8 +559,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{basic.start.term.signal.handler} + +\pnum 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. @@ -589,10 +573,10 @@ %WORDINGTODO: SY: If we keep this, we should have an example. \rSec1[ub.expr]{\ref{expr}: Expressions} -\rSec2[ub.expr.pre]{Preamble} -\pnum \ubxref{expr.expr.eval} + +\pnum 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. @@ -610,12 +594,9 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.prop]{Properties of expressions} - -\rSec3[ub.basic.lval]{Value category} +\ubxref{expr.basic.lvalue.strict.aliasing.violation} \pnum -\ubxref{expr.basic.lvalue.strict.aliasing.violation} If a program attempts to access\iref{defns.access} the stored value of an object whose dynamic type is $T$ through a glvalue whose type is not similar\iref{conv.rval} to $T$ (or its corresponding signed or unsigned types) @@ -639,8 +620,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.basic.lvalue.union.initialization} + +\pnum 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 @@ -658,10 +640,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.type]{Type} +\ubxref{expr.type.reference.lifetime} \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. @@ -678,12 +659,9 @@ \end{codeblock} \end{example} -\rSec2[ub.conv]{Standard conversions} - -\rSec3[ub.conv.lval]{Lvalue-to-rvalue conversion} +\ubxref{conv.lval.valid.representation} \pnum -\ubxref{conv.lval.valid.representation} Performing an lvalue-to-rvalue conversion on an object whose @@ -703,10 +681,9 @@ \end{codeblock} \end{example} -\rSec3[ub.conv.double]{Floating-point conversions} +\ubxref{conv.double.out.of.range} \pnum -\ubxref{conv.double.out.of.range} Converting a floating point value to a type that cannot represent the value is undefined behavior. \pnum @@ -725,10 +702,9 @@ \end{codeblock} \end{example} -\rSec3[ub.conv.fpint]{Floating-integral conversions} +\ubxref{conv.fpint.int.not.represented} \pnum -\ubxref{conv.fpint.int.not.represented} When converting a floating-point value to an integer type and vice versa if the value is not representable in the destination type it is undefined behavior. @@ -746,8 +722,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{conv.fpint.float.not.represented} + +\pnum 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. @@ -764,10 +741,9 @@ \end{codeblock} \end{example} -\rSec3[ub.conv.ptr]{Pointer conversions} +\ubxref{conv.ptr.virtual.base} \pnum -\ubxref{conv.ptr.virtual.base} Converting a pointer to a derived class \tcode{D} to @@ -790,10 +766,9 @@ \end{codeblock} \end{example} -\rSec3[ub.conv.mem]{Pointer-to-member conversions} +\ubxref{conv.member.missing.member} \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 @@ -815,15 +790,9 @@ \end{codeblock} \end{example} - -\rSec2[ub.expr.compound]{Compound expressions} - -\rSec3[ub.expr.post]{Postfix expressions} - -\rSec4[ub.expr.call]{Function call} +\ubxref{expr.call.different.type} \pnum -\ubxref{expr.call.different.type} Calling a function through an expression whose function type is not call-compatible with the function type of the called @@ -846,10 +815,9 @@ \end{codeblock} \end{example} -\rSec4[ub.expr.ref]{Class member access} +\ubxref{expr.ref.member.not.similar} \pnum -\ubxref{expr.ref.member.not.similar} If \tcode{E2} is a non-static member and the result of \tcode{E1} is an object whose type is not similar\iref{conv.qual} to the type of \tcode{E1}, the behavior is undefined. @@ -869,10 +837,9 @@ %WORDINGTODO: SY: The wording is not great, I don't have a good suggestion but we should %get some opinions -\rSec4[ub.expr.dynamic.cast]{Dynamic cast} +\ubxref{expr.dynamic.cast.pointer.lifetime} \pnum -\ubxref{expr.dynamic.cast.pointer.lifetime} Evaluating a \keyword{dynamic_cast} on a non-null pointer that points to an object (of polymorphic type) of the wrong type or to an object not within its lifetime has undefined behavior. @@ -888,8 +855,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.dynamic.cast.glvalue.lifetime} + +\pnum 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. @@ -905,10 +873,9 @@ \end{codeblock} \end{example} -\rSec4[ub.expr.static.cast]{Static cast} +\ubxref{expr.static.cast.base.class} \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. @@ -927,8 +894,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.static.cast.enum.outside.range} + +\pnum 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. @@ -944,8 +912,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.static.cast.fp.outside.range} + +\pnum An explicit conversion of a floating-point value that is outside the range of the target type has undefined behavior. @@ -965,8 +934,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.static.cast.downcast.wrong.derived.type} + +\pnum 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. @@ -985,8 +955,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.static.cast.does.not.contain.orignal.member} + +\pnum A pointer to member of derived class D can be cast to @@ -1017,12 +988,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.unary]{Unary expressions} - -\rSec4[ub.expr.unary.op]{Unary operators} +\ubxref{expr.unary.dereference} \pnum -\ubxref{expr.unary.dereference} Dereferencing a pointer that does not point to an object or function has undefined behavior. @@ -1037,10 +1005,9 @@ \end{codeblock} \end{example} -\rSec4[ub.expr.new]{New} +\ubxref{expr.new.non.allocating.null} \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. @@ -1068,10 +1035,9 @@ \end{codeblock} \end{example} -\rSec4[ub.expr.delete]{Delete} +\ubxref{expr.delete.mismatch} \pnum -\ubxref{expr.delete.mismatch} Using array delete on the result of a single object new expression is undefined behavior. \pnum @@ -1082,8 +1048,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.delete.array.mismatch} + +\pnum Using single object delete on the result of an array new expression is undefined behavior. \pnum @@ -1094,8 +1061,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.delete.dynamic.type.differ} + +\pnum If the static type of the object to be deleted is different from its dynamic type and the selected deallocation function is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual @@ -1119,8 +1087,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.delete.dynamic.array.dynamic.type.differ} + +\pnum 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 @@ -1144,10 +1113,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.mptr.oper]{Pointer-to-member operators} +\ubxref{expr.mptr.oper.not.contain.member} \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. @@ -1168,8 +1136,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.mptr.oper.member.func.null} + +\pnum If the second operand in a \tcode{.*} expression is the null member pointer value\iref{conv.mem}, the behavior is undefined. @@ -1188,10 +1157,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.mul]{Multiplicative operators} +\ubxref{expr.mul.div.by.zero} \pnum -\ubxref{expr.mul.div.by.zero} Division by zero is undefined behavior. \pnum @@ -1206,8 +1174,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.mul.representable.type.result} + +\pnum 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. @@ -1225,10 +1194,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.add]{Additive operators} +\ubxref{expr.add.out.of.bounds} \pnum -\ubxref{expr.add.out.of.bounds} Creating an out of bounds pointer is undefined behavior. \pnum @@ -1253,8 +1221,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.add.sub.diff.pointers} + +\pnum Subtracting pointers that are not part of the same array is undefined behavior. \pnum @@ -1271,8 +1240,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{expr.add.not.similar} + +\pnum 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. @@ -1301,10 +1271,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.shift]{Shift operators} +\ubxref{expr.shift.neg.and.width} \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 @@ -1318,10 +1287,9 @@ \end{codeblock} \end{example} -\rSec3[ub.expr.assign]{Assignment and compound assignment operators} +\ubxref{expr.assign.overlap} \pnum -\ubxref{expr.assign.overlap} Overlap in the storage between the source and destination may result in undefined behavior. \pnum @@ -1335,12 +1303,9 @@ \rSec1[ub.stmt]{\ref{stmt}: Statements} -\rSec2[ub.stmt.jump]{Jump statements} - -\rSec3[ub.stmt.return]{The \keyword{return} statement} +\ubxref{stmt.return.flow.off} \pnum -\ubxref{stmt.return.flow.off} Flowing off the end of a function other than main or a coroutine results in undefined behavior if the return type is not \cv{}~\keyword{void}. @@ -1361,10 +1326,9 @@ \end{codeblock} \end{example} -\rSec3[ub.stmt.return.coroutine]{The \keyword{co_return} statement} +\ubxref{stmt.return.coroutine.flow.off} \pnum -\ubxref{stmt.return.coroutine.flow.off} Flowing off the end of a coroutine function body that does not return void has undefined behavior. @@ -1425,10 +1389,9 @@ \end{codeblock} \end{example} -\rSec2[ub.stmt.dcl]{Declaration statement} +\ubxref{stmt.dcl.local.static.init.recursive} \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. @@ -1442,18 +1405,11 @@ \end{codeblock} \end{example} - - \rSec1[ub.dcl]{\ref{dcl}: Declarations} -\rSec2[ub.dcl.spec]{Specifiers} - -\rSec3[ub.dcl.type]{Type specifiers} - -\rSec4[ub.dcl.type.cv]{The \fakegrammarterm{cv-qualifier}{s}} +\ubxref{dcl.type.cv.modify.const.obj} \pnum -\ubxref{dcl.type.cv.modify.const.obj} Any attempt to modify a const object during its lifetime results in undefined behavior. @@ -1466,8 +1422,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{dcl.type.cv.access.volatile} + +\pnum 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 @@ -1481,14 +1438,9 @@ \end{codeblock} \end{example} -\rSec2[ub.dcl.decl]{Declarators} - -\rSec3[ub.dcl.meaning]{Meaning of declarators} - -\rSec4[ub.dcl.ref]{References} +\ubxref{dcl.ref.incompatible.function} \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} @@ -1503,8 +1455,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{dcl.ref.incompatible.type} + +\pnum Initializing a reference to an object with a value that is not type-accessible\iref{basic.lval} through @@ -1519,8 +1472,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{dcl.ref.uninitialized.reference} + +\pnum Evaluating a reference prior to initializing that reference has undefined behavior. @@ -1535,14 +1489,9 @@ \end{codeblock} \end{example} - - -\rSec2[ub.dcl.fct.def]{Function definitions} - -\rSec3[ub.dcl.fct.def.coroutine]{Coroutine definitions} +\ubxref{dcl.fct.def.coroutine.resume.not.suspended} \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 @@ -1597,8 +1546,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{dcl.fct.def.coroutine.destroy.not.suspended} + +\pnum Invoking destroy() on a coroutine that is not suspended is undefined behavior. \pnum @@ -1653,12 +1603,9 @@ \end{codeblock} \end{example} -\rSec2[ub.dcl.attr]{Attributes} - -\rSec3[ub.dcl.attr.assume]{Assumption attribute} +\ubxref{dcl.attr.assume.false} \pnum -\ubxref{dcl.attr.assume.false} If an assumption expression would not evaluate to true at the point where it appears the behavior is undefined. @@ -1676,10 +1623,9 @@ \end{codeblock} \end{example} -\rSec3[ub.dcl.attr.noreturn]{Noreturn attribute} +\ubxref{dcl.attr.noreturn.eventually.returns} \pnum -\ubxref{dcl.attr.noreturn.eventually.returns} If a function f is called where f was previously declared with the \tcode{noreturn} attribute and f eventually returns, the behavior is undefined. @@ -1699,12 +1645,9 @@ \rSec1[ub.class]{\ref{class}: Classes} -\rSec2[ub.class.mem]{Class members} - -\rSec3[ub.class.dtor]{Destructors} +\ubxref{class.dtor.no.longer.exists} \pnum -\ubxref{class.dtor.no.longer.exists} Once a destructor is invoked for an object, the object's lifetime has ended; the behavior is undefined if the @@ -1724,12 +1667,9 @@ \end{codeblock} \end{example} -\rSec2[ub.class.derived]{Derived classes} - -\rSec3[ub.class.abstract]{Abstract classes} +\ubxref{class.abstract.pure.virtual} \pnum -\ubxref{class.abstract.pure.virtual} Calling a pure virtual function from a constructor or destructor in an abstract class is undefined behavior. \pnum @@ -1748,12 +1688,9 @@ \end{codeblock} \end{example} -\rSec2[ub.class.init]{Initialization} - -\rSec3[ub.class.base.init]{Initializing bases and members} +\ubxref{class.base.init.mem.fun} \pnum -\ubxref{class.base.init.mem.fun} It is undefined behavior to call a member function before all the \grammarterm{mem-initializer}s for base classes have completed. \pnum @@ -1790,10 +1727,9 @@ \end{codeblock} \end{example} -\rSec3[ub.class.cdtor]{Construction and destruction} +\ubxref{class.cdtor.before.ctor} \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. @@ -1841,8 +1777,9 @@ %WORDINGTODO: CM: Can this example be shortened? -\pnum \ubxref{class.cdtor.after.dtor} + +\pnum 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 @@ -1869,8 +1806,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{class.cdtor.convert.pointer} + +\pnum 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. @@ -1896,8 +1834,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{class.cdtor.form.pointer} + +\pnum When forming a pointer to a direct non-static member of a class, construction must have started @@ -1918,8 +1857,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{class.cdtor.virtual.not.x} + +\pnum 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 @@ -1960,8 +1900,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{class.cdtor.typeid} + +\pnum 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. @@ -1990,8 +1931,9 @@ \end{codeblock} \end{example} -\pnum \ubxref{class.cdtor.dynamic.cast} + +\pnum 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} @@ -2022,12 +1964,9 @@ \rSec1[ub.temp]{\ref{temp}: Templates} -\rSec2[ub.temp.spec]{Template instantiation and specialization} - -\rSec3[ub.temp.inst]{Implicit instantiation} +\ubxref{temp.inst.inf.recursion} \pnum -\ubxref{temp.inst.inf.recursion} The result of an infinite recursion in template instantiation is undefined. \pnum @@ -2049,10 +1988,9 @@ \rSec1[ub.except]{\ref{except}: Exception handling} -\rSec2[ub.except.handle]{Handling an exception} +\ubxref{except.handle.handler.ctor.dtor} \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. From 32bb42c2367aa0ab06892ac1e9375f05c7e2a77f Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 28 May 2026 19:18:03 -0400 Subject: [PATCH 24/27] [ub] and [ifndr]: changed ubxref and ifndrxref commands to be more meaningful ubdescription and ifndrdescription --- source/ifndr.tex | 84 ++++++++++++------------ source/macros.tex | 2 +- source/ub.tex | 164 +++++++++++++++++++++++----------------------- 3 files changed, 125 insertions(+), 125 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index 4260712670..bd1648bd67 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -11,7 +11,7 @@ \rSec1[ifndr.lex]{\ref{lex}: Lexical conventions} -\ifndrxref{lex.name.reserved} +\ifndrdescription{lex.name.reserved} \pnum Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no @@ -32,7 +32,7 @@ \rSec1[ifndr.basic]{\ref{basic}: Basics} -\ifndrxref{basic.link.consistent.types} +\ifndrdescription{basic.link.consistent.types} \pnum Multiple declarations of an entity must be consistent, @@ -58,7 +58,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{basic.def.odr.exact.one.def} +\ifndrdescription{basic.def.odr.exact.one.def} \pnum Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in @@ -78,7 +78,7 @@ \end{codeblock} \end{example} -\ifndrxref{basic.def.odr.unnamed.enum.same.type} +\ifndrdescription{basic.def.odr.unnamed.enum.same.type} \pnum If, at any point in the program, there is more than one reachable unnamed enumeration definition in the same scope that have @@ -102,7 +102,7 @@ \end{codeblock} \end{example} -\ifndrxref{basic.contract.vastart.contract.predicate} +\ifndrdescription{basic.contract.vastart.contract.predicate} \pnum The use of \tcode{va_start}\iref{cstdarg.syn} @@ -120,7 +120,7 @@ \end{codeblock} \end{example} -\ifndrxref{basic.contract.handler.replacing.nonreplaceable} +\ifndrdescription{basic.contract.handler.replacing.nonreplaceable} \pnum On platforms where @@ -138,7 +138,7 @@ \end{codeblock} \end{example} -\ifndrxref{class.member.lookup.name.refers.diff.decl} +\ifndrdescription{class.member.lookup.name.refers.diff.decl} \pnum 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. @@ -183,7 +183,7 @@ \rSec1[ifndr.expr]{\ref{expr}: Expressions} -\ifndrxref{expr.prim.req.always.sub.fail} +\ifndrdescription{expr.prim.req.always.sub.fail} \pnum If the substitution of template arguments into a \grammarterm{requirement} @@ -201,7 +201,7 @@ \rSec1[ifndr.stmt]{\ref{stmt}: Statements} -\ifndrxref{stmt.ambig.bound.diff.parse} +\ifndrdescription{stmt.ambig.bound.diff.parse} \pnum If, during @@ -229,7 +229,7 @@ \rSec1[ifndr.dcl]{\ref{dcl}: Declarations} -\ifndrxref{dcl.constinit.specifier.not.reachable} +\ifndrdescription{dcl.constinit.specifier.not.reachable} \pnum If the initializing declaration @@ -248,7 +248,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{dcl.inline.missing.on.definition} +\ifndrdescription{dcl.inline.missing.on.definition} \pnum If a function or variable @@ -269,7 +269,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{dcl.fct.default.inline.same.defaults} +\ifndrdescription{dcl.fct.default.inline.same.defaults} \pnum If the accumulated set of default arguments @@ -292,7 +292,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{dcl.contract.func.mismatched.contract.specifiers} +\ifndrdescription{dcl.contract.func.mismatched.contract.specifiers} \pnum If two different first declarations of a function @@ -314,7 +314,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{dcl.fct.def.replace.bad.replacement} +\ifndrdescription{dcl.fct.def.replace.bad.replacement} \pnum A declaration of a replaceable function @@ -339,7 +339,7 @@ \end{codeblock} \end{example} -\ifndrxref{dcl.link.mismatched.language.linkage} +\ifndrdescription{dcl.link.mismatched.language.linkage} \pnum If two declarations of an entity @@ -353,7 +353,7 @@ \end{codeblock} \end{example} -\ifndrxref{dcl.align.diff.translation.units} +\ifndrdescription{dcl.align.diff.translation.units} \pnum No diagnostic is required if declarations of an entity have different \grammarterm{alignment-specifier}s in different @@ -370,7 +370,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{dcl.attr.indet.mismatched.declarations} +\ifndrdescription{dcl.attr.indet.mismatched.declarations} \pnum If two first declarations of a function @@ -388,7 +388,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} +\ifndrdescription{dcl.attr.noreturn.trans.unit.mismatch} \pnum No diagnostic is requried if a function is declared @@ -408,7 +408,7 @@ \rSec1[ifndr.module]{\ref{module}: Modules} -\ifndrxref{module.unit.reserved.identifiers} +\ifndrdescription{module.unit.reserved.identifiers} \pnum All \grammarterm{module-name}s either beginning with an identifier consisting of @@ -426,7 +426,7 @@ \end{codeblock} \end{example} -\ifndrxref{module.unit.named.module.no.partition} +\ifndrdescription{module.unit.named.module.no.partition} \pnum A named module shall contain exactly one module interface @@ -441,7 +441,7 @@ \end{codeblock} \end{example} -\ifndrxref{module.unit.unexported.module.partition} +\ifndrdescription{module.unit.unexported.module.partition} \pnum If a module partition of a module @@ -468,7 +468,7 @@ \end{codeblocktu} \end{example} -\ifndrxref{module.private.frag.other.module.units} +\ifndrdescription{module.private.frag.other.module.units} \pnum If a module has a private module fragment @@ -488,7 +488,7 @@ \rSec1[ifndr.class]{\ref{class}: Classes} -\ifndrxref{class.base.init.delegate.itself} +\ifndrdescription{class.base.init.delegate.itself} \pnum If a constructor delegates to itself directly or indirectly, @@ -506,7 +506,7 @@ \end{codeblock} \end{example} -\ifndrxref{class.virtual.pure.or.defined} +\ifndrdescription{class.virtual.pure.or.defined} \pnum A virtual function must be declared pure or defined, no diagnostic required. A virtual function declared pure can be defined @@ -527,7 +527,7 @@ \rSec1[ifndr.over]{\ref{over}: Overloading} -\ifndrxref{over.literal.reserved} +\ifndrdescription{over.literal.reserved} \pnum Some literal suffix identifiers are @@ -544,7 +544,7 @@ \rSec1[ifndr.temp]{\ref{temp}: Templates} -\ifndrxref{temp.pre.reach.def} +\ifndrdescription{temp.pre.reach.def} \pnum A definition of a function template, member function of a class template, variable template, or static data @@ -568,7 +568,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.arg.template.sat.constraints} +\ifndrdescription{temp.arg.template.sat.constraints} \pnum Any partial specializations\iref{temp.spec.partial} associated with the primary template are considered when a specialization @@ -598,7 +598,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.constr.atomic.equiv.but.not.equiv} +\ifndrdescription{temp.constr.atomic.equiv.but.not.equiv} \pnum If the validity or meaning of the program depends on whether two atomic @@ -619,7 +619,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.constr.atomic.sat.result.diff} +\ifndrdescription{temp.constr.atomic.sat.result.diff} \pnum 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. @@ -638,7 +638,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.constr.normal.invalid} +\ifndrdescription{temp.constr.normal.invalid} \pnum If during constraint normalization any such substitution results in an invalid type or expression, @@ -654,7 +654,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.spec.partial.general.partial.reachable} +\ifndrdescription{temp.spec.partial.general.partial.reachable} \pnum A partial specialization shall be reachable from any use of a template specialization that would make use of the @@ -678,7 +678,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.over.link.equiv.not.equiv} +\ifndrdescription{temp.over.link.equiv.not.equiv} \pnum If the validity or meaning of the program depends on whether two constructs are equivalent, and they are @@ -696,7 +696,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.res.general.default.but.not.found} +\ifndrdescription{temp.res.general.default.but.not.found} \pnum If the validity or meaning of the program would be changed by considering a default argument or default @@ -712,7 +712,7 @@ %WORDINGTODO: SY, JMB: We need to produce an example for this case. -\ifndrxref{temp.point.diff.pt.diff.meaning} +\ifndrdescription{temp.point.diff.pt.diff.meaning} \pnum A specialization for a class template has at most one point of instantiation within a translation unit. A @@ -744,7 +744,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.dep.candidate.different.lookup.different} +\ifndrdescription{temp.dep.candidate.different.lookup.different} \pnum If considering all function declarations @@ -762,7 +762,7 @@ %WORDINGTODO: JMB: produce an example -\ifndrxref{temp.explicit.decl.implicit.inst} +\ifndrdescription{temp.explicit.decl.implicit.inst} \pnum An entity that is the subject of @@ -783,7 +783,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.expl.spec.unreachable.declaration} +\ifndrdescription{temp.expl.spec.unreachable.declaration} \pnum If an implicit instantiation of a template would occur @@ -799,7 +799,7 @@ %WORDINGTODO: JMB: produce an example -\ifndrxref{temp.expl.spec.missing.definition} +\ifndrdescription{temp.expl.spec.missing.definition} \pnum If an explicit specialization of a template is @@ -816,7 +816,7 @@ \end{codeblock} \end{example} -\ifndrxref{temp.deduct.general.diff.order} +\ifndrdescription{temp.deduct.general.diff.order} \pnum If substitution @@ -847,7 +847,7 @@ \rSec1[ifndr.cpp]{\ref{cpp}: Preprocessing directives} -\ifndrxref{cpp.cond.defined.after.macro} +\ifndrdescription{cpp.cond.defined.after.macro} \pnum If the expansion of a macro produces the preprocessing token \tcode{defined} @@ -863,7 +863,7 @@ \end{codeblock} \end{example} -\ifndrxref{cpp.cond.defined.malformed} +\ifndrdescription{cpp.cond.defined.malformed} \pnum If the \tcode{defined} unary operator is used when it @@ -882,7 +882,7 @@ \end{codeblock} \end{example} -\ifndrxref{cpp.include.malformed.headername} +\ifndrdescription{cpp.include.malformed.headername} \pnum If the \grammarterm{header-name-tokens} after diff --git a/source/macros.tex b/source/macros.tex index c38df98737..3b69c5bf6d 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -810,7 +810,7 @@ \newcommand{\ubdef}[1]{\nolinebreak[3] (\label{ub:#1}\ref{ubx:#1})} % Use in Annex for sections describing each individual IFNDR -\newcommand{\ubxref}[1]{% +\newcommand{\ubdescription}[1]{% \let\oldcontentsline\addcontentsline% \let\addcontentsline\nocontentsline% \ifcase\value{SectionDepth} diff --git a/source/ub.tex b/source/ub.tex index ec7db7dc2f..105d008138 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -13,7 +13,7 @@ \rSec1[ub.basic]{\ref{basic}: Basics} -\ubxref{intro.object.implicit.create} +\ubdescription{intro.object.implicit.create} \pnum For each @@ -35,7 +35,7 @@ \end{codeblock} \end{example} -\ubxref{intro.object.implicit.pointer} +\ubdescription{intro.object.implicit.pointer} \pnum After implicitly creating objects within a specified region of storage, @@ -94,7 +94,7 @@ %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 ..." -\ubxref{basic.align.object.alignment} +\ubdescription{basic.align.object.alignment} \pnum All instances of a type must be created in storage that meets the alignment @@ -115,7 +115,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.pointer.delete} +\ubdescription{lifetime.outside.pointer.delete} \pnum For a pointer pointing to an object outside of its lifetime, behavior is @@ -139,7 +139,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.pointer.member} +\ubdescription{lifetime.outside.pointer.member} \pnum For a pointer pointing to an object outside of its lifetime, behavior is @@ -163,7 +163,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.pointer.virtual} +\ubdescription{lifetime.outside.pointer.virtual} \pnum For a pointer pointing to an object outside of its lifetime, behavior is @@ -184,7 +184,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.pointer.dynamic.cast} +\ubdescription{lifetime.outside.pointer.dynamic.cast} \pnum For a pointer pointing to an object outside of its lifetime, behavior is @@ -206,7 +206,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.glvalue.access} +\ubdescription{lifetime.outside.glvalue.access} \pnum Behavior is undefined if a glvalue referring to an object outside of its @@ -225,7 +225,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.glvalue.member} +\ubdescription{lifetime.outside.glvalue.member} \pnum Behavior is undefined if a glvalue referring to an object outside of its @@ -247,7 +247,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.glvalue.virtual} +\ubdescription{lifetime.outside.glvalue.virtual} \pnum Behavior is undefined if a glvalue referring to an object outside of its @@ -268,7 +268,7 @@ \end{codeblock} \end{example} -\ubxref{lifetime.outside.glvalue.dynamic.cast} +\ubdescription{lifetime.outside.glvalue.dynamic.cast} \pnum Behavior is undefined if a glvalue referring to an object outside of its @@ -290,7 +290,7 @@ \end{codeblock} \end{example} -\ubxref{original.type.implicit.destructor} +\ubdescription{original.type.implicit.destructor} \pnum The behavior is undefined if @@ -314,7 +314,7 @@ \end{codeblock} \end{example} -\ubxref{creating.within.const.complete.obj} +\ubdescription{creating.within.const.complete.obj} \pnum Creating a new object within the storage that a const complete object with static, thread, or automatic @@ -338,7 +338,7 @@ \end{codeblock} \end{example} -\ubxref{basic.indet.value} +\ubdescription{basic.indet.value} \pnum When the result of an evaluation is @@ -356,7 +356,7 @@ \end{codeblock} \end{example} -\ubxref{basic.stc.alloc.dealloc.constraint} +\ubdescription{basic.stc.alloc.dealloc.constraint} \pnum If the behavior of an allocation or deallocation function does not satisfy the semantic constraints @@ -381,7 +381,7 @@ \end{codeblock} \end{example} -\ubxref{basic.stc.alloc.dealloc.throw} +\ubdescription{basic.stc.alloc.dealloc.throw} \pnum If a call to a deallocation function @@ -401,7 +401,7 @@ \end{codeblock} \end{example} -\ubxref{basic.stc.alloc.zero.dereference} +\ubdescription{basic.stc.alloc.zero.dereference} \pnum The pointer returned when invoking an allocation function with a size of zero @@ -418,7 +418,7 @@ \end{codeblock} \end{example} -\ubxref{basic.compound.invalid.pointer} +\ubdescription{basic.compound.invalid.pointer} \pnum Indirection or @@ -442,7 +442,7 @@ \end{codeblock} \end{example} -\ubxref{intro.execution.unsequenced.modification} +\ubdescription{intro.execution.unsequenced.modification} \pnum If a side effect on a @@ -463,7 +463,7 @@ \end{codeblock} \end{example} -\ubxref{intro.races.data} +\ubdescription{intro.races.data} \pnum The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, @@ -480,7 +480,7 @@ \end{codeblock} \end{example} -\ubxref{intro.progress.stops} +\ubdescription{intro.progress.stops} \pnum The behavior is undefined if a thread of execution that has not terminated stops @@ -502,7 +502,7 @@ \end{codeblock} \end{example} -\ubxref{basic.start.main.exit.during.destruction} +\ubdescription{basic.start.main.exit.during.destruction} \pnum If \tcode{std::exit} is called to @@ -525,7 +525,7 @@ \end{codeblock} \end{example} -\ubxref{basic.start.term.use.after.destruction} +\ubdescription{basic.start.term.use.after.destruction} \pnum If a function contains a block-scope object of static or thread storage duration that has been destroyed and the @@ -559,7 +559,7 @@ \end{codeblock} \end{example} -\ubxref{basic.start.term.signal.handler} +\ubdescription{basic.start.term.signal.handler} \pnum If there is a use of a standard library object or function not permitted within signal handlers\iref{support.runtime} that @@ -574,7 +574,7 @@ \rSec1[ub.expr]{\ref{expr}: Expressions} -\ubxref{expr.expr.eval} +\ubdescription{expr.expr.eval} \pnum If during the evaluation of an expression, the result is not mathematically defined or not in the range of @@ -594,7 +594,7 @@ \end{codeblock} \end{example} -\ubxref{expr.basic.lvalue.strict.aliasing.violation} +\ubdescription{expr.basic.lvalue.strict.aliasing.violation} \pnum If a program attempts to access\iref{defns.access} the stored value of an object @@ -620,7 +620,7 @@ \end{codeblock} \end{example} -\ubxref{expr.basic.lvalue.union.initialization} +\ubdescription{expr.basic.lvalue.union.initialization} \pnum If a program invokes a defaulted copy/move constructor or @@ -640,7 +640,7 @@ \end{codeblock} \end{example} -\ubxref{expr.type.reference.lifetime} +\ubdescription{expr.type.reference.lifetime} \pnum Evaluating a reference when an equivalent use of a pointer denoting the same object @@ -659,7 +659,7 @@ \end{codeblock} \end{example} -\ubxref{conv.lval.valid.representation} +\ubdescription{conv.lval.valid.representation} \pnum Performing an @@ -681,7 +681,7 @@ \end{codeblock} \end{example} -\ubxref{conv.double.out.of.range} +\ubdescription{conv.double.out.of.range} \pnum Converting a floating point value to a type that cannot represent the value is undefined behavior. @@ -702,7 +702,7 @@ \end{codeblock} \end{example} -\ubxref{conv.fpint.int.not.represented} +\ubdescription{conv.fpint.int.not.represented} \pnum When converting a floating-point value to an integer type and vice versa if @@ -722,7 +722,7 @@ \end{codeblock} \end{example} -\ubxref{conv.fpint.float.not.represented} +\ubdescription{conv.fpint.float.not.represented} \pnum When converting a value of integer or unscoped enumeration type to a @@ -741,7 +741,7 @@ \end{codeblock} \end{example} -\ubxref{conv.ptr.virtual.base} +\ubdescription{conv.ptr.virtual.base} \pnum Converting @@ -766,7 +766,7 @@ \end{codeblock} \end{example} -\ubxref{conv.member.missing.member} +\ubdescription{conv.member.missing.member} \pnum The conversion of @@ -790,7 +790,7 @@ \end{codeblock} \end{example} -\ubxref{expr.call.different.type} +\ubdescription{expr.call.different.type} \pnum Calling a function through an expression whose @@ -815,7 +815,7 @@ \end{codeblock} \end{example} -\ubxref{expr.ref.member.not.similar} +\ubdescription{expr.ref.member.not.similar} \pnum If \tcode{E2} is a non-static member and the result of \tcode{E1} is an object whose type @@ -837,7 +837,7 @@ %WORDINGTODO: SY: The wording is not great, I don't have a good suggestion but we should %get some opinions -\ubxref{expr.dynamic.cast.pointer.lifetime} +\ubdescription{expr.dynamic.cast.pointer.lifetime} \pnum Evaluating a \keyword{dynamic_cast} on a non-null pointer that points to @@ -855,7 +855,7 @@ \end{codeblock} \end{example} -\ubxref{expr.dynamic.cast.glvalue.lifetime} +\ubdescription{expr.dynamic.cast.glvalue.lifetime} \pnum Evaluating a \keyword{dynamic_cast} on a reference that @@ -873,7 +873,7 @@ \end{codeblock} \end{example} -\ubxref{expr.static.cast.base.class} +\ubdescription{expr.static.cast.base.class} \pnum We can cast a base class B to a reference to derived class D (with certain restrictions wrt to cv qualifiers) @@ -894,7 +894,7 @@ \end{codeblock} \end{example} -\ubxref{expr.static.cast.enum.outside.range} +\ubdescription{expr.static.cast.enum.outside.range} \pnum If the enumeration type does not have a fixed underlying @@ -912,7 +912,7 @@ \end{codeblock} \end{example} -\ubxref{expr.static.cast.fp.outside.range} +\ubdescription{expr.static.cast.fp.outside.range} \pnum An explicit conversion of a @@ -934,7 +934,7 @@ \end{codeblock} \end{example} -\ubxref{expr.static.cast.downcast.wrong.derived.type} +\ubdescription{expr.static.cast.downcast.wrong.derived.type} \pnum Casting from a pointer to a base class to a pointer to a derived class @@ -955,7 +955,7 @@ \end{codeblock} \end{example} -\ubxref{expr.static.cast.does.not.contain.orignal.member} +\ubdescription{expr.static.cast.does.not.contain.orignal.member} \pnum A @@ -988,7 +988,7 @@ \end{codeblock} \end{example} -\ubxref{expr.unary.dereference} +\ubdescription{expr.unary.dereference} \pnum Dereferencing a pointer that does not point to an object or function @@ -1005,7 +1005,7 @@ \end{codeblock} \end{example} -\ubxref{expr.new.non.allocating.null} +\ubdescription{expr.new.non.allocating.null} \pnum If the allocation @@ -1035,7 +1035,7 @@ \end{codeblock} \end{example} -\ubxref{expr.delete.mismatch} +\ubdescription{expr.delete.mismatch} \pnum Using array delete on the result of a single object new expression is undefined behavior. @@ -1048,7 +1048,7 @@ \end{codeblock} \end{example} -\ubxref{expr.delete.array.mismatch} +\ubdescription{expr.delete.array.mismatch} \pnum Using single object delete on the result of an array new expression is undefined behavior. @@ -1061,7 +1061,7 @@ \end{codeblock} \end{example} -\ubxref{expr.delete.dynamic.type.differ} +\ubdescription{expr.delete.dynamic.type.differ} \pnum If the static type of the object to be deleted is different from its dynamic @@ -1087,7 +1087,7 @@ \end{codeblock} \end{example} -\ubxref{expr.delete.dynamic.array.dynamic.type.differ} +\ubdescription{expr.delete.dynamic.array.dynamic.type.differ} \pnum In an array delete expression, if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined. @@ -1113,7 +1113,7 @@ \end{codeblock} \end{example} -\ubxref{expr.mptr.oper.not.contain.member} +\ubdescription{expr.mptr.oper.not.contain.member} \pnum Abbreviating \grammarterm{pm-expression}.*\grammarterm{cast-expression} as \tcode{E1.*E2}, \tcode{E1} is called the object expression. If the dynamic type @@ -1136,7 +1136,7 @@ \end{codeblock} \end{example} -\ubxref{expr.mptr.oper.member.func.null} +\ubdescription{expr.mptr.oper.member.func.null} \pnum If the second operand in a \tcode{.*} expression is the null @@ -1157,7 +1157,7 @@ \end{codeblock} \end{example} -\ubxref{expr.mul.div.by.zero} +\ubdescription{expr.mul.div.by.zero} \pnum Division by zero is undefined behavior. @@ -1174,7 +1174,7 @@ \end{codeblock} \end{example} -\ubxref{expr.mul.representable.type.result} +\ubdescription{expr.mul.representable.type.result} \pnum If the @@ -1194,7 +1194,7 @@ \end{codeblock} \end{example} -\ubxref{expr.add.out.of.bounds} +\ubdescription{expr.add.out.of.bounds} \pnum Creating an out of bounds pointer is undefined behavior. @@ -1221,7 +1221,7 @@ \end{codeblock} \end{example} -\ubxref{expr.add.sub.diff.pointers} +\ubdescription{expr.add.sub.diff.pointers} \pnum Subtracting pointers that are not part of the same array is undefined behavior. @@ -1240,7 +1240,7 @@ \end{codeblock} \end{example} -\ubxref{expr.add.not.similar} +\ubdescription{expr.add.not.similar} \pnum For addition or subtraction of two expressions P and Q, @@ -1271,7 +1271,7 @@ \end{codeblock} \end{example} -\ubxref{expr.shift.neg.and.width} +\ubdescription{expr.shift.neg.and.width} \pnum Shifting by a negative amount or equal or greater than the bit-width of a type is undefined behavior. @@ -1287,7 +1287,7 @@ \end{codeblock} \end{example} -\ubxref{expr.assign.overlap} +\ubdescription{expr.assign.overlap} \pnum Overlap in the storage between the source and destination may result in undefined behavior. @@ -1303,7 +1303,7 @@ \rSec1[ub.stmt]{\ref{stmt}: Statements} -\ubxref{stmt.return.flow.off} +\ubdescription{stmt.return.flow.off} \pnum Flowing off the end of a function other @@ -1326,7 +1326,7 @@ \end{codeblock} \end{example} -\ubxref{stmt.return.coroutine.flow.off} +\ubdescription{stmt.return.coroutine.flow.off} \pnum Flowing off the end of a coroutine function body @@ -1389,7 +1389,7 @@ \end{codeblock} \end{example} -\ubxref{stmt.dcl.local.static.init.recursive} +\ubdescription{stmt.dcl.local.static.init.recursive} \pnum If control re-enters the declaration recursively while the @@ -1407,7 +1407,7 @@ \rSec1[ub.dcl]{\ref{dcl}: Declarations} -\ubxref{dcl.type.cv.modify.const.obj} +\ubdescription{dcl.type.cv.modify.const.obj} \pnum Any attempt to modify a const object during its lifetime results in @@ -1422,7 +1422,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.type.cv.access.volatile} +\ubdescription{dcl.type.cv.access.volatile} \pnum If an attempt is made to @@ -1438,7 +1438,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.ref.incompatible.function} +\ubdescription{dcl.ref.incompatible.function} \pnum Initializing a reference to a function @@ -1455,7 +1455,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.ref.incompatible.type} +\ubdescription{dcl.ref.incompatible.type} \pnum Initializing a reference to an object @@ -1472,7 +1472,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.ref.uninitialized.reference} +\ubdescription{dcl.ref.uninitialized.reference} \pnum Evaluating a reference @@ -1489,7 +1489,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.fct.def.coroutine.resume.not.suspended} +\ubdescription{dcl.fct.def.coroutine.resume.not.suspended} \pnum Invoking a resumption member function for a coroutine that is not suspended results in undefined behavior. @@ -1546,7 +1546,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.fct.def.coroutine.destroy.not.suspended} +\ubdescription{dcl.fct.def.coroutine.destroy.not.suspended} \pnum Invoking destroy() on a coroutine that is not suspended is undefined behavior. @@ -1603,7 +1603,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.attr.assume.false} +\ubdescription{dcl.attr.assume.false} \pnum If an assumption expression would not evaluate to true at the point where it @@ -1623,7 +1623,7 @@ \end{codeblock} \end{example} -\ubxref{dcl.attr.noreturn.eventually.returns} +\ubdescription{dcl.attr.noreturn.eventually.returns} \pnum If a function f is called where f was previously declared with the \tcode{noreturn} attribute and f eventually returns, @@ -1645,7 +1645,7 @@ \rSec1[ub.class]{\ref{class}: Classes} -\ubxref{class.dtor.no.longer.exists} +\ubdescription{class.dtor.no.longer.exists} \pnum Once a destructor is invoked for an object, @@ -1667,7 +1667,7 @@ \end{codeblock} \end{example} -\ubxref{class.abstract.pure.virtual} +\ubdescription{class.abstract.pure.virtual} \pnum Calling a pure virtual function from a constructor or destructor in an abstract class is undefined behavior. @@ -1688,7 +1688,7 @@ \end{codeblock} \end{example} -\ubxref{class.base.init.mem.fun} +\ubdescription{class.base.init.mem.fun} \pnum It is undefined behavior to call a member function before all the \grammarterm{mem-initializer}s for base classes have completed. @@ -1727,7 +1727,7 @@ \end{codeblock} \end{example} -\ubxref{class.cdtor.before.ctor} +\ubdescription{class.cdtor.before.ctor} \pnum For an object with a non-trivial constructor, referring to any non-static member or base class of the object @@ -1777,7 +1777,7 @@ %WORDINGTODO: CM: Can this example be shortened? -\ubxref{class.cdtor.after.dtor} +\ubdescription{class.cdtor.after.dtor} \pnum For an object with a non-trivial destructor, @@ -1806,7 +1806,7 @@ \end{codeblock} \end{example} -\ubxref{class.cdtor.convert.pointer} +\ubdescription{class.cdtor.convert.pointer} \pnum When converting a pointer to a base class of an object, @@ -1834,7 +1834,7 @@ \end{codeblock} \end{example} -\ubxref{class.cdtor.form.pointer} +\ubdescription{class.cdtor.form.pointer} \pnum When forming a pointer to @@ -1857,7 +1857,7 @@ \end{codeblock} \end{example} -\ubxref{class.cdtor.virtual.not.x} +\ubdescription{class.cdtor.virtual.not.x} \pnum When a virtual function is called directly or indirectly from a constructor or from a destructor, @@ -1900,7 +1900,7 @@ \end{codeblock} \end{example} -\ubxref{class.cdtor.typeid} +\ubdescription{class.cdtor.typeid} \pnum If the operand of \tcode{typeid} refers to @@ -1931,7 +1931,7 @@ \end{codeblock} \end{example} -\ubxref{class.cdtor.dynamic.cast} +\ubdescription{class.cdtor.dynamic.cast} \pnum If the operand of the @@ -1964,7 +1964,7 @@ \rSec1[ub.temp]{\ref{temp}: Templates} -\ubxref{temp.inst.inf.recursion} +\ubdescription{temp.inst.inf.recursion} \pnum The result of an infinite recursion in template instantiation is undefined. @@ -1988,7 +1988,7 @@ \rSec1[ub.except]{\ref{except}: Exception handling} -\ubxref{except.handle.handler.ctor.dtor} +\ubdescription{except.handle.handler.ctor.dtor} \pnum Referring to any non-static member or base class of an object in the handler for a \grammarterm{function-try-block} of a From c3fc4f9a9cf27b226f14c76d396af3bdfa1aef13 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Thu, 28 May 2026 22:26:46 -0400 Subject: [PATCH 25/27] [ub] and [ifndr] - typo fixes --- source/expressions.tex | 2 +- source/ifndr.tex | 27 ++++++++++++++------------- source/ub.tex | 16 ++++++++-------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 0da914b30f..29b347b9cf 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -4894,7 +4894,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\ubdef{expr.static.cast.does.not.contain.orignal.member}. +to the original member. Otherwise, the behavior is undefined\ubdef{expr.static.cast.does.not.contain.original.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 diff --git a/source/ifndr.tex b/source/ifndr.tex index bd1648bd67..23f5a6b06f 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -97,7 +97,7 @@ // main.cpp import "a.h"; import "b.h"; -auto n = decltype(a)::b; // ill-formed no diagnostic required, more than one unnammed enum +auto n = decltype(a)::b; // ill-formed no diagnostic required, more than one unnamed enum // definition reachable at this point but their types are not the same \end{codeblock} \end{example} @@ -233,15 +233,16 @@ \pnum If the initializing declaration -of a variable that has the \tcode{constinit} specifier -applied to declarations not reachable from -that initializing declaration +of a variable without the \tcode{constinit} specifier +has the \tcode{constinit} specifier +applied to declarations that are not reachable from +that initializing declaration, the program is ill-formed, no diagnostic required. \pnum \begin{example} \begin{codeblocktu}{Translation unit \#1} -int x = 5; // initializing declaration of \tcode{z} +int x = 5; // initializing declaration of \tcode{x} \end{codeblocktu} \begin{codeblocktu}{Translation unit \#2} extern constinit int x; // IFNDR, not reachable from initializing declaration of \tcode{x} @@ -334,7 +335,7 @@ 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 +void* operator new(decltype(sizeof(0))) noexcept; // IFNDR, mismatched exception specification to declaration // in \tcode{} \end{codeblock} \end{example} @@ -381,7 +382,7 @@ \pnum \begin{example} \begin{codeblocktu}{Translation unit \#1} -int h(int x [[indeterminate]]; // IFNDR, mismatched \tcode{[[indeterminate]]} 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]]} to other first declaration of \tcode{h} @@ -391,7 +392,7 @@ \ifndrdescription{dcl.attr.noreturn.trans.unit.mismatch} \pnum -No diagnostic is requried if a function is declared +No diagnostic is required if a function is declared in one translation unit with the \tcode{noreturn} attribute but has declarations in other translation units without the attribute. @@ -464,7 +465,7 @@ 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} +export module M:C; // IFNDR, not directly or indirectly exported by \tcode{M} \end{codeblocktu} \end{example} @@ -520,7 +521,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 no definition } \end{codeblock} \end{example} @@ -562,7 +563,7 @@ // a.cpp #include "a.h" int main() { - f(); // ill-formed no diagnostic required, function template implicity + f(); // ill-formed no diagnostic required, function template implicitly // instantiated but not reachable definition } \end{codeblock} @@ -812,7 +813,7 @@ \begin{codeblock} template int f(T&&) { return 0; } template <> int f(int&&); -int j = f(1); // IFNDR, odr-use of \tcode{f} with no defintion +int j = f(1); // IFNDR, odr-use of \tcode{f} with no definition \end{codeblock} \end{example} @@ -894,6 +895,6 @@ \pnum \begin{example} \begin{codeblock} -#include `` // Ill-formed no diagnoatic required, does not match one of the two allowable forms +#include `` // Ill-formed no diagnostic required, does not match one of the two allowable forms \end{codeblock} \end{example} diff --git a/source/ub.tex b/source/ub.tex index 105d008138..4b42397c9b 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -427,7 +427,7 @@ that has been freed has undefined behavior. (Most other uses of such a pointer have -implemention-defined behavior.) +implementation-defined behavior.) \pnum \begin{example} @@ -736,7 +736,7 @@ __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 are [-inf,+inf] this would not be UB } \end{codeblock} \end{example} @@ -907,7 +907,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 within the range of enumeration values } \end{codeblock} \end{example} @@ -922,7 +922,7 @@ \pnum \begin{example} If \tcode{float} does not adhere to \IsoFloatUndated{} -and cannot represent positive infinty, +and cannot represent positive infinity, a sufficiently large \tcode{double} value will be outside the (finite) range of \tcode{float}. \begin{codeblock} @@ -955,7 +955,7 @@ \end{codeblock} \end{example} -\ubdescription{expr.static.cast.does.not.contain.orignal.member} +\ubdescription{expr.static.cast.does.not.contain.original.member} \pnum A @@ -1030,7 +1030,7 @@ int main() { char *p = nullptr; - A *a = new (p) A; // undefined behavior, non-allocting new returning nullptr + A *a = new (p) A; // undefined behavior, non-allocating new returning nullptr } \end{codeblock} \end{example} @@ -1169,7 +1169,7 @@ 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 + // representable values are [-inf,+inf] this would not be UB } \end{codeblock} \end{example} @@ -1321,7 +1321,7 @@ 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 + // without a return statement } \end{codeblock} \end{example} From 5148a1720b4568b28b8d51dbf9649f6be9a0b585 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 29 May 2026 10:07:36 -0400 Subject: [PATCH 26/27] [ifndr] - significant ifndr description cleanup --- source/basic.tex | 12 ++- source/ifndr.tex | 233 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 189 insertions(+), 56 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 973edfcd2b..59d6235a80 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\ifndrdef{basic.def.odr.exact.one.def}. +outside of a discarded statement\iref{stmt.if}; no diagnostic required\ifndrdef{basic.def.odr.minimum.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}, @@ -762,21 +762,23 @@ that definition shall be an injected declaration having the same characteristic sequence as $X$; a diagnostic is required only if \tcode{D} is attached to a named module and -a prior definition is reachable at the point where a later definition occurs. +a prior definition is reachable +at the point where a later definition occurs\ifndrdef{basic.def.odr.injected.match}. \pnum For any other definable item \tcode{D} with definitions in multiple translation units, \begin{itemize} \item -if \tcode{D} is a non-inline non-templated function or variable, or +if \tcode{D} is a non-inline non-templated function or variable\ifndrdef{basic.def.odr.maximum.one.def}, or \item if the definitions in different translation units -do not satisfy the following requirements, +do not satisfy the following requirements\ifndrdef{basic.def.odr.definition.matches}, \end{itemize} the program is ill-formed; a diagnostic is required only if the definable item is attached to a named module and -a prior definition is reachable at the point where a later definition occurs. +a prior definition is reachable +at the point where a later definition occurs. Given such an item, for all definitions of \tcode{D}, or, if \tcode{D} is an unnamed enumeration, diff --git a/source/ifndr.tex b/source/ifndr.tex index 23f5a6b06f..c6f3ecb25b 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -4,7 +4,10 @@ \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. +the following phrases: +``no diagnostic is required'', +``no diagnostic required'', or +``a diagnostic is required only if''. 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. @@ -14,8 +17,8 @@ \ifndrdescription{lex.name.reserved} \pnum -Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no -diagnostic is required. +Using an identifier reserved for use by \Cpp{} +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -35,9 +38,10 @@ \ifndrdescription{basic.link.consistent.types} \pnum -Multiple declarations of an entity must be consistent, -no diagnostic is required if neither declaration is reachable -from the other. +Having multiple declarations of the same entity +with different kinds +when those declarations are not reachable from one another +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -58,11 +62,13 @@ \end{codeblocktu} \end{example} -\ifndrdescription{basic.def.odr.exact.one.def} +\ifndrdescription{basic.def.odr.minimum.one.def} \pnum -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. +Not having a definition +for a function or variable +that is odr-used from a non-discarded statement\iref{stmt.if} +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -78,12 +84,98 @@ \end{codeblock} \end{example} +\ifndrdescription{basic.def.odr.injected.match} + +\pnum +Defining a definable item \tcode{D} +with an injected declaration\iref{expr.const.reflect} +in one translation unit and +a definition in a different translation unit +when \tcode{D} is not attached to a named module +or neither definition is reachable from the other +is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +struct S; +consteval { std::meta::define_aggregate(^^S, {}); } // \#1 +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +struct S {}; // IFNDR, definition here, injected declaration at \#1 +\end{codeblocktu} +\end{example} + +\ifndrdescription{basic.def.odr.maximum.one.def} + +\pnum +If there are definitions +in different translation units +of a non-inline non-templated function or variable +that are not attached to a named module +or are not reachable from one another, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M:A; // module partition +void f() {} // \#1 +void g() {} // \#2 +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +export module M:B; // module partition +void f() {} // IFNDR, \#1 not reachable +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#3} +export module M; // primary module interface unit +export import :A; +void g(); // error: \#2 is reachable +\end{codeblocktu} +\end{example} + +\ifndrdescription{basic.def.odr.definition.matches} + +\pnum +If there are definitions +in different translation units +of a definable item \tcode{D} +that is +\begin{itemize} +\item not defined by an injected declaration\iref{expr.const.reflect}, +\item not an inline or templated function or variable, and +\item are not attached to a named module or are not reachable from one another, +\end{itemize} +that do not satisfy the matching rules described in \ref{basic.def.odr} +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline void f() {} // \#1 +inline void g() {} // \#2 +inline void h() {[]{}();} // \#3 +namespace { int i = 0; } +inline void j() {++i;} // \#4 +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +inline void f() {} // OK, same as \#1 +inline void g() {;} // IFNDR, different sequence of tokens than \#2 +inline void h() {[]{}();} // IFNDR, closure has different type than \#3 +namespace { int i = 0; } +inline void j() {++i; } // IFNDR, \tcode{i} refers to different entity than in \#4 +\end{codeblocktu} +\end{example} + \ifndrdescription{basic.def.odr.unnamed.enum.same.type} \pnum -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. +Having multiple unnamed enumeration definitions +in the same scope +that have the same first enumerator name +and do not have typedef names for linkage purposes\iref{dcl.enum} +that are not the same enumeration +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -141,7 +233,11 @@ \ifndrdescription{class.member.lookup.name.refers.diff.decl} \pnum -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. +A name $N$ used in a class $S$ +referring to a different declaration +when resolved in its context +than when re-evaluated in the completed scope of $S$ +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -321,7 +417,7 @@ A declaration of a replaceable function that is inline, not attached to the global module, -does not have \Cpp{} language linkage, +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) @@ -412,9 +508,12 @@ \ifndrdescription{module.unit.reserved.identifiers} \pnum -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. +Specifying a \grammarterm{module-name} +beginning with an identifier +consisting of \tcode{std} followed by zero or more digits, +or containing a reserved identifier\iref{lex.token} +in a \grammarterm{module-declaration} +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -430,9 +529,9 @@ \ifndrdescription{module.unit.named.module.no.partition} \pnum -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. +Having multiple primary module interface units +for a named module +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -510,8 +609,9 @@ \ifndrdescription{class.virtual.pure.or.defined} \pnum -A virtual function must be declared pure or defined, no diagnostic required. A virtual function declared pure can be defined -out of line +If a virtual function that is not pure +has no definition, +the program is ill-formed, no diagnostic required. \pnum \begin{example} @@ -548,10 +648,16 @@ \ifndrdescription{temp.pre.reach.def} \pnum -A definition of a function template, member function of a class template, variable template, or static data -member of a class template shall be reachable from the end of every definition domain\iref{basic.def.odr} in which it is -implicitly instantiated\iref{temp.inst} unless the corresponding specialization is explicitly instantiated\iref{temp.explicit} in -some translation unit; no diagnostic is required. +A definition of a function template, +member function of a class template, +variable template, +or static data member of a class template +that is not reachable from +the end of every definition domain\iref{basic.def.odr} +in which it is implicitly instantiated\iref{temp.inst} +and whose corresponding specialization +is not explicitly instantiated\iref{temp.explicit} in some translation unit +is ill-formed, no diagnostic required. \pnum \begin{example} @@ -572,10 +678,13 @@ \ifndrdescription{temp.arg.template.sat.constraints} \pnum -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. +Any partial specializations\iref{temp.spec.partial} +associated with the primary template are considered when a specialization +based on the template template-parameter is instantiated. +If a specialization is not reachable +from the point of instantiation, +and it would have been selected had it been reachable, +the program is ill-formed, no diagnostic required. \pnum \begin{example} @@ -602,9 +711,10 @@ \ifndrdescription{temp.constr.atomic.equiv.but.not.equiv} \pnum -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. +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} @@ -623,7 +733,10 @@ \ifndrdescription{temp.constr.atomic.sat.result.diff} \pnum -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. +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} @@ -642,7 +755,8 @@ \ifndrdescription{temp.constr.normal.invalid} \pnum -If during constraint normalization any such substitution results in an invalid type or expression, +If during constraint normalization +any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required \pnum @@ -658,8 +772,11 @@ \ifndrdescription{temp.spec.partial.general.partial.reachable} \pnum -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. +If a partial specialization +is not reachable from a use of a template specialization +that would make use of that partial specialization +as the result of an implicit or explicit instantiation, +the program is ill-formed, no diagnostic required. \pnum \begin{example} @@ -682,8 +799,10 @@ \ifndrdescription{temp.over.link.equiv.not.equiv} \pnum -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. +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} @@ -700,10 +819,13 @@ \ifndrdescription{temp.res.general.default.but.not.found} \pnum -If the validity or meaning of the program would be changed by considering a default argument or default -template argument introduced in a declaration that is reachable from the point of instantiation of a -specialization\iref{temp.point} but is not found by lookup for the specialization, the program is ill-formed, no -diagnostic required. +If the validity or meaning of the program +would be changed by considering +a default argument or default template argument +introduced in a declaration that is reachable +from the point of instantiation of a specialization\iref{temp.point} +but is not found by lookup for the specialization, +the program is ill-formed, no diagnostic required. \pnum \begin{example} @@ -716,10 +838,14 @@ \ifndrdescription{temp.point.diff.pt.diff.meaning} \pnum -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. +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\iref{basic.def.odr}, +the program is ill-formed, no diagnostic required. \pnum \begin{example} @@ -766,10 +892,15 @@ \ifndrdescription{temp.explicit.decl.implicit.inst} \pnum -An entity that is the subject of -an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit -instantiation\iref{temp.inst} in the translation unit shall be the subject of an explicit instantiation definition -somewhere in the program; otherwise the program is ill-formed, no diagnostic required. +If 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 +is not the subject of +an explicit instantiation definition somewhere in the program +the program is ill-formed, no diagnostic required. \pnum \begin{example} From 5b09847a6de6a8811e8b1e08454e65f0e9b94869 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Fri, 29 May 2026 13:08:15 -0400 Subject: [PATCH 27/27] [ub] and [ifndr]: feedback from christof --- source/ifndr.tex | 14 +++++------ source/ub.tex | 63 ++++++++++++++++++++++++------------------------ 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/source/ifndr.tex b/source/ifndr.tex index c6f3ecb25b..d1b8c44137 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -102,7 +102,7 @@ consteval { std::meta::define_aggregate(^^S, {}); } // \#1 \end{codeblocktu} \begin{codeblocktu}{Translation unit \#2} -struct S {}; // IFNDR, definition here, injected declaration at \#1 +struct S {}; // IFNDR, definition here, injected declaration at \#1 \end{codeblocktu} \end{example} @@ -140,13 +140,13 @@ If there are definitions in different translation units of a definable item \tcode{D} -that is +where \begin{itemize} -\item not defined by an injected declaration\iref{expr.const.reflect}, -\item not an inline or templated function or variable, and -\item are not attached to a named module or are not reachable from one another, +\item $D$ is not defined by an injected declaration\iref{expr.const.reflect}, +\item $D$ is not an inline or templated function or variable, and +\item $D$ is not attached to a named module or the declarations are not reachable from one another, \end{itemize} -that do not satisfy the matching rules described in \ref{basic.def.odr} +that do not satisfy the matching rules described in \ref{basic.def.odr}, the program is ill-formed, no diagnostic required. \pnum @@ -499,7 +499,7 @@ [[noreturn]] void f() {} \end{codeblocktu} \begin{codeblocktu}{Translation unit \#2} -void f(int i); // ill-formed no diagnostic required, declared without \tcode{noreturn} +void f(); // ill-formed no diagnostic required, declared without \tcode{noreturn} \end{codeblocktu} \end{example} diff --git a/source/ub.tex b/source/ub.tex index 4b42397c9b..48caf464bc 100644 --- a/source/ub.tex +++ b/source/ub.tex @@ -78,7 +78,7 @@ int x; }; -*make_y() { +Y* make_y() { X* p1 = (X*)std::malloc(sizeof(struct X)); p1->a = 1; Y* p2 = (Y*)p1; @@ -599,7 +599,7 @@ \pnum 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.qual} to $T$ (or its corresponding signed or unsigned types) the behavior is undefined. \pnum @@ -705,19 +705,18 @@ \ubdescription{conv.fpint.int.not.represented} \pnum -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. +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} -#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 + unsigned long long x2 = -1; + float f = x2; // undefined behavior on systems where \tcode{f} does not include + // a representation for infinity and the maximum value for \tcode{float} + // is smaller than the maximum value for \tcode{unsigned long long}. } \end{codeblock} \end{example} @@ -725,18 +724,19 @@ \ubdescription{conv.fpint.float.not.represented} \pnum -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. +When converting a floating-point value to an integer type, if +the value is not representable in the destination type it is undefined behavior. \pnum \begin{example} \begin{codeblock} +#include + 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 - // representable values are [-inf,+inf] this would not be UB + // Assuming 32-bit int the range of values are: $-2,147,483,648$ to + // $2,147,483,647$ Assuming 32-bit float and 64-bit double + double d = (double)std::numeric_limits::max() + 1; + int x1 = d; // undefined behavior $2,147,483,647 + 1$ is not representable as int } \end{codeblock} \end{example} @@ -876,8 +876,10 @@ \ubdescription{expr.static.cast.base.class} \pnum -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. +A glvalue of type \tcode{B} +can be cast to the type ``reference to \tcode{D}'' +if \tcode{B} is a base class of \tcode{D}, +otherwise the behavior is undefined. \pnum \begin{example} @@ -1178,8 +1180,11 @@ \pnum 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. +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. \pnum \begin{example} @@ -1361,11 +1366,11 @@ }; struct resumable::promise_type { - using coro_handle = std::experimental::coroutine_handle; + using coro_handle = std::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(); } + auto initial_suspend() { return std::suspend_always(); } + auto final_suspend() noexcept { return std::suspend_always(); } void unhandled_exception() { std::terminate(); } void return_value(const char* string) { string_ = string; } }; @@ -1376,7 +1381,7 @@ resumable foo() { std::cout << "Hello" << std::endl; - co_await std::experimental::suspend_always(); + co_await std::suspend_always(); // undefined behavior, falling off the end of coroutine that does not return void } @@ -1497,9 +1502,7 @@ \pnum \begin{example} \begin{codeblock} -#include - -using namespace std::experimental; +#include struct minig { struct promise_type { @@ -1554,9 +1557,7 @@ \pnum \begin{example} \begin{codeblock} -#include - -using namespace std::experimental; +#include struct minig { struct promise_type {