[clang] cb9b984 - PR47954 / DR2126: permit temporary objects that are lifetime-extended by
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 23 14:29:28 PDT 2020
Author: Richard Smith
Date: 2020-10-23T14:29:18-07:00
New Revision: cb9b9842d31d6082c6a2259a64eb5d47bd680d32
URL: https://github.com/llvm/llvm-project/commit/cb9b9842d31d6082c6a2259a64eb5d47bd680d32
DIFF: https://github.com/llvm/llvm-project/commit/cb9b9842d31d6082c6a2259a64eb5d47bd680d32.diff
LOG: PR47954 / DR2126: permit temporary objects that are lifetime-extended by
variables that are usable in constant expressions to themselves be
usable in constant expressions.
Added:
Modified:
clang/include/clang/AST/ExprCXX.h
clang/lib/AST/ExprCXX.cpp
clang/lib/AST/ExprConstant.cpp
clang/test/CXX/drs/dr21xx.cpp
clang/test/CodeGenCXX/const-init-cxx11.cpp
clang/test/SemaCXX/constant-expression-cxx11.cpp
clang/www/cxx_dr_status.html
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 61a23ddaa368..2144279f132b 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4519,6 +4519,10 @@ class MaterializeTemporaryExpr : public Expr {
return getValueKind() == VK_LValue;
}
+ /// Determine whether this temporary object is usable in constant
+ /// expressions, as specified in C++20 [expr.const]p4.
+ bool isUsableInConstantExpressions(const ASTContext &Context) const;
+
SourceLocation getBeginLoc() const LLVM_READONLY {
return getSubExpr()->getBeginLoc();
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index c1ec86075772..b7f677051ea2 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1647,6 +1647,20 @@ void MaterializeTemporaryExpr::setExtendingDecl(ValueDecl *ExtendedBy,
ES->ManglingNumber = ManglingNumber;
}
+bool MaterializeTemporaryExpr::isUsableInConstantExpressions(
+ const ASTContext &Context) const {
+ // C++20 [expr.const]p4:
+ // An object or reference is usable in constant expressions if it is [...]
+ // a temporary object of non-volatile const-qualified literal type
+ // whose lifetime is extended to that of a variable that is usable
+ // in constant expressions
+ auto *VD = dyn_cast_or_null<VarDecl>(getExtendingDecl());
+ return VD && getType().isConstant(Context) &&
+ !getType().isVolatileQualified() &&
+ getType()->isLiteralType(Context) &&
+ VD->isUsableInConstantExpressions(Context);
+}
+
TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc, bool Value)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b33ce14b3658..fa666930ef1d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4093,27 +4093,32 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
assert(MTE->getStorageDuration() == SD_Static &&
"should have a frame for a non-global materialized temporary");
- // Per C++1y [expr.const]p2:
+ // C++20 [expr.const]p4: [DR2126]
+ // An object or reference is usable in constant expressions if it is
+ // - a temporary object of non-volatile const-qualified literal type
+ // whose lifetime is extended to that of a variable that is usable
+ // in constant expressions
+ //
+ // C++20 [expr.const]p5:
// an lvalue-to-rvalue conversion [is not allowed unless it applies to]
- // - a [...] glvalue of integral or enumeration type that refers to
- // a non-volatile const object [...]
- // [...]
- // - a [...] glvalue of literal type that refers to a non-volatile
- // object whose lifetime began within the evaluation of e.
+ // - a non-volatile glvalue that refers to an object that is usable
+ // in constant expressions, or
+ // - a non-volatile glvalue of literal type that refers to a
+ // non-volatile object whose lifetime began within the evaluation
+ // of E;
//
// C++11 misses the 'began within the evaluation of e' check and
// instead allows all temporaries, including things like:
// int &&r = 1;
// int x = ++r;
// constexpr int k = r;
- // Therefore we use the C++14 rules in C++11 too.
+ // Therefore we use the C++14-onwards rules in C++11 too.
//
// Note that temporaries whose lifetimes began while evaluating a
// variable's constructor are not usable while evaluating the
// corresponding destructor, not even if they're of const-qualified
// types.
- if (!(BaseType.isConstQualified() &&
- BaseType->isIntegralOrEnumerationType()) &&
+ if (!MTE->isUsableInConstantExpressions(Info.Ctx) &&
!lifetimeStartedInEvaluation(Info, LVal.Base)) {
if (!IsAccess)
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
diff --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp
index 7e3ffa057ef7..6810944cde65 100644
--- a/clang/test/CXX/drs/dr21xx.cpp
+++ b/clang/test/CXX/drs/dr21xx.cpp
@@ -32,6 +32,40 @@ namespace dr2120 { // dr2120: 7
static_assert(!__is_standard_layout(E), "");
}
+namespace dr2126 { // dr2126: 12
+#if __cplusplus >= 201103L
+ struct A { int n; };
+
+ const A &a = {1}; // const temporary
+ A &b = (A &)(const A &)A{1}; // const temporary
+ A &&c = (A &&)(const A &)A{1}; // const temporary
+
+ A &&d = {1}; // non-const temporary expected-note {{here}}
+ const A &e = (A &)(A &&) A{1}; // non-const temporary expected-note {{here}}
+ A &&f = (A &&)(A &&) A{1}; // non-const temporary expected-note {{here}}
+
+ constexpr const A &g = {1}; // const temporary
+ constexpr A &&h = {1}; // non-const temporary expected-note {{here}}
+
+ struct B { const A &a; };
+ B i = {{1}}; // extending decl not usable in constant expr expected-note {{here}}
+ const B j = {{1}}; // extending decl not usable in constant expr expected-note {{here}}
+ constexpr B k = {{1}}; // extending decl usable in constant expr
+
+ static_assert(a.n == 1, "");
+ static_assert(b.n == 1, "");
+ static_assert(c.n == 1, "");
+ static_assert(d.n == 1, ""); // expected-error {{constant}} expected-note {{read of temporary}}
+ static_assert(e.n == 1, ""); // expected-error {{constant}} expected-note {{read of temporary}}
+ static_assert(f.n == 1, ""); // expected-error {{constant}} expected-note {{read of temporary}}
+ static_assert(g.n == 1, "");
+ static_assert(h.n == 1, ""); // expected-error {{constant}} expected-note {{read of temporary}}
+ static_assert(i.a.n == 1, ""); // expected-error {{constant}} expected-note {{read of non-constexpr variable}}
+ static_assert(j.a.n == 1, ""); // expected-error {{constant}} expected-note {{read of temporary}}
+ static_assert(k.a.n == 1, "");
+#endif
+}
+
namespace dr2140 { // dr2140: 9
#if __cplusplus >= 201103L
union U { int a; decltype(nullptr) b; };
diff --git a/clang/test/CodeGenCXX/const-init-cxx11.cpp b/clang/test/CodeGenCXX/const-init-cxx11.cpp
index 2673ac2baa10..3684ad1c5ff1 100644
--- a/clang/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/clang/test/CodeGenCXX/const-init-cxx11.cpp
@@ -400,6 +400,22 @@ namespace UnemittedTemporaryDecl {
// CHECK: @_ZN22UnemittedTemporaryDecl4ref2E = constant i32* @_ZGRN22UnemittedTemporaryDecl3refE_
}
+namespace DR2126 {
+ struct A { int &&b; };
+ constexpr const A &a = {42};
+ // CHECK: @_ZGRN6DR21261aE0_ = internal global i32 42
+ // FIXME: This is unused and need not be emitted.
+ // CHECK: @_ZGRN6DR21261aE_ = internal constant {{.*}} { i32* @_ZGRN6DR21261aE0_ }
+ // CHECK: @_ZN6DR21261rE = constant i32* @_ZGRN6DR21261aE0_
+ int &r = a.b;
+
+ // Dynamically initialized: the temporary object bound to 'b' could be
+ // modified (eg, by placement 'new') before the initializer of 's' runs.
+ constexpr A &&b = {42};
+ // CHECK: @_ZN6DR21261sE = global i32* null
+ int &s = b.b;
+}
+
// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101
// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102
// CHECK: @__const._ZN12LocalVarInit8mutable_Ev.a = private unnamed_addr constant {{.*}} i32 103
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 7d51a48eac42..0e97798cc197 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -409,12 +409,23 @@ namespace ConstAddedByReference {
const int &r = (0);
constexpr int n = r;
+ int &&r2 = 0; // expected-note {{created here}}
+ constexpr int n2 = r2; // expected-error {{constant}} expected-note {{read of temporary}}
+
struct A { constexpr operator int() const { return 0; }};
struct B { constexpr operator const int() const { return 0; }};
const int &ra = A();
const int &rb = B();
constexpr int na = ra;
constexpr int nb = rb;
+
+ struct C { int &&r; };
+ constexpr C c1 = {1};
+ constexpr int &c1r = c1.r;
+ constexpr const C &c2 = {2};
+ constexpr int &c2r = c2.r;
+ constexpr C &&c3 = {3}; // expected-note {{created here}}
+ constexpr int &c3r = c3.r; // expected-error {{constant}} expected-note {{read of temporary}}
}
}
@@ -1843,6 +1854,11 @@ namespace InitializerList {
static_assert(*std::initializer_list<int>{1, 2, 3}.begin() == 1, "");
static_assert(std::initializer_list<int>{1, 2, 3}.begin()[2] == 3, "");
+
+ namespace DR2126 {
+ constexpr std::initializer_list<float> il = {1.0, 2.0, 3.0};
+ static_assert(il.begin()[1] == 2.0, "");
+ }
}
namespace StmtExpr {
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 74319b138943..89e4fe0f7dc9 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -12571,7 +12571,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://wg21.link/cwg2126">2126</a></td>
<td>DRWP</td>
<td>Lifetime-extended temporaries in constant expressions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 12</td>
</tr>
<tr class="open" id="2127">
<td><a href="https://wg21.link/cwg2127">2127</a></td>
@@ -13843,7 +13843,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://wg21.link/cwg2338">2338</a></td>
<td>DRWP</td>
<td>Undefined behavior converting to short enums with fixed underlying types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 12</td>
</tr>
<tr id="2339">
<td><a href="https://wg21.link/cwg2339">2339</a></td>
More information about the cfe-commits
mailing list