diff options
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CXX/expr/expr.const/p2-0x.cpp | 4 | ||||
-rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx11.cpp | 76 | ||||
-rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx1y.cpp | 46 |
3 files changed, 12 insertions, 114 deletions
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index 2496845182f..4daed23bf9c 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -210,8 +210,8 @@ namespace UndefinedBehavior { constexpr int f() const { return 0; } } constexpr c = C(); constexpr int k1 = c.f(); // ok - constexpr int k2 = ((C*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced null pointer}} - constexpr int k3 = (&c)[1].f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced one-past-the-end pointer}} + constexpr int k2 = ((C*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{cannot call member function on null pointer}} + constexpr int k3 = (&c)[1].f(); // expected-error {{constant expression}} expected-note {{cannot call member function on pointer past the end of object}} C c2; constexpr int k4 = c2.f(); // ok! diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index c136b4d2693..6af43854b52 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -192,25 +192,6 @@ namespace StaticMemberFunction { constexpr int (*sf1)(int) = &S::f; constexpr int (*sf2)(int) = &s.f; constexpr const int *sk = &s.k; - - // Note, out_of_lifetime returns an invalid pointer value, but we don't do - // anything with it (other than copy it around), so there's no UB there. - constexpr S *out_of_lifetime(S s) { return &s; } // expected-warning {{address of stack}} - static_assert(out_of_lifetime({})->k == 42, ""); - static_assert(out_of_lifetime({})->f(3) == 128, ""); - - // Similarly, using an inactive union member breaks no rules. - union U { - int n; - S s; - }; - constexpr U u = {0}; - static_assert(u.s.k == 42, ""); - static_assert(u.s.f(1) == 44, ""); - - // And likewise for a past-the-end pointer. - static_assert((&s)[1].k == 42, ""); - static_assert((&s)[1].f(1) == 44, ""); } namespace ParameterScopes { @@ -1748,10 +1729,19 @@ namespace PR14203 { constexpr duration() {} constexpr operator int() const { return 0; } }; - // These are valid per P0859R0 (moved as DR). template<typename T> void f() { + // If we want to evaluate this at the point of the template definition, we + // need to trigger the implicit definition of the move constructor at that + // point. + // FIXME: C++ does not permit us to implicitly define it at the appropriate + // times, since it is only allowed to be implicitly defined when it is + // odr-used. constexpr duration d = duration(); } + // FIXME: It's unclear whether this is valid. On the one hand, we're not + // allowed to generate a move constructor. On the other hand, if we did, + // this would be a constant expression. For now, we generate a move + // constructor here. int n = sizeof(short{duration(duration())}); } @@ -1912,52 +1902,6 @@ namespace Lifetime { }; constexpr int k1 = S().t; // expected-error {{constant expression}} expected-note {{in call}} constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}} - - struct Q { - int n = 0; - constexpr int f() const { return 0; } - }; - constexpr Q *out_of_lifetime(Q q) { return &q; } // expected-warning {{address of stack}} expected-note 2{{declared here}} - constexpr int k3 = out_of_lifetime({})->n; // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}} - constexpr int k4 = out_of_lifetime({})->f(); // expected-error {{constant expression}} expected-note {{member call on variable whose lifetime has ended}} - - constexpr int null = ((Q*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced null pointer}} - - Q q; - Q qa[3]; - constexpr int pte0 = (&q)[0].f(); // ok - constexpr int pte1 = (&q)[1].f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced one-past-the-end pointer}} - constexpr int pte2 = qa[2].f(); // ok - constexpr int pte3 = qa[3].f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced one-past-the-end pointer}} - - constexpr Q cq; - constexpr Q cqa[3]; - constexpr int cpte0 = (&cq)[0].f(); // ok - constexpr int cpte1 = (&cq)[1].f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced one-past-the-end pointer}} - constexpr int cpte2 = cqa[2].f(); // ok - constexpr int cpte3 = cqa[3].f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced one-past-the-end pointer}} - - // FIXME: There's no way if we can tell if the first call here is valid; it - // depends on the active union member. Should we reject for that reason? - union U { - int n; - Q q; - }; - U u1 = {0}; - constexpr U u2 = {0}; - constexpr int union_member1 = u1.q.f(); - constexpr int union_member2 = u2.q.f(); // expected-error {{constant expression}} expected-note {{member call on member 'q' of union with active member 'n'}} - - struct R { // expected-note {{field init}} - struct Inner { constexpr int f() const { return 0; } }; - int a = b.f(); // expected-warning {{uninitialized}} expected-note {{member call on object outside its lifetime}} - Inner b; - }; - // FIXME: This should be rejected under DR2026. - constexpr R r; // expected-note {{default constructor}} - void rf() { - constexpr R r; // expected-error {{constant expression}} expected-note {{in call}} - } } namespace Bitfields { diff --git a/clang/test/SemaCXX/constant-expression-cxx1y.cpp b/clang/test/SemaCXX/constant-expression-cxx1y.cpp index fe69d105023..07ef7974d11 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1y.cpp @@ -1159,49 +1159,3 @@ 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}} -} |