1 // RUN: %clang_cc1 -verify -fsyntax-only -fms-extensions -fcxx-exceptions -fopenmp -triple x86_64-linux %s 2 3 int ReturnsInt1(); 4 int Func1() { 5 [[clang::musttail]] ReturnsInt1(); // expected-error {{'musttail' attribute only applies to return statements}} 6 [[clang::musttail(1, 2)]] return ReturnsInt1(); // expected-error {{'musttail' attribute takes no arguments}} 7 [[clang::musttail]] return 5; // expected-error {{'musttail' attribute requires that the return value is the result of a function call}} 8 [[clang::musttail]] return ReturnsInt1(); 9 } 10 11 void NoFunctionCall() { 12 [[clang::musttail]] return; // expected-error {{'musttail' attribute requires that the return value is the result of a function call}} 13 } 14 15 [[clang::musttail]] static int int_val = ReturnsInt1(); // expected-error {{'musttail' attribute cannot be applied to a declaration}} 16 17 void NoParams(); // expected-note {{target function has different number of parameters (expected 1 but has 0)}} 18 void TestParamArityMismatch(int x) { 19 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 20 return NoParams(); // expected-error {{cannot perform a tail call to function 'NoParams' because its signature is incompatible with the calling function}} 21 } 22 23 void LongParam(long x); // expected-note {{target function has type mismatch at 1st parameter (expected 'long' but has 'int')}} 24 void TestParamTypeMismatch(int x) { 25 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 26 return LongParam(x); // expected-error {{cannot perform a tail call to function 'LongParam' because its signature is incompatible with the calling function}} 27 } 28 29 long ReturnsLong(); // expected-note {{target function has different return type ('int' expected but has 'long')}} 30 int TestReturnTypeMismatch() { 31 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 32 return ReturnsLong(); // expected-error {{cannot perform a tail call to function 'ReturnsLong' because its signature is incompatible with the calling function}} 33 } 34 35 struct Struct1 { 36 void MemberFunction(); // expected-note {{'MemberFunction' declared here}} 37 }; 38 void TestNonMemberToMember() { 39 Struct1 st; 40 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 41 return st.MemberFunction(); // expected-error {{non-member function cannot perform a tail call to non-static member function 'MemberFunction'}} 42 } 43 44 void ReturnsVoid(); // expected-note {{'ReturnsVoid' declared here}} 45 struct Struct2 { 46 void TestMemberToNonMember() { 47 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 48 return ReturnsVoid(); // expected-error{{non-static member function cannot perform a tail call to non-member function 'ReturnsVoid'}} 49 } 50 }; 51 52 class HasNonTrivialDestructor { 53 public: 54 ~HasNonTrivialDestructor() {} 55 int ReturnsInt(); 56 }; 57 58 void ReturnsVoid2(); 59 void TestNonTrivialDestructorInScope() { 60 HasNonTrivialDestructor foo; // expected-note {{jump exits scope of variable with non-trivial destructor}} 61 [[clang::musttail]] return ReturnsVoid(); // expected-error {{cannot perform a tail call from this return statement}} 62 } 63 64 int NonTrivialParam(HasNonTrivialDestructor x); 65 int TestNonTrivialParam(HasNonTrivialDestructor x) { 66 [[clang::musttail]] return NonTrivialParam(x); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}} 67 } 68 69 HasNonTrivialDestructor ReturnsNonTrivialValue(); 70 HasNonTrivialDestructor TestReturnsNonTrivialValue() { 71 // FIXME: the diagnostic cannot currently distinguish between needing to run a 72 // destructor for the return value and needing to run a destructor for some 73 // other temporary created in the return statement. 74 [[clang::musttail]] return (ReturnsNonTrivialValue()); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}} 75 } 76 77 HasNonTrivialDestructor TestReturnsNonTrivialNonFunctionCall() { 78 [[clang::musttail]] return HasNonTrivialDestructor(); // expected-error {{'musttail' attribute requires that the return value is the result of a function call}} 79 } 80 81 struct UsesPointerToMember { 82 void (UsesPointerToMember::*p_mem)(); // expected-note {{'p_mem' declared here}} 83 }; 84 void TestUsesPointerToMember(UsesPointerToMember *foo) { 85 // "this" pointer cannot double as first parameter. 86 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 87 return (foo->*(foo->p_mem))(); // expected-error {{non-member function cannot perform a tail call to pointer-to-member function 'p_mem'}} 88 } 89 90 void ReturnsVoid2(); 91 void TestNestedClass() { 92 HasNonTrivialDestructor foo; 93 class Nested { 94 __attribute__((noinline)) static void NestedMethod() { 95 // Outer non-trivial destructor does not affect nested class. 96 [[clang::musttail]] return ReturnsVoid2(); 97 } 98 }; 99 } 100 101 template <class T> 102 T TemplateFunc(T x) { // expected-note{{target function has different return type ('long' expected but has 'int')}} 103 return x ? 5 : 10; 104 } 105 int OkTemplateFunc(int x) { 106 [[clang::musttail]] return TemplateFunc<int>(x); 107 } 108 template <class T> 109 T BadTemplateFunc(T x) { 110 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 111 return TemplateFunc<int>(x); // expected-error {{cannot perform a tail call to function 'TemplateFunc' because its signature is incompatible with the calling function}} 112 } 113 long TestBadTemplateFunc(long x) { 114 return BadTemplateFunc<long>(x); // expected-note {{in instantiation of}} 115 } 116 117 void IntParam(int x); 118 void TestVLA(int x) { 119 HasNonTrivialDestructor vla[x]; // expected-note {{jump exits scope of variable with non-trivial destructor}} 120 [[clang::musttail]] return IntParam(x); // expected-error {{cannot perform a tail call from this return statement}} 121 } 122 123 void TestNonTrivialDestructorSubArg(int x) { 124 [[clang::musttail]] return IntParam(NonTrivialParam(HasNonTrivialDestructor())); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}} 125 } 126 127 void VariadicFunction(int x, ...); 128 void TestVariadicFunction(int x, ...) { 129 [[clang::musttail]] return VariadicFunction(x); // expected-error {{'musttail' attribute may not be used with variadic functions}} 130 } 131 132 int TakesIntParam(int x); // expected-note {{target function has type mismatch at 1st parameter (expected 'int' but has 'short')}} 133 int TakesShortParam(short x); // expected-note {{target function has type mismatch at 1st parameter (expected 'short' but has 'int')}} 134 int TestIntParamMismatch(int x) { 135 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 136 return TakesShortParam(x); // expected-error {{cannot perform a tail call to function 'TakesShortParam' because its signature is incompatible with the calling function}} 137 } 138 int TestIntParamMismatch2(short x) { 139 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 140 return TakesIntParam(x); // expected-error {{cannot perform a tail call to function 'TakesIntParam' because its signature is incompatible with the calling function}} 141 } 142 143 struct TestClassMismatch1 { 144 void ToFunction(); // expected-note{{target function is a member of different class (expected 'TestClassMismatch2' but has 'TestClassMismatch1')}} 145 }; 146 TestClassMismatch1 *tcm1; 147 struct TestClassMismatch2 { 148 void FromFunction() { 149 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 150 return tcm1->ToFunction(); // expected-error {{cannot perform a tail call to function 'ToFunction' because its signature is incompatible with the calling function}} 151 } 152 }; 153 154 __regcall int RegCallReturnsInt(); // expected-note {{target function has calling convention regcall (expected cdecl)}} 155 int TestMismatchCallingConvention() { 156 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 157 return RegCallReturnsInt(); // expected-error {{cannot perform a tail call to function 'RegCallReturnsInt' because it uses an incompatible calling convention}} 158 } 159 160 int TestNonCapturingLambda() { 161 auto lambda = []() { return 12; }; // expected-note {{'operator()' declared here}} 162 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 163 return lambda(); // expected-error {{non-member function cannot perform a tail call to non-static member function 'operator()'}} 164 165 // This works. 166 auto lambda_fptr = static_cast<int (*)()>(lambda); 167 [[clang::musttail]] return lambda_fptr(); 168 [[clang::musttail]] return (+lambda)(); 169 } 170 171 int TestCapturingLambda() { 172 int x; 173 auto lambda = [x]() { return 12; }; // expected-note {{'operator()' declared here}} 174 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 175 return lambda(); // expected-error {{non-member function cannot perform a tail call to non-static member function 'operator()'}} 176 } 177 178 int TestNonTrivialTemporary(int) { 179 [[clang::musttail]] return TakesIntParam(HasNonTrivialDestructor().ReturnsInt()); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}} 180 } 181 182 void ReturnsVoid(); 183 struct TestDestructor { 184 ~TestDestructor() { 185 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 186 return ReturnsVoid(); // expected-error {{destructor '~TestDestructor' must not return void expression}} // expected-error {{cannot perform a tail call from a destructor}} 187 } 188 }; 189 190 struct ClassWithDestructor { // expected-note {{target destructor is declared here}} 191 void TestExplicitDestructorCall() { 192 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 193 return this->~ClassWithDestructor(); // expected-error {{cannot perform a tail call to a destructor}} 194 } 195 }; 196 197 struct HasNonTrivialCopyConstructor { 198 HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &); 199 }; 200 HasNonTrivialCopyConstructor ReturnsClassByValue(); 201 HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() { 202 // This is an elidable constructor, but when it is written explicitly 203 // we decline to elide it. 204 [[clang::musttail]] return HasNonTrivialCopyConstructor(ReturnsClassByValue()); // expected-error{{'musttail' attribute requires that the return value is the result of a function call}} 205 } 206 207 struct ClassWithConstructor { 208 ClassWithConstructor() = default; // expected-note {{target constructor is declared here}} 209 }; 210 void TestExplicitConstructorCall(ClassWithConstructor a) { 211 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 212 return a.ClassWithConstructor::ClassWithConstructor(); // expected-error{{cannot perform a tail call to a constructor}} expected-warning{{explicit constructor calls are a Microsoft extension}} 213 } 214 215 void TestStatementExpression() { 216 ({ 217 HasNonTrivialDestructor foo; // expected-note {{jump exits scope of variable with non-trivial destructor}} 218 [[clang::musttail]] return ReturnsVoid2(); // expected-error {{cannot perform a tail call from this return statement}} 219 }); 220 } 221 222 struct MyException {}; 223 void TestTryBlock() { 224 try { // expected-note {{jump exits try block}} 225 [[clang::musttail]] return ReturnsVoid2(); // expected-error {{cannot perform a tail call from this return statement}} 226 } catch (MyException &e) { 227 } 228 } 229 230 using IntFunctionType = int(); 231 IntFunctionType *ReturnsIntFunction(); 232 long TestRValueFunctionPointer() { 233 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 234 return ReturnsIntFunction()(); // expected-error{{cannot perform a tail call to function because its signature is incompatible with the calling function}} // expected-note{{target function has different return type ('long' expected but has 'int')}} 235 } 236 237 void TestPseudoDestructor() { 238 int n; 239 using T = int; 240 [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} 241 return n.~T(); // expected-error{{cannot perform a tail call to a destructor}} 242 } 243 244 struct StructPMF { 245 typedef void (StructPMF::*PMF)(); 246 static void TestReturnsPMF(); 247 }; 248 249 StructPMF *St; 250 StructPMF::PMF ReturnsPMF(); 251 void StructPMF::TestReturnsPMF() { 252 [[clang::musttail]] // expected-note{{tail call required by 'musttail' attribute here}} 253 return (St->*ReturnsPMF())(); // expected-error{{static member function cannot perform a tail call to pointer-to-member function}} 254 } 255 256 // These tests are merely verifying that we don't crash with incomplete or 257 // erroneous ASTs. These cases crashed the compiler in early iterations. 258 259 struct TestBadPMF { 260 int (TestBadPMF::*pmf)(); 261 void BadPMF() { 262 [[clang::musttail]] return ((*this)->*pmf)(); // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'TestBadPMF'}} 263 } 264 }; 265 266 namespace ns {} 267 void TestCallNonValue() { 268 [[clang::musttail]] return ns; // expected-error {{unexpected namespace name 'ns': expected expression}} 269 } 270 271 // Test diagnostics for lifetimes of local variables, which end earlier for a 272 // musttail call than for a nowmal one. 273 274 void TakesIntAndPtr(int, int *); 275 void PassAddressOfLocal(int a, int *b) { 276 int c; 277 [[clang::musttail]] return TakesIntAndPtr(0, &c); // expected-warning {{address of stack memory associated with local variable 'c' passed to musttail function}} 278 } 279 void PassAddressOfParam(int a, int *b) { 280 [[clang::musttail]] return TakesIntAndPtr(0, &a); // expected-warning {{address of stack memory associated with parameter 'a' passed to musttail function}} 281 } 282 void PassValues(int a, int *b) { 283 [[clang::musttail]] return TakesIntAndPtr(a, b); 284 } 285 286 void TakesIntAndRef(int, const int &); 287 void PassRefOfLocal(int a, const int &b) { 288 int c; 289 [[clang::musttail]] return TakesIntAndRef(0, c); // expected-warning {{address of stack memory associated with local variable 'c' passed to musttail function}} 290 } 291 void PassRefOfParam(int a, const int &b) { 292 [[clang::musttail]] return TakesIntAndRef(0, a); // expected-warning {{address of stack memory associated with parameter 'a' passed to musttail function}} 293 } 294 int ReturnInt(); 295 void PassRefOfTemporary(int a, const int &b) { 296 [[clang::musttail]] return TakesIntAndRef(0, ReturnInt()); // expected-warning {{passing address of local temporary object to musttail function}} 297 } 298 void PassValuesRef(int a, const int &b) { 299 [[clang::musttail]] return TakesIntAndRef(a, b); 300 } 301