// RUN: %clang_cc1 -fno-elide-constructors -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s // RUN: %clang_cc1 -fno-elide-constructors -S -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 T TemplateFunc(T) { return 5; } int Func9(int x) { [[clang::musttail]] return TemplateFunc(x); } // CHECK: %call = musttail call noundef i32 @_Z12TemplateFuncIiET_S0_(i32 noundef %0) template int Func10(int x) { T t; [[clang::musttail]] return Bar(x); } int Func11(int x) { return Func10(x); } // CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %0) template T Func12(T x) { [[clang::musttail]] return ::Bar(x); } int Func13(int x) { return Func12(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)