[clang] e28d9ba - PR44958: Allow member calls and typeid / dynamic_cast on mutable objects
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 18 14:57:22 PST 2020
Author: Richard Smith
Date: 2020-02-18T14:57:13-08:00
New Revision: e28d9bae4b3be60e90daa69a2eeb3254c952e051
URL: https://github.com/llvm/llvm-project/commit/e28d9bae4b3be60e90daa69a2eeb3254c952e051
DIFF: https://github.com/llvm/llvm-project/commit/e28d9bae4b3be60e90daa69a2eeb3254c952e051.diff
LOG: PR44958: Allow member calls and typeid / dynamic_cast on mutable objects
and objects with mutable subobjects.
The standard wording doesn't really cover these cases; accepting all
such cases seems most in line with what we do in other cases and what
other compilers do. (Essentially this means we're assuming that objects
external to the evaluation are always in-lifetime.)
Added:
Modified:
clang/lib/AST/ExprConstant.cpp
clang/test/SemaCXX/constant-expression-cxx2a.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index dfa9444c59aa..641368ebfdd9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3140,6 +3140,13 @@ struct CompleteObject {
: Base(Base), Value(Value), Type(Type) {}
bool mayAccessMutableMembers(EvalInfo &Info, AccessKinds AK) const {
+ // If this isn't a "real" access (eg, if it's just accessing the type
+ // info), allow it. We assume the type doesn't change dynamically for
+ // subobjects of constexpr objects (even though we'd hit UB here if it
+ // did). FIXME: Is this right?
+ if (!isAnyAccess(AK))
+ return true;
+
// In C++14 onwards, it is permitted to read a mutable member whose
// lifetime began within the evaluation.
// FIXME: Should we also allow this in C++11?
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 9012f377e1bc..3d5172619dbf 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -1279,3 +1279,57 @@ namespace value_dependent_init {
A a = T();
}
}
+
+namespace mutable_subobjects {
+ struct A {
+ int m;
+ mutable int n; // expected-note 2{{here}}
+ constexpr int f() const { return m; }
+ constexpr int g() const { return n; } // expected-note {{mutable}}
+ };
+
+ constexpr A a = {1, 2};
+ static_assert(a.f() == 1); // OK (PR44958)
+ static_assert(a.g() == 2); // expected-error {{constant}} expected-note {{in call}}
+
+ constexpr A b = a; // expected-error {{constant}} expected-note {{read of mutable member 'n'}} expected-note {{in call}}
+
+ auto &ti1 = typeid(a);
+ auto &ti2 = typeid(a.m);
+ auto &ti3 = typeid(a.n);
+
+ constexpr void destroy1() { // expected-error {{constexpr}}
+ a.~A(); // expected-note {{cannot modify an object that is visible outside}}
+ }
+ // FIXME: These should both be rejected once P0593 is implemented.
+ using T = int;
+ constexpr void destroy2() {
+ a.m.~T();
+ }
+ constexpr void destroy3() {
+ a.n.~T();
+ }
+
+ struct X {
+ mutable int n = 0;
+ virtual constexpr ~X() {}
+ };
+ struct Y : X {
+ };
+ constexpr Y y;
+ constexpr const X *p = &y;
+ constexpr const Y *q = dynamic_cast<const Y*>(p);
+
+ // FIXME: It's unclear whether this should be accepted. The dynamic_cast is
+ // undefined after 'z.y.~Y()`, for example. We essentially assume that all
+ // objects that the evaluator can reach have unbounded lifetimes. (We make
+ // the same assumption when evaluating member function calls.)
+ struct Z {
+ mutable Y y;
+ };
+ constexpr Z z;
+ constexpr const X *pz = &z.y;
+ constexpr const Y *qz = dynamic_cast<const Y*>(pz);
+ auto &zti = typeid(z.y);
+ static_assert(&zti == &typeid(Y));
+}
More information about the cfe-commits
mailing list