Skip to content

WIP: [std] Add Annex for undefined and IFNDR behavior #7826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2ed9326
[std] Add Annex for undefined and IFNDR behavior
jensmaurer Apr 5, 2025
6e12efa
[class.cdtor] Remove duplicate UB labels
jensmaurer Apr 5, 2025
f80cd9c
[expr.delete] Remove duplicate UB label
jensmaurer Apr 11, 2025
d92a145
[conv.fpint] Remove duplicate UB label
jensmaurer Apr 11, 2025
9d19eae
[ifndr.lex] Replace C++ with \Cpp
jensmaurer Apr 5, 2025
428d627
[ub,ifndr] Fix column alignment of comments
jensmaurer Apr 5, 2025
29f2045
[ifndr] Fix cross-references
jensmaurer Apr 5, 2025
2115438
[ub] Replace non-ASCII chars
jensmaurer Apr 5, 2025
20ffb6e
[check] Handle ub/ifndr labels
jensmaurer Apr 6, 2025
2ce67b5
[check] Exclude [ub] and [ifndr] from sibling checking for now
jensmaurer Apr 11, 2025
1372087
[ub.cpp.concat] Remove universal-character-name formation from ##; no…
jensmaurer Apr 5, 2025
51fd05f
[ifndr] Use codeblocktu
jensmaurer Apr 6, 2025
2be6676
Rename label expr.ass.overlap to expr.assign.overlap
jensmaurer Apr 13, 2025
94bbba6
[ub.basic.stc.dynamic] Fix typo
jensmaurer Apr 14, 2025
71be854
[ub] Fix some formatting (#7828)
jensmaurer Apr 22, 2025
a6064c6
Remove class.dtor.not.class.type (#7835)
jensmaurer Apr 23, 2025
0788337
Remove incorrect class.union.assignment.not.start.lifetime (#7833)
jensmaurer Apr 23, 2025
3c759d1
[ub.general,ifndr.general] Avoid hanging paragraphs by introducing 'G…
jensmaurer May 4, 2025
88a6384
[ub] Add many missing entries to UB annex (#7864)
notadragon May 14, 2025
35381f1
[conv.fpint] Remove unreferenced \ubdef that causes an undefined symb…
jensmaurer May 16, 2025
13307cb
[ub] small fixes to examples (#7890)
notadragon May 28, 2025
496f1bb
[ub] Added all missing ubdefs to bring UB annex in line with P3100R2 …
timuraudio Jun 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 29 additions & 29 deletions source/basic.tex
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@
\pnum
Every program shall contain at least one definition of every
function or variable that is odr-used in that program
outside of a discarded statement\iref{stmt.if}; no diagnostic required.
outside of a discarded statement\iref{stmt.if}; no diagnostic required\ifndrdef{basic.def.odr.exact.one.def}.
The definition can appear explicitly in the program, it can be found in
the standard or a user-defined library, or (when appropriate) it is
implicitly defined (see~\ref{class.default.ctor}, \ref{class.copy.ctor},
Expand Down Expand Up @@ -882,7 +882,7 @@
reachable unnamed enumeration definition in the same scope
that have the same first enumerator name and
do not have typedef names for linkage purposes\iref{dcl.enum},
those unnamed enumeration types shall be the same; no diagnostic required.
those unnamed enumeration types shall be the same; no diagnostic required\ifndrdef{basic.def.odr.unnamed.enum.same.type}.
\indextext{one-definition rule|)}

\rSec1[basic.scope]{Scope}%
Expand Down Expand Up @@ -1751,7 +1751,7 @@
If it is an invalid set, the program is ill-formed.
If it differs from the result of a search in $T$ for $M$
in a complete-class context\iref{class.mem} of $T$,
the program is ill-formed, no diagnostic required.
the program is ill-formed, no diagnostic required\ifndrdef{class.member.lookup.name.refers.diff.decl}.
\begin{example}
\begin{codeblock}
struct A { int x; }; // S(x,A) = \{ \{ \tcode{A::x} \}, \{ \tcode{A} \} \}
Expand Down Expand Up @@ -3486,7 +3486,7 @@
zero or more objects of implicit-lifetime types\iref{term.implicit.lifetime.type}
in its specified region of storage
if doing so would result in the program having defined behavior.
If no such set of objects would give the program defined behavior,
If no such set of objects would give the program defined behavior\ubdef{intro.object.implicit.create},
the behavior of the program is undefined.
If multiple such sets of objects would give the program defined behavior,
it is unspecified which such set of objects is created.
Expand All @@ -3504,7 +3504,7 @@
and produce a pointer value that points to that object,
if that value would result in the program having defined behavior.
If no such pointer value would give the program defined behavior,
the behavior of the program is undefined.
the behavior of the program is undefined\ubdef{intro.object.implicit.pointer}.
If multiple such pointer values would give the program defined behavior,
it is unspecified which such pointer value is produced.

Expand Down Expand Up @@ -3558,7 +3558,7 @@
using the alignment specifier\iref{dcl.align}.
Attempting to create an object\iref{intro.object} in storage that
does not meet the alignment requirements of the object's type
is undefined behavior.
is undefined behavior.\ubdef{basic.align.object.alignment}

\pnum
A \defnadj{fundamental}{alignment} is represented by an alignment
Expand Down Expand Up @@ -3748,27 +3748,27 @@
if the pointer were of type \tcode{\keyword{void}*} is
well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in
limited ways, as described below. The
program has undefined behavior if
program has undefined behavior if:
\begin{itemize}
\item
the pointer is used as the operand of a \grammarterm{delete-expression},
the pointer is used as the operand of a \grammarterm{delete-expression}\ubdef{lifetime.outside.pointer.delete},
\item
the pointer is used to access a non-static data member or call a
non-static member function of the object, or
non-static member function of the object\ubdef{lifetime.outside.pointer.member}, or
\item
the pointer is implicitly converted\iref{conv.ptr} to a pointer
to a virtual base class, or
to a virtual base class\ubdef{lifetime.outside.pointer.virtual}, or
\item
the pointer is used as the operand of a
\keyword{static_cast}\iref{expr.static.cast}, except when the conversion
\keyword{static_cast}\iref{expr.static.cast}\ubdef{lifetime.outside.pointer.static.cast}, except when the conversion
is to pointer to \cv{}~\keyword{void}, or to pointer to \cv{}~\keyword{void}
and subsequently to pointer to
\cv{}~\keyword{char},
\cv{}~\tcode{\keyword{unsigned} \keyword{char}}, or
\cv{}~\tcode{std::byte}\iref{cstddef.syn}, or
\item
the pointer is used as the operand of a
\keyword{dynamic_cast}\iref{expr.dynamic.cast}.
\keyword{dynamic_cast}\iref{expr.dynamic.cast}\ubdef{lifetime.outside.pointer.dynamic.cast}.
\end{itemize}
\begin{example}
\begin{codeblock}
Expand Down Expand Up @@ -3811,14 +3811,14 @@
a glvalue refers to
allocated storage\iref{basic.stc.dynamic.allocation}, and using the
properties of the glvalue that do not depend on its value is
well-defined. The program has undefined behavior if
well-defined. The program has undefined behavior if:
\begin{itemize}
\item the glvalue is used to access the object, or
\item the glvalue is used to call a non-static member function of the object, or
\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}, or
\item the glvalue is used to access the object\ubdef{lifetime.outside.glvalue.access}, or
\item the glvalue is used to call a non-static member function of the object\ubdef{lifetime.outside.glvalue.member}, or
\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}\ubdef{lifetime.outside.glvalue.virtual}, or
\item the glvalue is used as the operand of a
\keyword{dynamic_cast}\iref{expr.dynamic.cast} or as the operand of
\keyword{typeid}.
\keyword{typeid}\ubdef{lifetime.outside.glvalue.dynamic.cast}.
\end{itemize}

\begin{note}
Expand Down Expand Up @@ -3901,7 +3901,7 @@
\end{footnote}
and another object of the original type does not occupy
that same storage location when the implicit destructor call takes
place, the behavior of the program is undefined. This is true
place, the behavior of the program is undefined\ubdef{original.type.implicit.destructor}. This is true
even if the block is exited with an exception.
\begin{example}
\begin{codeblock}
Expand All @@ -3921,7 +3921,7 @@
Creating a new object within the storage that a const, complete
object with static, thread, or automatic storage duration occupies,
or within the storage that such a const object used to occupy before
its lifetime ended, results in undefined behavior.
its lifetime ended, results in undefined behavior\ubdef{creating.within.const.complete.obj}.
\begin{example}
\begin{codeblock}
struct B {
Expand Down Expand Up @@ -3973,7 +3973,7 @@
\pnum
Except in the following cases,
if an indeterminate value is produced by an evaluation,
the behavior is undefined, and
the behavior is undefined\ubdef{basic.indet.value}, and
if an erroneous value is produced by an evaluation,
the behavior is erroneous and
the result of the evaluation is the value so produced but is not erroneous:
Expand Down Expand Up @@ -4260,7 +4260,7 @@
does not satisfy the semantic constraints
specified in~\ref{basic.stc.dynamic.allocation}
and~\ref{basic.stc.dynamic.deallocation},
the behavior is undefined.
the behavior is undefined\ubdef{basic.stc.alloc.dealloc.constraint}.

\indextext{storage duration!dynamic|)}

Expand Down Expand Up @@ -4300,7 +4300,7 @@
\tcode{p0} represents the address of a block of storage disjoint from the storage
for any other object accessible to the caller.
The effect of indirecting through a pointer
returned from a request for zero size is undefined.
returned from a request for zero size is undefined.\ubdef{basic.stc.alloc.zero.dereference}
\begin{footnote}
The intent is
to have \tcode{\keyword{operator} \keyword{new}()} implementable by
Expand Down Expand Up @@ -4423,7 +4423,7 @@
signature.

\pnum
If a deallocation function terminates by throwing an exception, the behavior is undefined.
If a deallocation function terminates by throwing an exception, the behavior is undefined.\ubdef{basic.stc.alloc.dealloc.throw}
The value of the first argument supplied to a deallocation function may
be a null pointer value; if so, and if the deallocation function is one
supplied in the standard library, the call has no effect.
Expand Down Expand Up @@ -5634,7 +5634,7 @@
$P$ is not valid in the context of $E$,
then the behavior is undefined if $E$ is
an indirection\iref{expr.unary.op} or
an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation},
an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation}\ubdef{basic.compound.invalid.pointer},
and \impldef{invalid pointer value in the context of an evaluation} otherwise.
\begin{footnote}
Some implementations might define that
Expand Down Expand Up @@ -6152,7 +6152,7 @@
The value computations of the operands of an
operator are sequenced before the value computation of the result of the
operator.
The behavior is undefined if
The behavior is undefined\iref{intro.multithread}\ubdef{intro.execution.unsequenced.modification} if
\begin{itemize}
\item
\indextext{side effects}%
Expand Down Expand Up @@ -6552,7 +6552,7 @@
and neither happens before the other,
except for the special case for signal handlers described below.
Any such data race results in undefined
behavior.
behavior\ubdef{intro.races.data}.
\begin{note}
It can be shown that programs that correctly use mutexes
and \tcode{memory_order::seq_cst} operations to prevent all data races and use no
Expand Down Expand Up @@ -6916,7 +6916,7 @@
objects with automatic storage duration\iref{class.dtor}. If
\tcode{std::exit} is invoked during the destruction of
an object with static or thread storage duration, the program has undefined
behavior.
behavior\ubdef{basic.start.main.exit.during.destruction}.

\pnum
\indextext{termination!program}%
Expand Down Expand Up @@ -7210,7 +7210,7 @@
\pnum
If a function contains a block variable of static or thread storage duration that has been
destroyed and the function is called during the destruction of an object with static or
thread storage duration, the program has undefined behavior if the flow of control
thread storage duration, the program has undefined behavior\ubdef{basic.start.term.use.after.destruction} if the flow of control
passes through the definition of the previously destroyed block variable.
\begin{note}
Likewise, the behavior is undefined
Expand All @@ -7237,7 +7237,7 @@
handlers\iref{support.runtime} that does not happen before\iref{intro.multithread}
completion of destruction of objects with static storage duration and execution of
\tcode{std::atexit} registered functions\iref{support.start.term}, the program has
undefined behavior.
undefined behavior\ubdef{basic.start.term.signal.handler}.
\begin{note}
If there is a use of an object with static storage
duration that does not happen before the object's destruction, the program has undefined
Expand Down
25 changes: 13 additions & 12 deletions source/classes.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2356,7 +2356,7 @@

\pnum
Once a destructor is invoked for an object, the object's lifetime ends;
the behavior is undefined if the destructor is invoked
the behavior is undefined\ubdef{class.dtor.no.longer.exists} if the destructor is invoked
for an object whose lifetime has ended\iref{basic.life}.
\begin{example}
If the destructor for an object with automatic storage duration is explicitly invoked,
Expand Down Expand Up @@ -4019,7 +4019,7 @@
\indextext{definition!virtual function}%
A virtual function declared in a class shall be defined, or declared
pure\iref{class.abstract} in that class, or both; no diagnostic is
required\iref{basic.def.odr}.
required\iref{basic.def.odr}\ifndrdef{class.virtual.pure.or.defined}.
\indextext{friend!\tcode{virtual} and}%

\pnum
Expand Down Expand Up @@ -4252,7 +4252,7 @@
\indextext{virtual function call!undefined pure}%
the effect of making a virtual call\iref{class.virtual} to a pure
virtual function directly or indirectly for the object being created (or
destroyed) from such a constructor (or destructor) is undefined.%
destroyed) from such a constructor (or destructor) is undefined\ubdef{class.abstract.pure.virtual}.%
\indextext{derived class|)}

