summaryrefslogtreecommitdiffstats
path: root/clang/test/SemaCXX/constant-expression-cxx2a.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/SemaCXX/constant-expression-cxx2a.cpp')
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx2a.cpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index bb2a4a07dd8..e8819edd4ee 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -211,3 +211,94 @@ constexpr bool for_range_init() {
return k == 6;
}
static_assert(for_range_init());
+
+namespace Virtual {
+ struct NonZeroOffset { int padding = 123; };
+
+ // Ensure that we pick the right final overrider during construction.
+ struct A {
+ virtual constexpr char f() const { return 'A'; }
+ char a = f();
+ };
+ struct NoOverrideA : A {};
+ struct B : NonZeroOffset, NoOverrideA {
+ virtual constexpr char f() const { return 'B'; }
+ char b = f();
+ };
+ struct NoOverrideB : B {};
+ struct C : NonZeroOffset, A {
+ virtual constexpr char f() const { return 'C'; }
+ A *pba;
+ char c = ((A*)this)->f();
+ char ba = pba->f();
+ constexpr C(A *pba) : pba(pba) {}
+ };
+ struct D : NonZeroOffset, NoOverrideB, C { // expected-warning {{inaccessible}}
+ virtual constexpr char f() const { return 'D'; }
+ char d = f();
+ constexpr D() : C((B*)this) {}
+ };
+ constexpr D d;
+ static_assert(((B&)d).a == 'A');
+ static_assert(((C&)d).a == 'A');
+ static_assert(d.b == 'B');
+ static_assert(d.c == 'C');
+ // During the construction of C, the dynamic type of B's A is B.
+ static_assert(d.ba == 'B');
+ static_assert(d.d == 'D');
+ static_assert(d.f() == 'D');
+ constexpr const A &a = (B&)d;
+ constexpr const B &b = d;
+ static_assert(a.f() == 'D');
+ static_assert(b.f() == 'D');
+
+ // FIXME: It is unclear whether this should be permitted.
+ D d_not_constexpr;
+ static_assert(d_not_constexpr.f() == 'D'); // expected-error {{constant expression}} expected-note {{virtual function called on object 'd_not_constexpr' whose dynamic type is not constant}}
+
+ // Check that we apply a proper adjustment for a covariant return type.
+ struct Covariant1 {
+ D d;
+ virtual const A *f() const;
+ };
+ template<typename T>
+ struct Covariant2 : Covariant1 {
+ virtual const T *f() const;
+ };
+ template<typename T>
+ struct Covariant3 : Covariant2<T> {
+ constexpr virtual const D *f() const { return &this->d; }
+ };
+
+ constexpr Covariant3<B> cb;
+ constexpr Covariant3<C> cc;
+
+ constexpr const Covariant1 *cb1 = &cb;
+ constexpr const Covariant2<B> *cb2 = &cb;
+ static_assert(cb1->f()->a == 'A');
+ static_assert(cb1->f() == (B*)&cb.d);
+ static_assert(cb1->f()->f() == 'D');
+ static_assert(cb2->f()->b == 'B');
+ static_assert(cb2->f() == &cb.d);
+ static_assert(cb2->f()->f() == 'D');
+
+ constexpr const Covariant1 *cc1 = &cc;
+ constexpr const Covariant2<C> *cc2 = &cc;
+ static_assert(cc1->f()->a == 'A');
+ static_assert(cc1->f() == (C*)&cc.d);
+ static_assert(cc1->f()->f() == 'D');
+ static_assert(cc2->f()->c == 'C');
+ static_assert(cc2->f() == &cc.d);
+ static_assert(cc2->f()->f() == 'D');
+
+ static_assert(cb.f()->d == 'D');
+ static_assert(cc.f()->d == 'D');
+
+ struct Abstract {
+ constexpr virtual void f() = 0; // expected-note {{declared here}}
+ constexpr Abstract() { do_it(); } // expected-note {{in call to}}
+ constexpr void do_it() { f(); } // expected-note {{pure virtual function 'Virtual::Abstract::f' called}}
+ };
+ struct PureVirtualCall : Abstract { void f(); }; // expected-note {{in call to 'Abstract}}
+ constexpr PureVirtualCall pure_virtual_call; // expected-error {{constant expression}} expected-note {{in call to 'PureVirtualCall}}
+}
OpenPOWER on IntegriCloud