brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.8 KiB · b88f031 Raw
301 lines · cpp
1// RUN: %clang_cc1 -verify -fsyntax-only -fms-extensions -fcxx-exceptions -fopenmp -triple x86_64-linux %s2 3int ReturnsInt1();4int Func1() {5  [[clang::musttail]] ReturnsInt1();              // expected-error {{'clang::musttail' attribute only applies to return statements}}6  [[clang::musttail(1, 2)]] return ReturnsInt1(); // expected-error {{'clang::musttail' attribute takes no arguments}}7  [[clang::musttail]] return 5;                   // expected-error {{'clang::musttail' attribute requires that the return value is the result of a function call}}8  [[clang::musttail]] return ReturnsInt1();9}10 11void NoFunctionCall() {12  [[clang::musttail]] return; // expected-error {{'clang::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 {{'clang::musttail' attribute cannot be applied to a declaration}}16 17void NoParams(); // expected-note {{target function has different number of parameters (expected 1 but has 0)}}18void TestParamArityMismatch(int x) {19  [[clang::musttail]] // expected-note {{tail call required by 'clang::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 23void LongParam(long x); // expected-note {{target function has type mismatch at 1st parameter (expected 'long' but has 'int')}}24void TestParamTypeMismatch(int x) {25  [[clang::musttail]]  // expected-note {{tail call required by 'clang::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 29long ReturnsLong(); // expected-note {{target function has different return type ('int' expected but has 'long')}}30int TestReturnTypeMismatch() {31  [[clang::musttail]]   // expected-note {{tail call required by 'clang::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 35struct Struct1 {36  void MemberFunction(); // expected-note {{'MemberFunction' declared here}}37};38void TestNonMemberToMember() {39  Struct1 st;40  [[clang::musttail]]         // expected-note {{tail call required by 'clang::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 44void ReturnsVoid(); // expected-note {{'ReturnsVoid' declared here}}45struct Struct2 {46  void TestMemberToNonMember() {47    [[clang::musttail]]   // expected-note {{tail call required by 'clang::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 52class HasNonTrivialDestructor {53public:54  ~HasNonTrivialDestructor() {}55  int ReturnsInt();56};57 58void ReturnsVoid2();59void 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 64int NonTrivialParam(HasNonTrivialDestructor x);65int 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 69HasNonTrivialDestructor ReturnsNonTrivialValue();70HasNonTrivialDestructor TestReturnsNonTrivialValue() {71  // FIXME: the diagnostic cannot currently distinguish between needing to run a72  // destructor for the return value and needing to run a destructor for some73  // 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 77HasNonTrivialDestructor TestReturnsNonTrivialNonFunctionCall() {78  [[clang::musttail]] return HasNonTrivialDestructor(); // expected-error {{'clang::musttail' attribute requires that the return value is the result of a function call}}79}80 81struct UsesPointerToMember {82  void (UsesPointerToMember::*p_mem)(); // expected-note {{'p_mem' declared here}}83};84void TestUsesPointerToMember(UsesPointerToMember *foo) {85  // "this" pointer cannot double as first parameter.86  [[clang::musttail]]            // expected-note {{tail call required by 'clang::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 90void ReturnsVoid2();91void 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 101template <class T>102T TemplateFunc(T x) { // expected-note{{target function has different return type ('long' expected but has 'int')}}103  return x ? 5 : 10;104}105int OkTemplateFunc(int x) {106  [[clang::musttail]] return TemplateFunc<int>(x);107}108template <class T>109T BadTemplateFunc(T x) {110  [[clang::musttail]]          // expected-note {{tail call required by 'clang::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}113long TestBadTemplateFunc(long x) {114  return BadTemplateFunc<long>(x); // expected-note {{in instantiation of}}115}116 117void IntParam(int x);118void 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 123void 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 127void VariadicFunction(int x, ...);128void TestVariadicFunction(int x, ...) {129  [[clang::musttail]] return VariadicFunction(x); // expected-error {{'clang::musttail' attribute may not be used with variadic functions}}130}131 132int TakesIntParam(int x);     // expected-note {{target function has type mismatch at 1st parameter (expected 'int' but has 'short')}}133int TakesShortParam(short x); // expected-note {{target function has type mismatch at 1st parameter (expected 'short' but has 'int')}}134int TestIntParamMismatch(int x) {135  [[clang::musttail]]        // expected-note {{tail call required by 'clang::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}138int TestIntParamMismatch2(short x) {139  [[clang::musttail]]      // expected-note {{tail call required by 'clang::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 143struct TestClassMismatch1 {144  void ToFunction(); // expected-note{{target function is a member of different class (expected 'TestClassMismatch2' but has 'TestClassMismatch1')}}145};146TestClassMismatch1 *tcm1;147struct TestClassMismatch2 {148  void FromFunction() {149    [[clang::musttail]]        // expected-note {{tail call required by 'clang::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)}}155int TestMismatchCallingConvention() {156  [[clang::musttail]]         // expected-note {{tail call required by 'clang::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 160int TestNonCapturingLambda() {161  auto lambda = []() { return 12; }; // expected-note {{'operator()' declared here}}162  [[clang::musttail]]                // expected-note {{tail call required by 'clang::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 171int TestCapturingLambda() {172  int x;173  auto lambda = [x]() { return 12; }; // expected-note {{'operator()' declared here}}174  [[clang::musttail]]                 // expected-note {{tail call required by 'clang::musttail' attribute here}}175  return lambda();                    // expected-error {{non-member function cannot perform a tail call to non-static member function 'operator()'}}176}177 178int 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 182void ReturnsVoid();183struct TestDestructor {184  ~TestDestructor() {185    [[clang::musttail]]   // expected-note {{tail call required by 'clang::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 190struct ClassWithDestructor { // expected-note {{target destructor is declared here}}191  void TestExplicitDestructorCall() {192    [[clang::musttail]]                  // expected-note {{tail call required by 'clang::musttail' attribute here}}193    return this->~ClassWithDestructor(); // expected-error {{cannot perform a tail call to a destructor}}194  }195};196 197struct HasNonTrivialCopyConstructor {198  HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &);199};200HasNonTrivialCopyConstructor ReturnsClassByValue();201HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() {202  // This is an elidable constructor, but when it is written explicitly203  // we decline to elide it.204  [[clang::musttail]] return HasNonTrivialCopyConstructor(ReturnsClassByValue()); // expected-error{{'clang::musttail' attribute requires that the return value is the result of a function call}}205}206 207struct ClassWithConstructor {208  ClassWithConstructor() = default; // expected-note {{target constructor is declared here}}209};210void TestExplicitConstructorCall(ClassWithConstructor a) {211  [[clang::musttail]]                                    // expected-note {{tail call required by 'clang::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 215void 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 222struct MyException {};223void 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 230using IntFunctionType = int();231IntFunctionType *ReturnsIntFunction();232long TestRValueFunctionPointer() {233  [[clang::musttail]]            // expected-note {{tail call required by 'clang::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 237void TestPseudoDestructor() {238  int n;239  using T = int;240  [[clang::musttail]] // expected-note {{tail call required by 'clang::musttail' attribute here}}241  return n.~T();      // expected-error{{cannot perform a tail call to a destructor}}242}243 244struct StructPMF {245  typedef void (StructPMF::*PMF)();246  static void TestReturnsPMF();247};248 249StructPMF *St;250StructPMF::PMF ReturnsPMF();251void StructPMF::TestReturnsPMF() {252  [[clang::musttail]]           // expected-note{{tail call required by 'clang::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 or257// erroneous ASTs. These cases crashed the compiler in early iterations.258 259struct 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 266namespace ns {}267void 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 a272// musttail call than for a nowmal one.273 274void TakesIntAndPtr(int, int *);275void 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}279void 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}282void PassValues(int a, int *b) {283  [[clang::musttail]] return TakesIntAndPtr(a, b);284}285 286void TakesIntAndRef(int, const int &);287void 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}291void 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}294int ReturnInt();295void 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}298void PassValuesRef(int a, const int &b) {299  [[clang::musttail]] return TakesIntAndRef(a, b);300}301