\rSec1[class.access]{Member access control}%
Expand Down Expand Up @@ -5523,7 +5523,7 @@
The target constructor is selected by overload resolution.
Once the target constructor returns, the body of the delegating constructor
is executed. If a constructor delegates to itself directly or indirectly,
the program is ill-formed, no diagnostic required.
the program is ill-formed, no diagnostic required\ifndrdef{class.base.init.delegate.itself}.
\begin{example}
\begin{codeblock}
struct C {
Expand Down Expand Up @@ -5838,7 +5838,7 @@
\item
a postcondition assertion of a destructor\iref{dcl.contract.func},
\end{itemize}
the program has undefined behavior.
the program has undefined behavior\ubdef{class.base.init.mem.fun}.
\begin{example}
\begin{codeblock}
class A {
Expand Down Expand Up @@ -6035,9 +6035,10 @@
\indextext{destruction!member access}%
For an object with a non-trivial constructor, referring to any non-static member
or base class of the object before the constructor begins execution results in
undefined behavior. For an object with a non-trivial destructor, referring to
undefined behavior\ubdef{class.cdtor.before.ctor}.
For an object with a non-trivial destructor, referring to
any non-static member or base class of the object after the destructor finishes
execution results in undefined behavior.
execution results in undefined behavior\ubdef{class.cdtor.after.dtor}.
\begin{example}
\begin{codeblock}
struct X { int i; };
Expand Down Expand Up @@ -6122,15 +6123,15 @@
indirectly derive from
\tcode{B}
shall have started and the destruction of these classes shall not have
completed, otherwise the conversion results in undefined behavior.
completed, otherwise the conversion results in undefined behavior\ubdef{class.cdtor.convert.pointer}.
To form a pointer to (or access the value of) a direct non-static member of
an object
\tcode{obj},
the construction of
\tcode{obj}
shall have started and its destruction shall not have completed,
otherwise the computation of the pointer value (or accessing the member
value) results in undefined behavior.
value) results in undefined behavior\ubdef{class.cdtor.form.pointer}.
\begin{example}
\begin{codeblock}
struct A { };
Expand Down Expand Up @@ -6174,7 +6175,7 @@
and the object expression refers to
the complete object of \tcode{x} or one of that object's base class subobjects
but not \tcode{x} or one of its base class subobjects, the behavior
is undefined.
is undefined\ubdef{class.cdtor.virtual.not.x}.
\begin{example}
\begin{codeblock}
struct V {
Expand Down Expand Up @@ -6231,7 +6232,7 @@
\tcode{typeid}
refers to the object under construction or destruction and the static type of
the operand is neither the constructor or destructor's class nor one of its
bases, the behavior is undefined.
bases, the behavior is undefined\ubdef{class.cdtor.typeid}.

\pnum
\indextext{construction!dynamic cast and}%
Expand All @@ -6256,7 +6257,7 @@
the operand is not a pointer to or object of the constructor or destructor's
own class or one of its bases, the
\keyword{dynamic_cast}
results in undefined behavior.
results in undefined behavior\ubdef{class.cdtor.dynamic.cast}.
\begin{example}
\begin{codeblock}
struct V {
Expand Down
Loading
Loading