1 // RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -fcxx-exceptions 2 3 4 class logic_error { 5 public: logic_error(const char * message)6 logic_error(const char *message) {} 7 }; 8 9 typedef logic_error *logic_ptr; 10 typedef logic_ptr logic_double_typedef; 11 12 int lastException; 13 14 template <class T> struct remove_reference { typedef T type; }; 15 template <class T> struct remove_reference<T &> { typedef T type; }; 16 template <class T> struct remove_reference<T &&> { typedef T type; }; 17 move(T && arg)18template <typename T> typename remove_reference<T>::type &&move(T &&arg) { 19 return static_cast<typename remove_reference<T>::type &&>(arg); 20 } 21 CreateException()22logic_error CreateException() { return logic_error("created"); } 23 testThrowFunc()24void testThrowFunc() { 25 throw new logic_error("by pointer"); 26 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference] 27 logic_ptr tmp = new logic_error("by pointer"); 28 throw tmp; 29 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] 30 // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference] 31 throw logic_error("by value"); 32 auto *literal = "test"; 33 throw logic_error(literal); 34 throw "test string literal"; 35 throw L"throw wide string literal"; 36 const char *characters = 0; 37 throw characters; 38 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] 39 // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference] 40 logic_error lvalue("lvalue"); 41 throw lvalue; 42 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] 43 44 throw move(lvalue); 45 int &ex = lastException; 46 throw ex; 47 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] 48 throw CreateException(); 49 } 50 throwReferenceFunc(logic_error & ref)51void throwReferenceFunc(logic_error &ref) { throw ref; } 52 catchByPointer()53void catchByPointer() { 54 try { 55 testThrowFunc(); 56 } catch (logic_error *e) { 57 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference] 58 } 59 } 60 catchByValue()61void catchByValue() { 62 try { 63 testThrowFunc(); 64 } catch (logic_error e) { 65 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches by value; should catch by reference instead [misc-throw-by-value-catch-by-reference] 66 } 67 } 68 catchByReference()69void catchByReference() { 70 try { 71 testThrowFunc(); 72 } catch (logic_error &e) { 73 } 74 } 75 catchByConstReference()76void catchByConstReference() { 77 try { 78 testThrowFunc(); 79 } catch (const logic_error &e) { 80 } 81 } 82 catchTypedef()83void catchTypedef() { 84 try { 85 testThrowFunc(); 86 } catch (logic_ptr) { 87 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference] 88 } 89 } 90 catchAll()91void catchAll() { 92 try { 93 testThrowFunc(); 94 } catch (...) { 95 } 96 } 97 catchLiteral()98void catchLiteral() { 99 try { 100 testThrowFunc(); 101 } catch (const char *) { 102 } catch (const wchar_t *) { 103 // disabled for now until it is clear 104 // how to enable them in the test 105 //} catch (const char16_t*) { 106 //} catch (const char32_t*) { 107 } 108 } 109 110 // catching fundamentals should not warn catchFundamental()111void catchFundamental() { 112 try { 113 testThrowFunc(); 114 } catch (int) { 115 } catch (double) { 116 } catch (unsigned long) { 117 } 118 } 119 120 struct TrivialType { 121 double x; 122 double y; 123 }; 124 catchTrivial()125void catchTrivial() { 126 try { 127 testThrowFunc(); 128 } catch (TrivialType) { 129 } 130 } 131 132 typedef logic_error &fine; additionalTests()133void additionalTests() { 134 try { 135 } catch (int i) { // ok 136 throw i; // ok 137 } catch (fine e) { // ok 138 throw e; // ok 139 } catch (logic_error *e) { 140 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference] 141 throw e; // ok, despite throwing a pointer 142 } catch (...) { // ok 143 throw; // ok 144 } 145 } 146 147 struct S {}; 148 149 S &returnByReference(); 150 S returnByValue(); 151 f()152void f() { 153 throw returnByReference(); // Should diagnose 154 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] 155 throw returnByValue(); // Should not diagnose 156 } 157