|  | // RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -std=c++11 -fcxx-exceptions | 
|  |  | 
|  |  | 
|  | class logic_error { | 
|  | public: | 
|  | logic_error(const char *message) {} | 
|  | }; | 
|  |  | 
|  | typedef logic_error *logic_ptr; | 
|  | typedef logic_ptr logic_double_typedef; | 
|  |  | 
|  | int lastException; | 
|  |  | 
|  | template <class T> struct remove_reference { typedef T type; }; | 
|  | template <class T> struct remove_reference<T &> { typedef T type; }; | 
|  | template <class T> struct remove_reference<T &&> { typedef T type; }; | 
|  |  | 
|  | template <typename T> typename remove_reference<T>::type &&move(T &&arg) { | 
|  | return static_cast<typename remove_reference<T>::type &&>(arg); | 
|  | } | 
|  |  | 
|  | logic_error CreateException() { return logic_error("created"); } | 
|  |  | 
|  | void testThrowFunc() { | 
|  | throw new logic_error("by pointer"); | 
|  | // 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] | 
|  | logic_ptr tmp = new logic_error("by pointer"); | 
|  | throw tmp; | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] | 
|  | // 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] | 
|  | throw logic_error("by value"); | 
|  | auto *literal = "test"; | 
|  | throw logic_error(literal); | 
|  | throw "test string literal"; | 
|  | throw L"throw wide string literal"; | 
|  | const char *characters = 0; | 
|  | throw characters; | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] | 
|  | // 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] | 
|  | logic_error lvalue("lvalue"); | 
|  | throw lvalue; | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] | 
|  |  | 
|  | throw move(lvalue); | 
|  | int &ex = lastException; | 
|  | throw ex; | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] | 
|  | throw CreateException(); | 
|  | } | 
|  |  | 
|  | void throwReferenceFunc(logic_error &ref) { throw ref; } | 
|  |  | 
|  | void catchByPointer() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (logic_error *e) { | 
|  | // 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] | 
|  | } | 
|  | } | 
|  |  | 
|  | void catchByValue() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (logic_error e) { | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches by value; should catch by reference instead [misc-throw-by-value-catch-by-reference] | 
|  | } | 
|  | } | 
|  |  | 
|  | void catchByReference() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (logic_error &e) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void catchByConstReference() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (const logic_error &e) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void catchTypedef() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (logic_ptr) { | 
|  | // 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] | 
|  | } | 
|  | } | 
|  |  | 
|  | void catchAll() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (...) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void catchLiteral() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (const char *) { | 
|  | } catch (const wchar_t *) { | 
|  | // disabled for now until it is clear | 
|  | // how to enable them in the test | 
|  | //} catch (const char16_t*) { | 
|  | //} catch (const char32_t*) { | 
|  | } | 
|  | } | 
|  |  | 
|  | // catching fundamentals should not warn | 
|  | void catchFundamental() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (int) { | 
|  | } catch (double) { | 
|  | } catch (unsigned long) { | 
|  | } | 
|  | } | 
|  |  | 
|  | struct TrivialType { | 
|  | double x; | 
|  | double y; | 
|  | }; | 
|  |  | 
|  | void catchTrivial() { | 
|  | try { | 
|  | testThrowFunc(); | 
|  | } catch (TrivialType) { | 
|  | } | 
|  | } | 
|  |  | 
|  | typedef logic_error &fine; | 
|  | void additionalTests() { | 
|  | try { | 
|  | } catch (int i) {  // ok | 
|  | throw i;         // ok | 
|  | } catch (fine e) { // ok | 
|  | throw e;         // ok | 
|  | } catch (logic_error *e) { | 
|  | // 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] | 
|  | throw e;      // ok, despite throwing a pointer | 
|  | } catch (...) { // ok | 
|  | throw;        // ok | 
|  | } | 
|  | } | 
|  |  | 
|  | struct S {}; | 
|  |  | 
|  | S &returnByReference(); | 
|  | S returnByValue(); | 
|  |  | 
|  | void f() { | 
|  | throw returnByReference(); // Should diagnose | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference] | 
|  | throw returnByValue(); // Should not diagnose | 
|  | } |