Skip to content

Commit 3b95ac2

Browse files
committed
P2280R4 Using unknown pointers and references in constant expressions
1 parent d59a4f3 commit 3b95ac2

File tree

1 file changed

+84
-21
lines changed

1 file changed

+84
-21
lines changed

source/expressions.tex

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7209,9 +7209,15 @@
72097209
machine\iref{intro.execution}, would evaluate one of the following:
72107210
\begin{itemize}
72117211
\item
7212-
\keyword{this}\iref{expr.prim.this}, except in a constexpr
7213-
function\iref{dcl.constexpr} that is being evaluated as part
7214-
of $E$;
7212+
\keyword{this}\iref{expr.prim.this}, except
7213+
\begin{itemize}
7214+
\item
7215+
in a constexpr function\iref{dcl.constexpr}
7216+
that is being evaluated as part of $E$ or
7217+
\item
7218+
when appearing as the \grammarterm{postfix-expression} of
7219+
an implicit or explicit class member access expression\iref{expr.ref};
7220+
\end{itemize}
72157221

72167222
\item
72177223
a control flow that passes through
@@ -7236,11 +7242,7 @@
72367242

72377243
\item
72387244
an invocation of a virtual function\iref{class.virtual}
7239-
for an object unless
7240-
\begin{itemize}
7241-
\item the object is usable in constant expressions or
7242-
\item its lifetime began within the evaluation of $E$;
7243-
\end{itemize}
7245+
for an object whose dynamic type is constexpr-unknown
72447246

72457247
\item
72467248
an expression that would exceed the implementation-defined
@@ -7284,18 +7286,6 @@
72847286
for a union whose active member (if any) is mutable,
72857287
unless the lifetime of the union object began within the evaluation of $E$;
72867288

7287-
\item
7288-
an \grammarterm{id-expression} that refers to a variable or
7289-
data member of reference type
7290-
unless the reference has a preceding initialization and either
7291-
\begin{itemize}
7292-
\item
7293-
it is usable in constant expressions or
7294-
7295-
\item
7296-
its lifetime began within the evaluation of $E$;
7297-
\end{itemize}
7298-
72997289
\item
73007290
in a \grammarterm{lambda-expression},
73017291
a reference to \keyword{this} or to a variable with
@@ -7387,7 +7377,10 @@
73877377
a \grammarterm{throw-expression}\iref{expr.throw};
73887378

73897379
\item
7390-
a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or \keyword{typeid}\iref{expr.typeid} expression
7380+
a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or
7381+
\keyword{typeid}\iref{expr.typeid} expression
7382+
on a glvalue that refers to an object
7383+
whose dynamic type is constexpr-unknown or
73917384
that would throw an exception;
73927385

73937386
\item
@@ -7469,6 +7462,71 @@
74697462
the evaluation of the underlying constructor call
74707463
disqualifies $E$ from being a core constant expression.
74717464

7465+
\pnum
7466+
During the evaluation of an expression $E$ as a core constant expression,
7467+
all \grammarterm{id-expression}s and uses of \tcode{*\keyword{this}}
7468+
that refer to an object or reference
7469+
whose lifetime did not begin with the evaluation of $E$
7470+
are treated as referring to a specific instance of that object or reference
7471+
whose lifetime and that of all subobjects (including all union members)
7472+
includes the entire constant evaluation.
7473+
For such an object that is not usable in constant expressions,
7474+
the dynamic type of the object is \defn{constexpr-unknown}.
7475+
For such a reference that is not usable in constant expressions,
7476+
the reference is treated as binding to
7477+
an unspecified object of the referenced type
7478+
whose lifetime and that of all subobjects includes
7479+
the entire constant evaluation and whose dynamic type is constexpr-unknown.
7480+
\begin{example}
7481+
\begin{codeblock}
7482+
template <typename T, size_t N>
7483+
constexpr size_t array_size(T (&)[N]) {
7484+
return N;
7485+
}
7486+
7487+
void use_array(int const (&gold_medal_mel)[2]) {
7488+
constexpr auto gold = array_size(gold_medal_mel); // OK
7489+
}
7490+
7491+
constexpr auto olympic_mile() {
7492+
const int ledecky = 1500;
7493+
return []{ return ledecky; };
7494+
}
7495+
static_assert(olympic_mile()() == 1500); // OK
7496+
7497+
struct Swim {
7498+
constexpr int phelps() { return 28; }
7499+
virtual constexpr int lochte() { return 12; }
7500+
int coughlin = 12;
7501+
};
7502+
7503+
constexpr int how_many(Swim& swam) {
7504+
Swim* p = &swam;
7505+
return (p + 1 - 1)->phelps();
7506+
}
7507+
7508+
void splash(Swim& swam) {
7509+
static_assert(swam.phelps() == 28); // OK
7510+
static_assert((&swam)->phelps() == 28); // OK
7511+
Swim* pswam = &swam;
7512+
static_assert(pswam->phelps() == 28); // error: lvalue-to-rvalue conversion on a pointer
7513+
// not usable in constant expressions
7514+
static_assert(how_many(swam) == 28); // OK
7515+
static_assert(Swim().lochte() == 12); // OK
7516+
static_assert(swam.lochte() == 12); // error: invoking virtual function on reference
7517+
// with constexpr-unknown dynamic type
7518+
static_assert(swam.coughlin == 12); // error: lvalue-to-rvalue conversion on an object
7519+
// not usable in constant expressions
7520+
}
7521+
7522+
extern Swim dc;
7523+
extern Swim& trident;
7524+
7525+
constexpr auto& sandeno = typeid(dc); // OK, can only be \tcode{typeid(Swim)}
7526+
constexpr auto& gallagher = typeid(trident); // error: constexpr-unknown dynamic type
7527+
\end{codeblock}
7528+
\end{example}
7529+
74727530
\pnum
74737531
An object \tcode{a} is said to have \defnadj{constant}{destruction} if:
74747532
\begin{itemize}
@@ -7582,6 +7640,11 @@
75827640
object with static storage duration that either is not a temporary object or is
75837641
a temporary object whose value satisfies the above constraints, or if
75847642
it is a non-immediate function.
7643+
\begin{note}
7644+
A glvalue core constant expression
7645+
that either refers to or points to an unspecified object
7646+
is not a constant expression.
7647+
\end{note}
75857648
\begin{example}
75867649
\begin{codeblock}
75877650
consteval int f() { return 42; }

0 commit comments

Comments
 (0)