summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/CXX/drs/dr16xx.cpp118
-rw-r--r--clang/test/CXX/drs/dr21xx.cpp24
-rw-r--r--clang/test/CodeGenCXX/constructors.cpp56
-rw-r--r--clang/test/CodeGenCXX/implicit-exception-spec.cpp22
-rw-r--r--clang/test/SemaCXX/implicit-exception-spec.cpp58
5 files changed, 277 insertions, 1 deletions
diff --git a/clang/test/CXX/drs/dr16xx.cpp b/clang/test/CXX/drs/dr16xx.cpp
index c9f084db73a..08ae92570ce 100644
--- a/clang/test/CXX/drs/dr16xx.cpp
+++ b/clang/test/CXX/drs/dr16xx.cpp
@@ -3,6 +3,13 @@
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+namespace dr1611 { // dr1611: dup 1658
+ struct A { A(int); };
+ struct B : virtual A { virtual void f() = 0; };
+ struct C : B { C() : A(0) {} void f(); };
+ C c;
+}
+
namespace dr1684 { // dr1684: 3.6
#if __cplusplus >= 201103L
struct NonLiteral { // expected-note {{because}}
@@ -101,3 +108,114 @@ namespace dr1653 { // dr1653: 4 c++17
b -= 1; // ok
}
}
+
+namespace dr1658 { // dr1658: 5
+ namespace DefCtor {
+ class A { A(); }; // expected-note 0-2{{here}}
+ class B { ~B(); }; // expected-note 0-2{{here}}
+
+ // The stars align! An abstract class does not construct its virtual bases.
+ struct C : virtual A { C(); virtual void foo() = 0; };
+ C::C() = default; // ok, not deleted, expected-error 0-1{{extension}}
+ struct D : virtual B { D(); virtual void foo() = 0; };
+ D::D() = default; // ok, not deleted, expected-error 0-1{{extension}}
+
+ // In all other cases, we are not so lucky.
+ struct E : A { E(); virtual void foo() = 0; };
+#if __cplusplus < 201103L
+ E::E() = default; // expected-error {{private default constructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ E::E() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible default constructor}}
+#endif
+ struct F : virtual A { F(); };
+#if __cplusplus < 201103L
+ F::F() = default; // expected-error {{private default constructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ F::F() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible default constructor}}
+#endif
+
+ struct G : B { G(); virtual void foo() = 0; };
+#if __cplusplus < 201103L
+ G::G() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ G::G() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ struct H : virtual B { H(); };
+#if __cplusplus < 201103L
+ H::H() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ H::H() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ }
+
+ namespace Dtor {
+ class B { ~B(); }; // expected-note 0-2{{here}}
+
+ struct D : virtual B { ~D(); virtual void foo() = 0; };
+ D::~D() = default; // ok, not deleted, expected-error 0-1{{extension}}
+
+ struct G : B { ~G(); virtual void foo() = 0; };
+#if __cplusplus < 201103L
+ G::~G() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ G::~G() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ struct H : virtual B { ~H(); };
+#if __cplusplus < 201103L
+ H::~H() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ H::~H() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ }
+
+ namespace MemInit {
+ struct A { A(int); }; // expected-note {{here}}
+ struct B : virtual A {
+ B() {}
+ virtual void f() = 0;
+ };
+ struct C : virtual A {
+ C() {} // expected-error {{must explicitly initialize}}
+ };
+ }
+
+ namespace CopyCtorParamType {
+ struct A { A(A&); };
+ struct B : virtual A { virtual void f() = 0; };
+ struct C : virtual A { virtual void f(); };
+ struct D : A { virtual void f() = 0; };
+
+ struct X {
+ friend B::B(const B&) throw();
+ friend C::C(C&);
+ friend D::D(D&);
+ };
+ }
+
+ namespace CopyCtor {
+ class A { A(const A&); A(A&&); }; // expected-note 0-4{{here}} expected-error 0-1{{extension}}
+
+ struct C : virtual A { C(const C&); C(C&&); virtual void foo() = 0; }; // expected-error 0-1{{extension}}
+ C::C(const C&) = default; // expected-error 0-1{{extension}}
+ C::C(C&&) = default; // expected-error 0-2{{extension}}
+
+ struct E : A { E(const E&); E(E&&); virtual void foo() = 0; }; // expected-error 0-1{{extension}}
+#if __cplusplus < 201103L
+ E::E(const E&) = default; // expected-error {{private copy constructor}} expected-error {{extension}} expected-note {{here}}
+ E::E(E&&) = default; // expected-error {{private move constructor}} expected-error 2{{extension}} expected-note {{here}}
+#else
+ E::E(const E&) = default; // expected-error {{would delete}} expected-note@-5{{inaccessible copy constructor}}
+ E::E(E&&) = default; // expected-error {{would delete}} expected-note@-6{{inaccessible move constructor}}
+#endif
+ struct F : virtual A { F(const F&); F(F&&); }; // expected-error 0-1{{extension}}
+#if __cplusplus < 201103L
+ F::F(const F&) = default; // expected-error {{private copy constructor}} expected-error {{extension}} expected-note {{here}}
+ F::F(F&&) = default; // expected-error {{private move constructor}} expected-error 2{{extension}} expected-note {{here}}
+#else
+ F::F(const F&) = default; // expected-error {{would delete}} expected-note@-5{{inaccessible copy constructor}}
+ F::F(F&&) = default; // expected-error {{would delete}} expected-note@-6{{inaccessible move constructor}}
+#endif
+ }
+
+ // assignment case is superseded by dr2180
+}
diff --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp
new file mode 100644
index 00000000000..78fc0bec40b
--- /dev/null
+++ b/clang/test/CXX/drs/dr21xx.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace dr2180 { // dr2180: yes
+ class A {
+ A &operator=(const A &); // expected-note 0-2{{here}}
+ A &operator=(A &&); // expected-note 0-2{{here}} expected-error 0-1{{extension}}
+ };
+
+ struct B : virtual A {
+ B &operator=(const B &);
+ B &operator=(B &&); // expected-error 0-1{{extension}}
+ virtual void foo() = 0;
+ };
+#if __cplusplus < 201103L
+ B &B::operator=(const B&) = default; // expected-error {{private member}} expected-error {{extension}} expected-note {{here}}
+ B &B::operator=(B&&) = default; // expected-error {{private member}} expected-error 2{{extension}} expected-note {{here}}
+#else
+ B &B::operator=(const B&) = default; // expected-error {{would delete}} expected-note@-9{{inaccessible copy assignment}}
+ B &B::operator=(B&&) = default; // expected-error {{would delete}} expected-note@-10{{inaccessible move assignment}}
+#endif
+}
diff --git a/clang/test/CodeGenCXX/constructors.cpp b/clang/test/CodeGenCXX/constructors.cpp
index ecbe5bb45b6..a8981403834 100644
--- a/clang/test/CodeGenCXX/constructors.cpp
+++ b/clang/test/CodeGenCXX/constructors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s --implicit-check-not=should_not_appear_in_output
struct Member { int x; Member(); Member(int); Member(const Member &); };
struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); };
@@ -109,3 +109,57 @@ namespace test1 {
// CHECK: [[THIS:%.*]] = load [[B:%.*]]*, [[B:%.*]]**
// CHECK-NEXT: ret void
}
+
+// Ensure that we
+// a) emit the ABI-required but useless complete object and deleting destructor
+// symbols for an abstract class, and
+// b) do *not* emit references to virtual base destructors for an abstract class
+//
+// Our approach to this is to give these functions a body that simply traps.
+//
+// FIXME: We should ideally not create these symbols at all, but Clang can
+// actually generate references to them in other TUs in some cases, so we can't
+// stop emitting them without breaking ABI. See:
+//
+// https://github.com/itanium-cxx-abi/cxx-abi/issues/10
+namespace abstract {
+ // Note, the destructor of this class is not instantiated here.
+ template<typename T> struct should_not_appear_in_output {
+ ~should_not_appear_in_output() { int arr[-(int)sizeof(T)]; }
+ };
+
+ struct X { ~X(); };
+
+ struct A : virtual should_not_appear_in_output<int>, X {
+ virtual ~A() = 0;
+ };
+
+ // CHECK-LABEL: define void @_ZN8abstract1AD2Ev(
+ // CHECK: call {{.*}}@_ZN8abstract1XD2Ev(
+ // CHECK: ret
+
+ // CHECK-LABEL: define void @_ZN8abstract1AD1Ev(
+ // CHECK: call {{.*}}@llvm.trap(
+ // CHECK: unreachable
+
+ // CHECK-LABEL: define void @_ZN8abstract1AD0Ev(
+ // CHECK: call {{.*}}@llvm.trap(
+ // CHECK: unreachable
+ A::~A() {}
+
+ struct B : virtual should_not_appear_in_output<int>, X {
+ virtual void f() = 0;
+ ~B();
+ };
+
+ // CHECK-LABEL: define void @_ZN8abstract1BD2Ev(
+ // CHECK: call {{.*}}@_ZN8abstract1XD2Ev(
+ // CHECK: ret
+
+ // CHECK-LABEL: define void @_ZN8abstract1BD1Ev(
+ // CHECK: call {{.*}}@llvm.trap(
+ // CHECK: unreachable
+
+ // CHECK-NOT: @_ZN8abstract1BD0Ev(
+ B::~B() {}
+}
diff --git a/clang/test/CodeGenCXX/implicit-exception-spec.cpp b/clang/test/CodeGenCXX/implicit-exception-spec.cpp
new file mode 100644
index 00000000000..cf363bd685a
--- /dev/null
+++ b/clang/test/CodeGenCXX/implicit-exception-spec.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK %s
+
+struct A {
+ A();
+ A(const A&);
+ A(A&&);
+};
+struct B : virtual A {
+ virtual void f() = 0;
+};
+struct C : B {
+ void f();
+};
+
+// CHECK-DAG: define {{.*}} @_ZN1BC2Ev({{.*}} #[[NOUNWIND:[0-9]*]]
+C c1;
+// CHECK-DAG: define {{.*}} @_ZN1BC2ERKS_({{.*}} #[[NOUNWIND]]
+C c2(c1);
+// CHECK-DAG: define {{.*}} @_ZN1BC2EOS_({{.*}} #[[NOUNWIND]]
+C c3(static_cast<C&&>(c1));
+
+// CHECK-DAG: #[[NOUNWIND]] = {{{.*}} nounwind
diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp
index fc86d1810ba..f400c222de8 100644
--- a/clang/test/SemaCXX/implicit-exception-spec.cpp
+++ b/clang/test/SemaCXX/implicit-exception-spec.cpp
@@ -92,3 +92,61 @@ namespace ImplicitDtorExceptionSpec {
} e;
};
}
+
+struct nothrow_t {} nothrow;
+void *operator new(decltype(sizeof(0)), nothrow_t) noexcept;
+
+namespace PotentiallyConstructed {
+ template<bool NE> struct A {
+ A() noexcept(NE);
+ A(const A&) noexcept(NE);
+ A(A&&) noexcept(NE);
+ A &operator=(const A&) noexcept(NE);
+ A &operator=(A&&) noexcept(NE);
+ ~A() noexcept(NE);
+ };
+
+ template<bool NE> struct B : virtual A<NE> {};
+
+ template<bool NE> struct C : virtual A<NE> {
+ virtual void f() = 0; // expected-note 2{{unimplemented}}
+ };
+
+ template<bool NE> struct D final : C<NE> {
+ void f();
+ };
+
+ template<typename T, bool A, bool B, bool C, bool D, bool E, bool F> void check() {
+ T *p = nullptr;
+ T &a = *p;
+ static_assert(noexcept(a = a) == D, "");
+ static_assert(noexcept(a = static_cast<T&&>(a)) == E, "");
+ static_assert(noexcept(delete &a) == F, ""); // expected-warning 2{{abstract}}
+
+ // These are last because the first failure here causes instantiation to bail out.
+ static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}}
+ static_assert(noexcept(new (nothrow) T(a)) == B, "");
+ static_assert(noexcept(new (nothrow) T(static_cast<T&&>(a))) == C, "");
+ }
+
+ template void check<A<false>, 0, 0, 0, 0, 0, 0>();
+ template void check<A<true >, 1, 1, 1, 1, 1, 1>();
+ template void check<B<false>, 0, 0, 0, 0, 0, 0>();
+ template void check<B<true >, 1, 1, 1, 1, 1, 1>();
+ template void check<C<false>, 1, 1, 1, 0, 0, 0>(); // expected-note {{instantiation}}
+ template void check<C<true >, 1, 1, 1, 1, 1, 1>(); // expected-note {{instantiation}}
+ template void check<D<false>, 0, 0, 0, 0, 0, 0>();
+ template void check<D<true >, 1, 1, 1, 1, 1, 1>();
+
+ // ... the above trick doesn't work for this case...
+ struct Cfalse : virtual A<false> {
+ virtual void f() = 0;
+
+ Cfalse() noexcept;
+ Cfalse(const Cfalse&) noexcept;
+ Cfalse(Cfalse&&) noexcept;
+ };
+ Cfalse::Cfalse() noexcept = default;
+ Cfalse::Cfalse(const Cfalse&) noexcept = default;
+ Cfalse::Cfalse(Cfalse&&) noexcept = default;
+}
OpenPOWER on IntegriCloud