From c4be75a2205db046c6f39e214b2280978f621fdf Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Sat, 24 Dec 2022 10:12:52 +0100 Subject: [PATCH 1/5] Suggested changes for CWG#204 (on GitHub) https://github.com/cplusplus/CWG/issues/204 --- source/basic.tex | 30 ++++++++++++++++----- source/classes.tex | 66 +++++++++++----------------------------------- 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index bd155ed606..e6f5732476 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3432,10 +3432,7 @@ program has undefined behavior if: \begin{itemize} \item - the pointer is used as the operand of a \grammarterm{delete-expression}, -\item - the pointer is used to access a non-static data member or call a - non-static member function of the object, or + the pointer is used as the operand of a \grammarterm{delete-expression}, or \item the pointer is implicitly converted\iref{conv.ptr} to a pointer to a virtual base class, or @@ -3451,6 +3448,10 @@ the pointer is used as the operand of a \keyword{dynamic_cast}\iref{expr.dynamic.cast}. \end{itemize} +\begin{note} +Referencing a non-static data member or calling a non-static member function is + performed via a glvalue formed by indirecting the pointer; see below. +\end{note} \begin{example} \begin{codeblock} #include @@ -3466,7 +3467,7 @@ void B::mutate() { new (this) D2; // reuses storage --- ends the lifetime of \tcode{*this} - f(); // undefined behavior + f(); // undefined behavior (see below) ... = this; // OK, \keyword{this} points to valid memory } @@ -3476,7 +3477,7 @@ pb->mutate(); *pb; // OK, \tcode{pb} points to valid memory void* q = pb; // OK, \tcode{pb} points to valid memory - pb->f(); // undefined behavior: lifetime of \tcode{*pb} has ended + pb->f(); // undefined behavior (see below): lifetime of \tcode{*pb} has ended } \end{codeblock} \end{example} @@ -3495,12 +3496,27 @@ 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 used to call a virtual 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 refer to a non-static data member or call a non-static + member function of a virtual base class, 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}. \end{itemize} +\begin{example} +\begin{codeblock} +struct W { int j; }; +struct X : public virtual W { }; +struct Y { + int* p; + X x; + Y() : p(&x.j) { // undefined, x is not yet constructed + } +}; +\end{codeblock} +\end{example} \pnum If, after the lifetime of an object has ended and before the storage diff --git a/source/classes.tex b/source/classes.tex index e13097d465..cd4b0b6077 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -5924,44 +5924,10 @@ \indextext{destruction|(}% \pnum -\indextext{construction!member access}% -\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 -any non-static member or base class of the object after the destructor finishes -execution results in undefined behavior. -\begin{example} -\begin{codeblock} -struct X { int i; }; -struct Y : X { Y(); }; // non-trivial -struct A { int a; }; -struct B : public A { int j; Y y; }; // non-trivial - -extern B bobj; -B* pb = &bobj; // OK -int* p1 = &bobj.a; // undefined behavior: refers to base class member -int* p2 = &bobj.y.i; // undefined behavior: refers to member's member - -A* pa = &bobj; // undefined behavior: upcast to a base class type -B bobj; // definition of \tcode{bobj} - -extern X xobj; -int* p3 = &xobj.i; // OK, \tcode{X} is a trivial class -X xobj; -\end{codeblock} -For another example, -\begin{codeblock} -struct W { int j; }; -struct X : public virtual W { }; -struct Y { - int* p; - X x; - Y() : p(&x.j) { // undefined, \tcode{x} is not yet constructed - } -}; -\end{codeblock} -\end{example} +\begin{note} +\ref{basic.life} describes how a pointer or glvalue to an object that is outside +its lifetime and is not under construction or destruction may be used. +\end{note} \pnum During the construction of an object, @@ -6001,28 +5967,28 @@ \pnum \indextext{construction!pointer to member or base}% \indextext{destruction!pointer to member or base}% +\indextext{construction!member access}% +\indextext{destruction!member access}% To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class \tcode{X} -to a pointer (reference) to a direct or indirect base class +that is under construction or destruction +to a pointer (reference) to a direct or indirect virtual base class \tcode{B} of \tcode{X}, +or to use said pointer (glvalue) to form a glvalue to a non-static data member +of the \tcode{B} subobject of \tcode{obj}, or to call a non-static member +function of said object, the construction of \tcode{X} -and the construction of all of its direct or indirect bases that directly or -indirectly derive from +and the construction of all of its direct or indirect bases +for which \tcode{B} +is a direct or indirect virtual base shall have started and the destruction of these classes shall not have -completed, otherwise the conversion results in undefined behavior. -To form a pointer to (or access the value of) a direct non-static member of -an object -\tcode{obj}, -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. +completed, otherwise the conversion, member access or member function call +results in undefined behavior. \begin{example} \begin{codeblock} struct A { }; From d36b5b5a5ee10638c8c937311f9180b20b21069e Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Sat, 24 Dec 2022 10:18:45 +0100 Subject: [PATCH 2/5] linting --- source/basic.tex | 2 +- source/classes.tex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index e6f5732476..fccb936c16 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3512,7 +3512,7 @@ struct Y { int* p; X x; - Y() : p(&x.j) { // undefined, x is not yet constructed + Y() : p(&x.j) { // undefined, x is not yet constructed } }; \end{codeblock} diff --git a/source/classes.tex b/source/classes.tex index cd4b0b6077..e6f8c216c2 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -5926,7 +5926,7 @@ \pnum \begin{note} \ref{basic.life} describes how a pointer or glvalue to an object that is outside -its lifetime and is not under construction or destruction may be used. +its lifetime and is not under construction or destruction can be used. \end{note} \pnum From f2937ee3acebf61031b7dde94d53e602d840de21 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Sat, 24 Dec 2022 10:47:32 +0100 Subject: [PATCH 3/5] add note on UB from non-virtual member function --- source/basic.tex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/basic.tex b/source/basic.tex index fccb936c16..0c124c2c0e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3496,7 +3496,13 @@ 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 virtual member function of the object, or +\item + the glvalue is used to call a virtual member function of the object, + \begin{footnote} + Evaluation of a non-virtual member function, or initialization of its + parameters, including its explicit object parameter, if any, may also result + in undefined behavior. + \end{footnote} 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 refer to a non-static data member or call a non-static From d3adfbb7f97fc4fea1748e893960ae1a3733b517 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Sat, 24 Dec 2022 10:50:07 +0100 Subject: [PATCH 4/5] lint --- source/basic.tex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 0c124c2c0e..5fdf6a3d2d 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3500,9 +3500,10 @@ the glvalue is used to call a virtual member function of the object, \begin{footnote} Evaluation of a non-virtual member function, or initialization of its - parameters, including its explicit object parameter, if any, may also result + parameters, including its explicit object parameter, if any, can also result in undefined behavior. - \end{footnote} or + \end{footnote} + 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 refer to a non-static data member or call a non-static From 5b5d2b18fae2e414c8e8c6c83f4369ced3f8f806 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Sun, 25 Dec 2022 19:58:13 +0100 Subject: [PATCH 5/5] restore prohibition on non-virtual non-static member function calls out of lifetime --- source/basic.tex | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/source/basic.tex b/source/basic.tex index 5fdf6a3d2d..8b56d12722 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3496,18 +3496,9 @@ 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 virtual member function of the object, - \begin{footnote} - Evaluation of a non-virtual member function, or initialization of its - parameters, including its explicit object parameter, if any, can also result - in undefined behavior. - \end{footnote} - 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 refer to a non-static data member or call a non-static - member function of a virtual base class, or +\item the glvalue is used to refer to a non-static data member of a virtual base class, 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}.