From 9fe270eb95486914f6e9176bc11a9d0cd03bc1bc Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Fri, 12 Feb 2021 21:48:58 +0100 Subject: [PATCH] [conv.lval] Determine the value of a constant without accessing an object --- source/expressions.tex | 63 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/source/expressions.tex b/source/expressions.tex index 5a62b5b6a5..0dc42f5487 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -599,7 +599,7 @@ \pnum \indextext{conversion!lvalue-to-rvalue}% \indextext{type!incomplete}% -A glvalue\iref{basic.lval} of a non-function, non-array type \tcode{T} +A glvalue\iref{basic.lval} $E$ of a non-function, non-array type \tcode{T} can be converted to a prvalue. \begin{footnote} @@ -618,38 +618,21 @@ cv-qualified types. \end{footnote} -\pnum -When an lvalue-to-rvalue conversion -is applied to an expression $E$, and either -\begin{itemize} -\item $E$ is not potentially evaluated, or -\item the evaluation of $E$ results in the evaluation of a member - $E_\tcode{x}$ of the set of potential results of $E$, and $E_\tcode{x}$ - names a variable \tcode{x} that is not odr-used by - $E_\tcode{x}$\iref{basic.def.odr}, -\end{itemize} -the value contained in the referenced object is not accessed. -\begin{example} -\begin{codeblock} -struct S { int n; }; -auto f() { - S x { 1 }; - constexpr S y { 2 }; - return [&](bool b) { return (b ? y : x).n; }; -} -auto g = f(); -int m = g(false); // undefined behavior: access of \tcode{x.n} outside its lifetime -int n = g(true); // OK, does not access \tcode{y.n} -\end{codeblock} -\end{example} - \pnum The result of the conversion is determined according to the following rules: \begin{itemize} -\item If \tcode{T} is \cv{}~\tcode{std::nullptr_t}, the result is a +\item If $E$ is not potentially evaluated, +the result is an unspecified value of type \tcode{T}. +\begin{note} +An expression that is not potentially evaluated is only +analyzed for its type or other expression properties, +thus its value is not relevant. +\end{note} + +\item Otherwise, if \tcode{T} is \cv{}~\tcode{std::nullptr_t}, the result is a null pointer constant\iref{conv.ptr}. \begin{note} Since the conversion does not access the object to which the glvalue refers, @@ -661,6 +644,17 @@ type, the conversion copy-initializes the result object from the glvalue. +\item Otherwise, +if the evaluation of $E$ results in +the evaluation of a member $E_\tcode{x}$ of the set of potential results of $E$, +and $E_\tcode{x}$ names a variable \tcode{x} +that is not odr-used by $E_\tcode{x}$\iref{basic.def.odr}, +the result is the value of \tcode{x}. +\begin{note} +The variable \tcode{x} is thus usable in constant expressions\iref{expr.const}; +the conversion does not access the object to which the glvalue refers. +\end{note} + \item Otherwise, if the object to which the glvalue refers contains an invalid pointer value~(\ref{basic.stc.dynamic.deallocation}, \ref{basic.stc.dynamic.safety}), the behavior is @@ -675,6 +669,21 @@ See also~\ref{basic.lval}. \end{note} +\pnum +\begin{example} +\begin{codeblock} +struct S { int n; }; +auto f() { + S x { 1 }; + constexpr S y { 2 }; + return [&](bool b) { return (b ? y : x).n; }; +} +auto g = f(); +int m = g(false); // undefined behavior: access of \tcode{x.n} outside its lifetime +int n = g(true); // OK, does not access \tcode{y.n} +\end{codeblock} +\end{example} + \rSec2[conv.array]{Array-to-pointer conversion} \pnum