1 | // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s |
2 | struct A {}; |
3 | |
4 | enum Foo { F }; |
5 | typedef Foo Bar; // expected-note{{type 'Bar' (aka 'Foo') is declared here}} |
6 | |
7 | typedef int Integer; |
8 | typedef double Double; |
9 | |
10 | void g(); |
11 | |
12 | namespace N { |
13 | typedef Foo Wibble; |
14 | typedef int OtherInteger; |
15 | } |
16 | |
17 | template <typename T> |
18 | void cv_test(const volatile T* cvt) { |
19 | cvt->T::~T(); // no-warning |
20 | } |
21 | |
22 | void f(A* a, Foo *f, int *i, double *d, int ii) { |
23 | a->~A(); |
24 | a->A::~A(); |
25 | |
26 | a->~foo(); // expected-error{{identifier 'foo' in object destruction expression does not name a type}} |
27 | |
28 | a->~Bar(); // expected-error{{destructor type 'Bar' (aka 'Foo') in object destruction expression does not match the type 'A' of the object being destroyed}} |
29 | |
30 | f->~Bar(); |
31 | f->~Foo(); |
32 | i->~Bar(); // expected-error{{does not match}} |
33 | |
34 | g().~Bar(); // expected-error{{non-scalar}} |
35 | |
36 | f->::~Bar(); |
37 | f->N::~Wibble(); // FIXME: technically, Wibble isn't a class-name |
38 | |
39 | f->::~Bar(17, 42); // expected-error{{cannot have any arguments}} |
40 | |
41 | i->~Integer(); |
42 | i->Integer::~Integer(); |
43 | i->N::~OtherInteger(); |
44 | i->N::OtherInteger::~OtherInteger(); |
45 | i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}} |
46 | i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}} |
47 | i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}} |
48 | |
49 | ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; did you mean to use '.'?}} |
50 | ii.~Integer(); |
51 | |
52 | cv_test(a); |
53 | cv_test(f); |
54 | cv_test(i); |
55 | cv_test(d); |
56 | } |
57 | |
58 | |
59 | typedef int Integer; |
60 | |
61 | void destroy_without_call(int *ip) { |
62 | ip->~Integer; // expected-error{{reference to pseudo-destructor must be called}} |
63 | } |
64 | |
65 | void paren_destroy_with_call(int *ip) { |
66 | (ip->~Integer)(); |
67 | } |
68 | |
69 | // PR5530 |
70 | namespace N1 { |
71 | class X0 { }; |
72 | } |
73 | |
74 | void test_X0(N1::X0 &x0) { |
75 | x0.~X0(); |
76 | } |
77 | |
78 | namespace PR11339 { |
79 | template<class T> |
80 | void destroy(T* p) { |
81 | p->~T(); // ok |
82 | p->~oops(); // expected-error{{expected the class name after '~' to name a destructor}} |
83 | } |
84 | |
85 | template void destroy(int*); // expected-note{{in instantiation of function template specialization}} |
86 | } |
87 | |
88 | template<typename T> using Id = T; |
89 | void AliasTemplate(int *p) { |
90 | p->~Id<int>(); |
91 | } |
92 | |
93 | namespace dotPointerAccess { |
94 | struct Base { |
95 | virtual ~Base() {} |
96 | }; |
97 | |
98 | struct Derived : Base { |
99 | ~Derived() {} |
100 | }; |
101 | |
102 | void test() { |
103 | Derived d; |
104 | static_cast<Base *>(&d).~Base(); // expected-error {{member reference type 'dotPointerAccess::Base *' is a pointer; did you mean to use '->'}} |
105 | d->~Derived(); // expected-error {{member reference type 'dotPointerAccess::Derived' is not a pointer; did you mean to use '.'}} |
106 | } |
107 | |
108 | typedef Derived *Foo; |
109 | |
110 | void test2(Foo d) { |
111 | d.~Foo(); // This is ok |
112 | d.~Derived(); // expected-error {{member reference type 'dotPointerAccess::Foo' (aka 'dotPointerAccess::Derived *') is a pointer; did you mean to use '->'}} |
113 | } |
114 | } |
115 | |