From 4ef8aa3ab6c0d7fdaf401abb95171716487e8055 Mon Sep 17 00:00:00 2001 From: jberne4 Date: Tue, 10 Feb 2026 13:10:12 -0500 Subject: [PATCH 01/20] [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/20] [*] 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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] 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/20] 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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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}