diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-12 08:57:59 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-12 08:57:59 +0000 |
commit | d3d6f4f65c77344ccf57f0ae9bea45d8c664ae0f (patch) | |
tree | 32d1efa4eb05a3ebcb8c3e987cf4d31910f4b300 /clang/test | |
parent | 91ab86fd29be1a2e0201cf214f8aaf3f24fafd8b (diff) | |
download | bcm5719-llvm-d3d6f4f65c77344ccf57f0ae9bea45d8c664ae0f.tar.gz bcm5719-llvm-d3d6f4f65c77344ccf57f0ae9bea45d8c664ae0f.zip |
Fix handling of objects under construction during constant expression
evaluation.
It's not enough to just track the LValueBase that we're evaluating, we
need to also track the path to the objects whose constructors are
running.
This reinstates r360464 (reverted in r360531) with a workaround for an
MSVC bug that previously caused the Windows bots to fail.
llvm-svn: 360537
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx1y.cpp | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/clang/test/SemaCXX/constant-expression-cxx1y.cpp b/clang/test/SemaCXX/constant-expression-cxx1y.cpp index 07ef7974d11..fe69d105023 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1y.cpp @@ -1159,3 +1159,49 @@ enum InEnum2 : int { enum class InEnum3 { THREE = indirect_builtin_constant_p("abc") }; + +// [class.ctor]p4: +// A constructor can be invoked for a const, volatile or const volatile +// object. const and volatile semantics are not applied on an object under +// construction. They come into effect when the constructor for the most +// derived object ends. +namespace ObjectsUnderConstruction { + struct A { + int n; + constexpr A() : n(1) { n = 2; } + }; + struct B { + const A a; + constexpr B(bool mutate) { + if (mutate) + const_cast<A &>(a).n = 3; // expected-note {{modification of object of const-qualified type 'const int'}} + } + }; + constexpr B b(false); + static_assert(b.a.n == 2, ""); + constexpr B bad(true); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'B(true)'}} + + struct C { + int n; + constexpr C() : n(1) { n = 2; } + }; + constexpr int f(bool get) { + volatile C c; // expected-note {{here}} + return get ? const_cast<int&>(c.n) : 0; // expected-note {{read of volatile object 'c'}} + } + static_assert(f(false) == 0, ""); // ok, can modify volatile c.n during c's initialization: it's not volatile then + static_assert(f(true) == 2, ""); // expected-error {{constant}} expected-note {{in call}} + + struct Aggregate { + int x = 0; + int y = ++x; + }; + constexpr Aggregate aggr1; + static_assert(aggr1.x == 1 && aggr1.y == 1, ""); + // FIXME: This is not specified by the standard, but sanity requires it. + constexpr Aggregate aggr2 = {}; + static_assert(aggr2.x == 1 && aggr2.y == 1, ""); + + // The lifetime of 'n' begins at the initialization, not before. + constexpr int n = ++const_cast<int&>(n); // expected-error {{constant expression}} expected-note {{modification}} +} |