llvm/clang/test/CodeGenCXX/attr-musttail.cpp

// RUN: %clang_cc1 -fno-elide-constructors -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
// RUN: %clang_cc1 -fno-elide-constructors -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | opt -passes=verify
// FIXME: remove the call to "opt" once the tests are running the Clang verifier automatically again.

int Bar(int);
int Baz(int);

int Func1(int x) {
  if (x) {
    // CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %1)
    // CHECK-NEXT: ret i32 %call
    [[clang::musttail]] return Bar(x);
  } else {
    [[clang::musttail]] return Baz(x); // CHECK: %call1 = musttail call noundef i32 @_Z3Bazi(i32 noundef %3)
  }
}

int Func2(int x) {
  {
    [[clang::musttail]] return Bar(Bar(x));
  }
}

// CHECK: %call1 = musttail call noundef i32 @_Z3Bari(i32 noundef %call)

class Foo {
public:
  static int StaticMethod(int x);
  int MemberFunction(int x);
  int TailFrom(int x);
  int TailFrom2(int x);
  int TailFrom3(int x);
};

int Foo::TailFrom(int x) {
  [[clang::musttail]] return MemberFunction(x);
}

// CHECK: %call = musttail call noundef i32 @_ZN3Foo14MemberFunctionEi(ptr noundef nonnull align 1 dereferenceable(1) %this1, i32 noundef %0)

int Func3(int x) {
  [[clang::musttail]] return Foo::StaticMethod(x);
}

// CHECK: %call = musttail call noundef i32 @_ZN3Foo12StaticMethodEi(i32 noundef %0)

int Func4(int x) {
  Foo foo; // Object with trivial destructor.
  [[clang::musttail]] return foo.StaticMethod(x);
}

// CHECK: %call = musttail call noundef i32 @_ZN3Foo12StaticMethodEi(i32 noundef %0)

int (Foo::*pmf)(int);

int Foo::TailFrom2(int x) {
  [[clang::musttail]] return ((*this).*pmf)(x);
}

// CHECK: %call = musttail call noundef i32 %5(ptr noundef nonnull align 1 dereferenceable(1) %1, i32 noundef %6)

int Foo::TailFrom3(int x) {
  [[clang::musttail]] return (this->*pmf)(x);
}

// CHECK: %call = musttail call noundef i32 %5(ptr noundef nonnull align 1 dereferenceable(1) %1, i32 noundef %6)

void ReturnsVoid();

void Func5() {
  [[clang::musttail]] return ReturnsVoid();
}

// CHECK: musttail call void @_Z11ReturnsVoidv()

class HasTrivialDestructor {};

int ReturnsInt(int x);

int Func6(int x) {
  HasTrivialDestructor foo;
  [[clang::musttail]] return ReturnsInt(x);
}

// CHECK: %call = musttail call noundef i32 @_Z10ReturnsInti(i32 noundef %0)

struct Data {
  int (*fptr)(Data *);
};

int Func7(Data *data) {
  [[clang::musttail]] return data->fptr(data);
}

// CHECK: %call = musttail call noundef i32 %1(ptr noundef %2)

template <class T>
T TemplateFunc(T) {
  return 5;
}

int Func9(int x) {
  [[clang::musttail]] return TemplateFunc<int>(x);
}

// CHECK: %call = musttail call noundef i32 @_Z12TemplateFuncIiET_S0_(i32 noundef %0)

template <class T>
int Func10(int x) {
  T t;
  [[clang::musttail]] return Bar(x);
}

int Func11(int x) {
  return Func10<int>(x);
}

// CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %0)

template <class T>
T Func12(T x) {
  [[clang::musttail]] return ::Bar(x);
}

int Func13(int x) {
  return Func12<int>(x);
}

// CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %0)

int Func14(int x) {
  int vla[x];
  [[clang::musttail]] return Bar(x);
}

// CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %3)

void TrivialDestructorParam(HasTrivialDestructor obj);

void Func14(HasTrivialDestructor obj) {
  [[clang::musttail]] return TrivialDestructorParam(obj);
}

// CHECK: musttail call void @_Z22TrivialDestructorParam20HasTrivialDestructor()

struct Struct3 {
  void ConstMemberFunction(const int *) const;
  void NonConstMemberFunction(int *i);
};
void Struct3::NonConstMemberFunction(int *i) {
  // The parameters are not identical, but they are compatible.
  [[clang::musttail]] return ConstMemberFunction(i);
}

// CHECK: musttail call void @_ZNK7Struct319ConstMemberFunctionEPKi(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef %0)

struct HasNonTrivialCopyConstructor {
  HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &);
};
HasNonTrivialCopyConstructor ReturnsClassByValue();
HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() {
  [[clang::musttail]] return (((ReturnsClassByValue())));
}

// CHECK: musttail call void @_Z19ReturnsClassByValuev(ptr dead_on_unwind writable sret(%struct.HasNonTrivialCopyConstructor) align 1 %agg.result)

struct HasNonTrivialCopyConstructor2 {
  // Copy constructor works even if it has extra default params.
  HasNonTrivialCopyConstructor2(const HasNonTrivialCopyConstructor &, int DefaultParam = 5);
};
HasNonTrivialCopyConstructor2 ReturnsClassByValue2();
HasNonTrivialCopyConstructor2 TestNonElidableCopyConstructor2() {
  [[clang::musttail]] return (((ReturnsClassByValue2())));
}

// CHECK: musttail call void @_Z20ReturnsClassByValue2v()

void TestFunctionPointer(int x) {
  void (*p)(int) = nullptr;
  [[clang::musttail]] return p(x);
}

// CHECK: musttail call void %0(i32 noundef %1)

struct LargeWithCopyConstructor {
  LargeWithCopyConstructor(const LargeWithCopyConstructor &);
  char data[32];
};
LargeWithCopyConstructor ReturnsLarge();
LargeWithCopyConstructor TestLargeWithCopyConstructor() {
  [[clang::musttail]] return ReturnsLarge();
}

// CHECK: define dso_local void @_Z28TestLargeWithCopyConstructorv(ptr dead_on_unwind noalias writable sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
// CHECK: musttail call void @_Z12ReturnsLargev(ptr dead_on_unwind writable sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)

using IntFunctionType = int();
IntFunctionType *ReturnsIntFunction();
int TestRValueFunctionPointer() {
  [[clang::musttail]] return ReturnsIntFunction()();
}

// CHECK: musttail call noundef i32 %call()

void(FuncWithParens)() {
  [[clang::musttail]] return FuncWithParens();
}

// CHECK: musttail call void @_Z14FuncWithParensv()

int TestNonCapturingLambda() {
  auto lambda = []() { return 12; };
  [[clang::musttail]] return (+lambda)();
}

// CHECK: %call = call noundef ptr @"_ZZ22TestNonCapturingLambdavENK3$_0cvPFivEEv"(ptr noundef nonnull align 1 dereferenceable(1) %lambda)
// CHECK: musttail call noundef i32 %call()

class TestVirtual {
  virtual void TailTo();
  virtual void TailFrom();
};

void TestVirtual::TailFrom() {
  [[clang::musttail]] return TailTo();
}

// CHECK: musttail call void %0(ptr noundef nonnull align 8 dereferenceable(8) %this1)