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)18 template <typename T> typename remove_reference<T>::type &&move(T &&arg) {
19   return static_cast<typename remove_reference<T>::type &&>(arg);
20 }
21 
CreateException()22 logic_error CreateException() { return logic_error("created"); }
23 
testThrowFunc()24 void 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)51 void throwReferenceFunc(logic_error &ref) { throw ref; }
52 
catchByPointer()53 void 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()61 void 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()69 void catchByReference() {
70   try {
71     testThrowFunc();
72   } catch (logic_error &e) {
73   }
74 }
75 
catchByConstReference()76 void catchByConstReference() {
77   try {
78     testThrowFunc();
79   } catch (const logic_error &e) {
80   }
81 }
82 
catchTypedef()83 void 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()91 void catchAll() {
92   try {
93     testThrowFunc();
94   } catch (...) {
95   }
96 }
97 
catchLiteral()98 void 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()111 void 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()125 void catchTrivial() {
126   try {
127     testThrowFunc();
128   } catch (TrivialType) {
129   }
130 }
131 
132 typedef logic_error &fine;
additionalTests()133 void 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()152 void 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