| 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 | |