Files
clang-p2996/clang/test/CXX/except/except.spec/p14.cpp
Richard Smith 5179eb7821 P0136R1, DR1573, DR1645, DR1715, DR1736, DR1903, DR1941, DR1959, DR1991:
Replace inheriting constructors implementation with new approach, voted into
C++ last year as a DR against C++11.

Instead of synthesizing a set of derived class constructors for each inherited
base class constructor, we make the constructors of the base class visible to
constructor lookup in the derived class, using the normal rules for
using-declarations.

For constructors, UsingShadowDecl now has a ConstructorUsingShadowDecl derived
class that tracks the requisite additional information. We create shadow
constructors (not found by name lookup) in the derived class to model the
actual initialization, and have a new expression node,
CXXInheritedCtorInitExpr, to model the initialization of a base class from such
a constructor. (This initialization is special because it performs real perfect
forwarding of arguments.)

In cases where argument forwarding is not possible (for inalloca calls,
variadic calls, and calls with callee parameter cleanup), the shadow inheriting
constructor is not emitted and instead we directly emit the initialization code
into the caller of the inherited constructor.

Note that this new model is not perfectly compatible with the old model in some
corner cases. In particular:
 * if B inherits a private constructor from A, and C uses that constructor to
   construct a B, then we previously required that A befriends B and B
   befriends C, but the new rules require A to befriend C directly, and
 * if a derived class has its own constructors (and so its implicit default
   constructor is suppressed), it may still inherit a default constructor from
   a base class

llvm-svn: 274049
2016-06-28 19:03:57 +00:00

144 lines
4.8 KiB
C++

// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify -std=c++11 %s
struct A { };
struct B { };
struct C { };
// Destructor
struct X0 {
virtual ~X0() throw(A); // expected-note{{overridden virtual function is here}}
};
struct X1 {
virtual ~X1() throw(B); // expected-note{{overridden virtual function is here}}
};
struct X2 : public X0, public X1 { }; // expected-error 2{{exception specification of overriding function is more lax than base version}}
// Copy-assignment operator.
struct CA0 {
CA0 &operator=(const CA0&) throw(A);
};
struct CA1 {
CA1 &operator=(const CA1&) throw(B);
};
struct CA2 : CA0, CA1 { };
void test_CA() {
CA2 &(CA2::*captr1)(const CA2&) throw(A, B) = &CA2::operator=;
CA2 &(CA2::*captr2)(const CA2&) throw(A, B, C) = &CA2::operator=;
CA2 &(CA2::*captr3)(const CA2&) throw(A) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
CA2 &(CA2::*captr4)(const CA2&) throw(B) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
}
// In-class member initializers.
struct IC0 {
int inClassInit = 0;
};
struct IC1 {
int inClassInit = (throw B(), 0);
};
// FIXME: the exception specification on the default constructor is wrong:
// we cannot currently compute the set of thrown types.
static_assert(noexcept(IC0()), "IC0() does not throw");
static_assert(!noexcept(IC1()), "IC1() throws");
namespace PR13381 {
struct NoThrowMove {
NoThrowMove(const NoThrowMove &);
NoThrowMove(NoThrowMove &&) noexcept;
NoThrowMove &operator=(const NoThrowMove &) const;
NoThrowMove &operator=(NoThrowMove &&) const noexcept;
};
struct NoThrowMoveOnly {
NoThrowMoveOnly(NoThrowMoveOnly &&) noexcept;
NoThrowMoveOnly &operator=(NoThrowMoveOnly &&) noexcept;
};
struct X {
const NoThrowMove a;
NoThrowMoveOnly b;
static X val();
static X &ref();
};
// These both perform a move, but that copy might throw, because it calls
// NoThrowMove's copy constructor (because PR13381::a is const).
static_assert(!noexcept(X(X::val())), "");
static_assert(!noexcept(X::ref() = X::val()), "");
}
namespace PR14141 {
// Part of DR1351: the implicit exception-specification is noexcept(false) if
// the set of potential exceptions of the special member function contains
// "any". Hence it is compatible with noexcept(false).
struct ThrowingBase {
ThrowingBase() noexcept(false);
ThrowingBase(const ThrowingBase&) noexcept(false);
ThrowingBase(ThrowingBase&&) noexcept(false);
ThrowingBase &operator=(const ThrowingBase&) noexcept(false);
ThrowingBase &operator=(ThrowingBase&&) noexcept(false);
~ThrowingBase() noexcept(false);
};
struct Derived : ThrowingBase {
Derived() noexcept(false) = default;
Derived(const Derived&) noexcept(false) = default;
Derived(Derived&&) noexcept(false) = default;
Derived &operator=(const Derived&) noexcept(false) = default;
Derived &operator=(Derived&&) noexcept(false) = default;
~Derived() noexcept(false) = default;
};
struct Derived2 : ThrowingBase {
Derived2() = default;
Derived2(const Derived2&) = default;
Derived2(Derived2&&) = default;
Derived2 &operator=(const Derived2&) = default;
Derived2 &operator=(Derived2&&) = default;
~Derived2() = default;
};
struct Derived3 : ThrowingBase {
Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
Derived3(const Derived3&) noexcept(true) = default; // expected-error {{does not match the calculated}}
Derived3(Derived3&&) noexcept(true) = default; // expected-error {{does not match the calculated}}
Derived3 &operator=(const Derived3&) noexcept(true) = default; // expected-error {{does not match the calculated}}
Derived3 &operator=(Derived3&&) noexcept(true) = default; // expected-error {{does not match the calculated}}
~Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
};
}
namespace rdar13017229 {
struct Base {
virtual ~Base() {}
};
struct Derived : Base {
virtual ~Derived();
Typo foo(); // expected-error{{unknown type name 'Typo'}}
};
}
namespace InhCtor {
template<int> struct X {};
struct Base {
Base(X<0>) noexcept(true);
Base(X<1>) noexcept(false);
Base(X<2>) throw(X<2>);
template<typename T> Base(T) throw(T);
};
template<typename T> struct Throw {
Throw() throw(T);
};
struct Derived1 : Base, X<5> {
using Base::Base;
int n;
};
struct Derived2 : Base, Throw<X<3>> {
using Base::Base;
};
struct Derived3 : Base {
using Base::Base;
Throw<X<4>> x;
};
static_assert(noexcept(Derived1(X<0>())), "");
static_assert(!noexcept(Derived1(X<1>())), "");
static_assert(!noexcept(Derived1(X<2>())), "");
static_assert(!noexcept(Derived2(X<0>())), "");
static_assert(!noexcept(Derived3(X<0>())), "");
}