diff --git a/source/basic.tex b/source/basic.tex index bf53cb3f67..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} @@ -3840,7 +3841,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 +4586,7 @@ \tcode{p0} represents the address of a block of storage disjoint from the storage for any other object accessible to the caller. The effect of indirecting through a pointer -returned from a request for zero size is undefined.\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 +4709,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. @@ -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 ae650118b0..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. @@ -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&); @@ -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/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 diff --git a/source/ifndr.tex b/source/ifndr.tex index 0185e2ccfa..267440c6a7 100644 --- a/source/ifndr.tex +++ b/source/ifndr.tex @@ -34,6 +34,33 @@ \rSec1[ifndr.basic]{\ref{basic}: Basics} +\rSec2[ifndr.basic.link]{Program and linkage} + +\pnum +\ifndrxref{basic.link.consistent.types} +Multiple declarations of an entity must be consistent, +no diagnostic is required if neither declaration is reachable +from the other. + +\pnum +\begin{example} +\begin{codeblocktu}{Module interface of \tcode{M}} +void g(); // \#1 +void h(); // \#2 +template int j; // \#3 +\end{codeblocktu} +\begin{codeblocktu}{Module interface of \tcode{N}} +int g(); // same entity as \#1, different type +namespace h {} // same entity as \#2, not both namespaces +template int j; // same entity as \#3, non-equivalent template heads +\end{codeblocktu} +\begin{codeblocktu}{Other translation unit} +import M; +import N; + // ill-formed, no diagnostic required due to the mismatched pairs above +\end{codeblocktu} +\end{example} + \rSec2[ifndr.basic.def.odr]{One-definition rule} \pnum @@ -81,7 +108,49 @@ \end{example} -\rSec2[ifndr.class.member.lookup]{Member name lookup} +\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.basic.lookup]{Name lookup} + +\rSec3[ifndr.class.member.lookup]{Member name lookup} \pnum \ifndrxref{class.member.lookup.name.refers.diff.decl} @@ -128,7 +197,11 @@ \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} + +\rSec4[ifndr.expr.prim.req.general]{General} \pnum \ifndrxref{expr.prim.req.always.sub.fail} @@ -146,7 +219,7 @@ \end{example} -\rSec1[ifndr.stmt.stmt]{\ref{stmt}: Statements} +\rSec1[ifndr.stmt]{\ref{stmt}: Statements} \rSec2[ifndr.stmt.ambig]{Ambiguity resolution} @@ -176,9 +249,151 @@ \end{example} -\rSec1[ifndr.dcl.dcl]{\ref{dcl}: Declarations} +\rSec1[ifndr.dcl]{\ref{dcl}: Declarations} + +\rSec2[ifndr.dcl.spec]{Specifiers} + +\rSec3[ifndr.dcl.constinit]{The \keyword{constinit} specifier} + +\pnum +\ifndrxref{dcl.constinit.specifier.not.reachable} +If the initializing declaration +of a variable that has the \tcode{constinit} specifier +applied to declarations not reachable from +that initializing declaration +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int x = 5; // initializing declaration of \tcode{z} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +extern constinit int x; // IFNDR, not reachable from initializing declaration of \tcode{x} +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.inline]{The \keyword{inline} specifier} + +\pnum +\ifndrxref{dcl.inline.missing.on.definition} +If a function or variable +with external or module linkage +is declared inline +but there is no inline declaration +reachable from the end of some definition domain +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline int f(); +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int f() { return 17; } + // IFNDR, end of definition domain but no inline declaration of \tcode{f} is reachable. +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.decl]{Declarators} + +\rSec3[ifndr.dcl.meaning]{Meaning of declarators} + +\rSec4[ifndr.dcl.fct.default]{Default arguments} + +\pnum +\ifndrxref{dcl.fct.default.inline.same.defaults} +If the accumulated set of default arguments +for a given inline function +with definitions in multiple translation units +is different at the end +of different translation units, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline int f(int x, int y = 2); +inline int f(int x = 1, int y); + // IFNDR, default arguments of \tcode{f} are \tcode{1} and \tcode{2} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +inline int f(int x = 3, int y = 4); + // IFNDR, default arguments of \tcode{f} are \tcode{3} and \tcode{4} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.contract]{Function contract specifiers} + +\rSec3[ifndr.dcl.contract.func]{General} + +\pnum +\ifndrxref{dcl.contract.func.mismatched.contract.specifiers} +If two different first declarations of a function +(which must therefore not be reachable from one another) +do not have equivalent function contract specifiers +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int f(int x) pre(x >= 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{f} +int g(int x) pre(x == 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{g} +int h(int x) pre(x <= 0); // OK, equivalent function contract specifiers to the other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int f(int x); // IFNDR, different function contract specifiers from the other first declaration of \tcode{f} +int g(int x) pre(x != 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{g} +int h(int y) pre(y <= 0); // OK, equivalent function contract specifiers to the other first declaration of \tcode{h} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.fct.def]{Function definitions} + +\rSec3[ifndr.dcl.fct.def.replace]{Replaceable function definitions} + +\pnum +\ifndrxref{dcl.fct.def.replace.bad.replacement} +A declaration of a replaceable function +that is inline, +not attached to the global module, +does not have \Cpp{} language linkage, +does not have the required return type, +or is not a valid redeclaration of the +corresponding declaration in a standard library header (if there is one) +then the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +extern "C" // IFNDR, wrong language linkage +inline // IFNDR, inline +int // IFNDR, wrong return type +handle_contract_violation(const std::contract::contract_violation&) {} + +void* operator new(decltype(sizeof(0)) noexcept; // IFNDR, mismatched exception specification to declaration + // in \tcode{} +\end{codeblock} +\end{example} + +\rSec2[ifndr.dcl.link]{Linkage specifications} + +\pnum +\ifndrxref{dcl.link.mismatched.language.linkage} +If two declarations of an entity +do not have the same language linkage +and neither is reachable from the other +the program is ill-formed, no diagnostic required. -\rSec2[ifndr.dcl.align]{Alignment specifier} +\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,10 +411,35 @@ \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{codeblocktu}{Translation unit \#1} +int h(int x [[indeterminate]]; // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int h(int x); // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.attr.noreturn]{Noreturn attribute} \pnum \ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} +No diagnostic is requried if a function is declared +in one translation unit with the \tcode{noreturn} attribute +but has declarations in other translation units +without the attribute. + +\pnum \begin{example} \begin{codeblocktu}{Translation unit \#1} [[noreturn]] void f() {} @@ -245,10 +485,57 @@ \end{codeblock} \end{example} +\pnum +\ifndrxref{module.unit.unexported.module.partition} +If a module partition of a module +that is a module interface unit +but is not directly or indirectly exported +by the primary module interface unit\iref{module.import}, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M; // primary module interface unit +export import :A; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +export module M:A; // OK, directly exported by \tcode{M} +export import :B; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#3} +export module M:B; // OK, indirectly exported by \tcode{M} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#4} +export module M:C; // IFNDR, not directl or indirectly exported by \tcode{M} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.module.private.frag]{Private module fragment} + +\pnum +\ifndrxref{module.private.frag.other.module.units} +If a module has a private module fragment +and there is another module unit of that module, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M; +module :private; // private module fragment +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +module M:A; // IFNDR, partition of \tcode{M} with private module fragment +\end{codeblocktu} +\end{example} + \rSec1[ifndr.class]{\ref{class}: Classes} -\rSec2[ifndr.class.base.init]{Initializing bases and members} +\rSec2[ifndr.class.init]{Initialization} + +\rSec3[ifndr.class.base.init]{Initializing bases and members} \pnum \ifndrxref{class.base.init.delegate.itself} @@ -267,8 +554,9 @@ \end{codeblock} \end{example} +\rSec2[ifndr.class.derived]{Derived classes} -\rSec2[ifndr.class.virtual]{Virtual functions} +\rSec3[ifndr.class.virtual]{Virtual functions} \pnum \ifndrxref{class.virtual.pure.or.defined} @@ -334,8 +622,9 @@ \end{codeblock} \end{example} +\rSec2[ifndr.temp.arg]{Template arguments} -\rSec2[ifndr.temp.arg.template]{Template template arguments} +\rSec3[ifndr.temp.arg.template]{Template template arguments} \pnum \ifndrxref{temp.arg.template.sat.constraints} @@ -366,8 +655,11 @@ \end{codeblock} \end{example} +\rSec2[ifndr.temp.constr]{Template constraints} -\rSec2[ifndr.constr.atomic]{Atomic constraints} +\rSec3[ifndr.temp.constr.constr]{Constraints} + +\rSec4[ifndr.temp.constr.atomic]{Atomic constraints} \pnum \ifndrxref{temp.constr.atomic.equiv.but.not.equiv} @@ -407,8 +699,7 @@ \end{codeblock} \end{example} - -\rSec2[ifndr.temp.constr.normal]{Constraint normalization} +\rSec3[ifndr.temp.constr.normal]{Constraint normalization} \pnum \ifndrxref{temp.constr.normal.invalid} @@ -426,7 +717,15 @@ \end{example} -\rSec2[ifndr.temp.spec.partial]{Partial specialization} +%TODO: JMB: There are two earlier "no diagnostic requireds" in this section, i am +% not sure if they a really are worth calling distinct cases of ifndr, as they +% are all variations on producing an invalid construct upon substitution + +\rSec2[ifndr.temp.decls]{Template declarations} + +\rSec3[ifndr.temp.spec.partial]{Partial specialization} + +\rSec4[ifndr.temp.spec.partial.general]{General} \pnum \ifndrxref{temp.spec.partial.general.partial.reachable} @@ -452,31 +751,9 @@ \end{example} -\rSec2[ifndr.temp.names]{Names of template specializations} +\rSec3[ifndr.temp.fct]{Function templates} -\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} - - -\rSec2[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} @@ -512,9 +789,11 @@ \end{codeblock} \end{example} -\rSec2[ifndr.temp.dep.res]{Dependent name resolution} +%TODO: SY, JMB: We need to produce an example for this case. -\rSec3[ifndr.temp.point]{Point of instantiation} +\rSec3[ifndr.temp.dep.res]{Dependent name resolution} + +\rSec4[ifndr.temp.point]{Point of instantiation} \pnum \ifndrxref{temp.point.diff.pt.diff.meaning} @@ -547,8 +826,29 @@ \end{codeblock} \end{example} +\rSec4[ifndr.temp.dep.candidate]{Candidate functions} -\rSec2[ifndr.temp.explicit]{Explicit instantiation} +\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.spec]{Template instantiation and specialization} + +\rSec3[ifndr.temp.explicit]{Explicit instantiation} \pnum \ifndrxref{temp.explicit.decl.implicit.inst} @@ -570,26 +870,124 @@ \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. -\rSec2[ifndr.temp.deduct]{Template argument deduction} +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} -\rSec3[ifndr.temp.deduct.general]{General} +%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} +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} + +\rSec2[ifndr.temp.fct.spec]{Function template specializations} + +\rSec3[ifndr.temp.deduct]{Template argument deduction} + +\rSec4[ifndr.temp.deduct.general]{General} \pnum \ifndrxref{temp.deduct.general.diff.order} If substitution -into different declarations of the same function template would cause template instantiations to occur in a -different order or not at all, the program is ill-formed; no diagnostic required. +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. + + +\rSec1[ifndr.cpp]{\ref{cpp}: Preprocessing directives} + +\rSec2[ifndr.cpp.cond]{Conditional inclusion} + +\pnum +\ifndrxref{cpp.cond.defined.after.macro} +If the expansion of a macro produces the preprocessing token \tcode{defined} +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#define A defined +#if A // Ill-formed no diagnostic required, \tcode{defined} is generated by macro replacement + // in controlling expression +#endif +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{cpp.cond.defined.malformed} +If the \tcode{defined} unary operator is used when it +does not match +one of the specified grammatical forms, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#define A +#define B A) +#if defined ( B // Ill-formed no diagnostic required, unary operator \tcode{defined} did not match + // valid form before replacement +#endif +\end{codeblock} +\end{example} + +\rSec2[ifndr.cpp.include]{Source file inclusion} + +\pnum +\ifndrxref{cpp.include.malformed.headername} +If the \grammarterm{header-name-tokens} after +an \tcode{include} directive +cannot be formed into a \grammarterm{header-name} +(with implementation-defined treatment of whitespace), +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#include `` // Ill-formed no diagnoatic required, does not match one of the two allowable forms +\end{codeblock} +\end{example} diff --git a/source/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/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} diff --git a/source/templates.tex b/source/templates.tex index 8ce89369d1..de6fd2c460 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} @@ -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 @@ -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} diff --git a/source/ub.tex b/source/ub.tex index d913666ede..f446787123 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]{Object model} \pnum \ubxref{intro.object.implicit.create} @@ -36,7 +38,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{intro.object.implicit.pointer} After implicitly creating objects within a specified region of storage, @@ -90,7 +91,12 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.align]{Object alignment} +%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 ..." + +\rSec3[ub.basic.align]{Alignment} \pnum \ubxref{basic.align.object.alignment} @@ -105,12 +111,14 @@ 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} -\rSec2[ub.basic.life]{Object lifetime} +\rSec3[ub.basic.life]{Lifetime} \pnum \ubxref{lifetime.outside.pointer.delete} @@ -161,8 +169,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} @@ -281,8 +289,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. +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} @@ -300,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 @@ -324,7 +333,7 @@ \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} @@ -343,7 +352,11 @@ \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} + +\rSec5[ub.basic.stc.dynamic.general]{General} \pnum \ubxref{basic.stc.alloc.dealloc.constraint} @@ -352,7 +365,6 @@ in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}. the behavior is undefined. - \pnum \begin{example} \begin{codeblock} @@ -370,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 @@ -389,9 +403,7 @@ \end{codeblock} \end{example} - - -\rSec2[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} @@ -409,7 +421,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} @@ -434,8 +448,9 @@ \end{codeblock} \end{example} +\rSec2[ub.basic.exec]{Program execution} -\rSec2[ub.intro.execution]{Sequential execution} +\rSec3[ub.intro.execution]{Sequential execution} \pnum \ubxref{intro.execution.unsequenced.modification} @@ -457,7 +472,9 @@ \end{codeblock} \end{example} -\rSec2[ub.intro.races]{Data races} +\rSec3[ub.intro.multithread]{Multi-threaded executions and data races} + +\rSec4[ub.intro.races]{Data races} \pnum \ubxref{intro.races.data} @@ -475,7 +492,7 @@ \end{codeblock} \end{example} -\rSec2[ub.intro.progress]{Forward progress} +\rSec4[ub.intro.progress]{Forward progress} \pnum \ubxref{intro.progress.stops} @@ -498,7 +515,9 @@ \end{codeblock} \end{example} -\rSec2[ub.basic.start.main]{main function} +\rSec3[ub.basic.start]{Start and termination} + +\rSec4[ub.basic.start.main]{\tcode{main} function} \pnum \ubxref{basic.start.main.exit.during.destruction} @@ -515,15 +534,14 @@ ~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} \end{codeblock} \end{example} - -\rSec2[ub.basic.start.term]{Termination} +\rSec4[ub.basic.start.term]{Termination} \pnum \ubxref{basic.start.term.use.after.destruction} @@ -549,7 +567,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 @@ -558,22 +576,20 @@ \end{codeblock} \end{example} - \pnum \ubxref{basic.start.term.signal.handler} If there is a use of a standard library object or function not permitted within signal handlers\iref{support.runtime} that does not happen before\iref{intro.multithread} completion of destruction of objects with static storage duration and execution of std::atexit registered functions\iref{support.start.term}, the program has undefined behavior. -\pnum -\begin{example} -\begin{codeblock} -\end{codeblock} -\end{example} - +%TODO: JMB/TD: This is really a general precondition imposed on the Standard +%Library, not a piece of core language undefined behavior. It is also currently +%missing an example. Should we retain this UB? Should we have a core issue +%to move this wording into the library section somewhere? +%TODO: SY: If we keep this, we should have an example. \rSec1[ub.expr]{\ref{expr}: Expressions} -\rSec2[ub.expr.eval]{Result of Expression not Mathematically Defined/out of Range} +\rSec2[ub.expr.pre]{Preamble} \pnum \ubxref{expr.expr.eval} @@ -585,14 +601,18 @@ \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} -\rSec2[ub.basic.lval]{Value category} +\rSec2[ub.expr.prop]{Properties of expressions} + +\rSec3[ub.basic.lval]{Value category} \pnum \ubxref{expr.basic.lvalue.strict.aliasing.violation} @@ -621,7 +641,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. @@ -637,7 +658,7 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.type]{Type} +\rSec3[ub.expr.type]{Type} \pnum \ubxref{expr.type.reference.lifetime} @@ -657,7 +678,9 @@ \end{codeblock} \end{example} -\rSec2[ub.conv.lval]{Lvalue-to-rvalue conversion} +\rSec2[ub.conv]{Standard conversions} + +\rSec3[ub.conv.lval]{Lvalue-to-rvalue conversion} \pnum \ubxref{conv.lval.valid.representation} @@ -680,8 +703,7 @@ \end{codeblock} \end{example} - -\rSec2[ub.conv.double]{Floating-point conversions} +\rSec3[ub.conv.double]{Floating-point conversions} \pnum \ubxref{conv.double.out.of.range} @@ -697,14 +719,13 @@ 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} \end{example} - -\rSec2[ub.conv.fpint]{Floating-integral conversions} +\rSec3[ub.conv.fpint]{Floating-integral conversions} \pnum \ubxref{conv.fpint.int.not.represented} @@ -717,10 +738,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} @@ -743,7 +764,7 @@ \end{codeblock} \end{example} -\rSec2[ub.conv.ptr]{Pointer conversions} +\rSec3[ub.conv.ptr]{Pointer conversions} \pnum \ubxref{conv.ptr.virtual.base} @@ -769,7 +790,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} @@ -795,12 +816,17 @@ \end{example} +\rSec2[ub.expr.compound]{Compound expressions} + +\rSec3[ub.expr.post]{Postfix expressions} -\rSec2[ub.expr.call]{Function call} +\rSec4[ub.expr.call]{Function call} \pnum \ubxref{expr.call.different.type} -Calling a function through an expression whose function type is different from the function type of the called +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 @@ -820,7 +846,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} @@ -840,8 +866,10 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.dynamic.cast]{Dynamic cast} +%TODO: SY: The wording is not great, I don't have a good suggestion but we should +%get some opinions +\rSec4[ub.expr.dynamic.cast]{Dynamic cast} \pnum \ubxref{expr.dynamic.cast.pointer.lifetime} @@ -860,7 +888,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{expr.dynamic.cast.glvalue.lifetime} Evaluating a \keyword{dynamic_cast} on a reference that @@ -878,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} @@ -888,7 +915,7 @@ \pnum \begin{example} \begin{codeblock} -truct B {}; +struct B {}; struct D1 : B {}; struct D2 : B {}; @@ -938,10 +965,11 @@ \end{codeblock} \end{example} - \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,9 +987,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 \begin{example} @@ -983,7 +1017,9 @@ \end{codeblock} \end{example} -\rSec2[ub.expr.unary.op]{Unary operators} +\rSec3[ub.expr.unary]{Unary expressions} + +\rSec4[ub.expr.unary.op]{Unary operators} \pnum \ubxref{expr.unary.dereference} @@ -1001,8 +1037,7 @@ \end{codeblock} \end{example} - -\rSec2[ub.expr.new]{New} +\rSec4[ub.expr.new]{New} \pnum \ubxref{expr.new.non.allocating.null} @@ -1033,8 +1068,7 @@ \end{codeblock} \end{example} - -\rSec2[ub.expr.delete]{Delete} +\rSec4[ub.expr.delete]{Delete} \pnum \ubxref{expr.delete.mismatch} @@ -1060,11 +1094,10 @@ \end{codeblock} \end{example} - \pnum \ubxref{expr.delete.dynamic.type.differ} If the static type of the object to be deleted is different from its dynamic -type and the selected deallocation function (see below) is not a destroying operator delete, the static type +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. @@ -1086,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. @@ -1112,8 +1144,7 @@ \end{codeblock} \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} @@ -1137,10 +1168,9 @@ \end{codeblock} \end{example} - \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 @@ -1158,8 +1188,7 @@ \end{codeblock} \end{example} - -\rSec2[ub.expr.mul]{Multiplicative operators} +\rSec3[ub.expr.mul]{Multiplicative operators} \pnum \ubxref{expr.mul.div.by.zero} @@ -1189,14 +1218,14 @@ #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} -\rSec2[ub.expr.add]{Additive operators} +\rSec3[ub.expr.add]{Additive operators} \pnum \ubxref{expr.add.out.of.bounds} @@ -1244,7 +1273,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 @@ -1271,8 +1301,7 @@ \end{codeblock} \end{example} - -\rSec2[ub.expr.shift]{Shift operators} +\rSec3[ub.expr.shift]{Shift operators} \pnum \ubxref{expr.shift.neg.and.width} @@ -1289,8 +1318,7 @@ \end{codeblock} \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} @@ -1305,14 +1333,17 @@ \end{codeblock} \end{example} -\rSec1[ub.stmt.stmt]{\ref{stmt}: Statements} +\rSec1[ub.stmt]{\ref{stmt}: Statements} -\rSec2[ub.stmt.return]{The return statement} +\rSec2[ub.stmt.jump]{Jump statements} + +\rSec3[ub.stmt.return]{The \keyword{return} statement} \pnum \ubxref{stmt.return.flow.off} Flowing off the end of a function other -than main or a coroutine results in undefined behavior. +than main or a coroutine results in undefined behavior if the return type +is not \cv{}~\keyword{void}. \pnum \begin{example} @@ -1330,11 +1361,13 @@ \end{codeblock} \end{example} -\rSec2[ub.return.coroutine]{The co_return statement} +\rSec3[ub.stmt.return.coroutine]{The \keyword{co_return} statement} \pnum \ubxref{stmt.return.coroutine.flow.off} -Falling off the end of a coroutine function body that does not return void is undefined behavior. +Flowing off the end of a coroutine function body +that does not return void +has undefined behavior. \pnum \begin{example} @@ -1411,10 +1444,13 @@ +\rSec1[ub.dcl]{\ref{dcl}: Declarations} -\rSec1[ub.dcl.dcl]{\ref{dcl}: Declarations} +\rSec2[ub.dcl.spec]{Specifiers} -\rSec2[ub.dcl.type.cv]{The cv-qualifiers} +\rSec3[ub.dcl.type]{Type specifiers} + +\rSec4[ub.dcl.type.cv]{The \fakegrammarterm{cv-qualifier}{s}} \pnum \ubxref{dcl.type.cv.modify.const.obj} @@ -1430,7 +1466,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{dcl.type.cv.access.volatile} If an attempt is made to @@ -1446,7 +1481,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} @@ -1498,8 +1537,9 @@ +\rSec2[ub.dcl.fct.def]{Function definitions} -\rSec2[ub.dcl.fct.def.coroutine]{Coroutine definitions} +\rSec3[ub.dcl.fct.def.coroutine]{Coroutine definitions} \pnum \ubxref{dcl.fct.def.coroutine.resume.not.suspended} @@ -1557,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. @@ -1614,11 +1653,13 @@ \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} -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 @@ -1635,8 +1676,7 @@ \end{codeblock} \end{example} - -\rSec2[ub.dcl.attr.noreturn]{Noreturn attribute} +\rSec3[ub.dcl.attr.noreturn]{Noreturn attribute} \pnum \ubxref{dcl.attr.noreturn.eventually.returns} @@ -1657,14 +1697,17 @@ \end{codeblock} \end{example} - \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} -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 @@ -1676,13 +1719,14 @@ 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} +\rSec2[ub.class.derived]{Derived classes} -\rSec2[ub.class.abstract]{Abstract classes} +\rSec3[ub.class.abstract]{Abstract classes} \pnum \ubxref{class.abstract.pure.virtual} @@ -1704,8 +1748,9 @@ \end{codeblock} \end{example} +\rSec2[ub.class.init]{Initialization} -\rSec2[ub.class.base.init]{Initializing bases and members} +\rSec3[ub.class.base.init]{Initializing bases and members} \pnum \ubxref{class.base.init.mem.fun} @@ -1725,7 +1770,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 }; @@ -1745,15 +1790,12 @@ \end{codeblock} \end{example} - -\rSec2[ub.class.cdtor]{Construction and destruction} +\rSec3[ub.class.cdtor]{Construction and destruction} \pnum \ubxref{class.cdtor.before.ctor} For an object with a non-trivial constructor, referring to any non-static member or base class of the object -before the constructor begins execution results in undefined behavior. 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 +1839,7 @@ \end{codeblock} \end{example} +%TODO: CM: Can this example be shortened? \pnum \ubxref{class.cdtor.after.dtor} @@ -1917,7 +1960,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{class.cdtor.typeid} If the operand of \tcode{typeid} refers to @@ -1948,7 +1990,6 @@ \end{codeblock} \end{example} - \pnum \ubxref{class.cdtor.dynamic.cast} If the operand of the @@ -1979,9 +2020,11 @@ \end{codeblock} \end{example} - \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} @@ -2004,7 +2047,6 @@ \end{codeblock} \end{example} - \rSec1[ub.except]{\ref{except}: Exception handling} \rSec2[ub.except.handle]{Handling an exception}