1 | // This is a test for an egregious hack in Clang that works around |
2 | // an issue with GCC's <utility> implementation. std::pair::swap |
3 | // has an exception specification that makes an unqualified call to |
4 | // swap. This is invalid, because it ends up calling itself with |
5 | // the wrong number of arguments. |
6 | // |
7 | // The same problem afflicts a bunch of other class templates. Those |
8 | // affected are array, pair, priority_queue, stack, and queue. |
9 | |
10 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array |
11 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DPR28423 |
12 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=pair |
13 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=priority_queue |
14 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=stack |
15 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=queue |
16 | // |
17 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DNAMESPACE=__debug |
18 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DNAMESPACE=__profile |
19 | |
20 | // MSVC's standard library uses a very similar pattern that relies on delayed |
21 | // parsing of exception specifications. |
22 | // |
23 | // RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DMSVC |
24 | |
25 | #ifdef BE_THE_HEADER |
26 | |
27 | #pragma GCC system_header |
28 | #ifdef PR28423 |
29 | using namespace std; |
30 | #endif |
31 | |
32 | namespace std { |
33 | template<typename T> void swap(T &, T &); |
34 | template<typename T> void do_swap(T &a, T &b) noexcept(noexcept(swap(a, b))) { |
35 | swap(a, b); |
36 | } |
37 | |
38 | #ifdef NAMESPACE |
39 | namespace NAMESPACE { |
40 | #define STD_CLASS std::NAMESPACE::CLASS |
41 | #else |
42 | #define STD_CLASS std::CLASS |
43 | #endif |
44 | |
45 | template<typename A, typename B> struct CLASS { |
46 | #ifdef MSVC |
47 | void swap(CLASS &other) noexcept(noexcept(do_swap(member, other.member))); |
48 | #endif |
49 | A member; |
50 | #ifndef MSVC |
51 | void swap(CLASS &other) noexcept(noexcept(swap(member, other.member))); |
52 | #endif |
53 | }; |
54 | |
55 | // template<typename T> void do_swap(T &, T &); |
56 | // template<typename A> struct vector { |
57 | // void swap(vector &other) noexcept(noexcept(do_swap(member, other.member))); |
58 | // A member; |
59 | // }; |
60 | |
61 | #ifdef NAMESPACE |
62 | } |
63 | #endif |
64 | } |
65 | |
66 | #else |
67 | |
68 | #define BE_THE_HEADER |
69 | #include __FILE__ |
70 | |
71 | struct X {}; |
72 | using PX = STD_CLASS<X, X>; |
73 | using PI = STD_CLASS<int, int>; |
74 | void swap(X &, X &) noexcept; |
75 | PX px; |
76 | PI pi; |
77 | |
78 | static_assert(noexcept(px.swap(px)), ""); |
79 | static_assert(!noexcept(pi.swap(pi)), ""); |
80 | |
81 | namespace sad { |
82 | template<typename T> void swap(T &, T &); |
83 | |
84 | template<typename A, typename B> struct CLASS { |
85 | void swap(CLASS &other) noexcept(noexcept(swap(*this, other))); // expected-error {{too many arguments}} expected-note {{declared here}} |
86 | // expected-error@-1{{uses itself}} expected-note@-1{{in instantiation of}} |
87 | }; |
88 | |
89 | CLASS<int, int> pi; |
90 | |
91 | static_assert(!noexcept(pi.swap(pi)), ""); // expected-note 2{{in instantiation of exception specification for 'swap'}} |
92 | } |
93 | |
94 | #endif |
95 | |