Files
clang-p2996/clang/test/CodeGenCXX/attr-musttail.cpp
Roman Lebedev 16d0381841 Return "[CGCall] Annotate this argument with alignment"
The original change was reverted because it was discovered
that clang mishandles thunks, and they receive wrong
attributes for their this/return types - the ones for the function
they will call, not the ones they have.

While i have tried to fix this in https://reviews.llvm.org/D100388
that patch has been up and stuck for a month now,
with little signs of progress.

So while it will be good to solve this for real,
for now we can simply avoid introducing the bug,
by not annotating this/return for thunks.

This reverts commit 6270b3a1ea,
relanding 0aa0458f14.
2021-05-13 20:33:14 +03:00

229 lines
6.0 KiB
C++

// 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 -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 i32 @_Z3Bari(i32 %1)
// CHECK-NEXT: ret i32 %call
[[clang::musttail]] return Bar(x);
} else {
[[clang::musttail]] return Baz(x); // CHECK: %call1 = musttail call i32 @_Z3Bazi(i32 %3)
}
}
int Func2(int x) {
{
[[clang::musttail]] return Bar(Bar(x));
}
}
// CHECK: %call1 = musttail call i32 @_Z3Bari(i32 %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 i32 @_ZN3Foo14MemberFunctionEi(%class.Foo* nonnull align 1 dereferenceable(1) %this1, i32 %0)
int Func3(int x) {
[[clang::musttail]] return Foo::StaticMethod(x);
}
// CHECK: %call = musttail call i32 @_ZN3Foo12StaticMethodEi(i32 %0)
int Func4(int x) {
Foo foo; // Object with trivial destructor.
[[clang::musttail]] return foo.StaticMethod(x);
}
// CHECK: %call = musttail call i32 @_ZN3Foo12StaticMethodEi(i32 %0)
int (Foo::*pmf)(int);
int Foo::TailFrom2(int x) {
[[clang::musttail]] return ((*this).*pmf)(x);
}
// CHECK: %call = musttail call i32 %8(%class.Foo* nonnull align 1 dereferenceable(1) %this.adjusted, i32 %9)
int Foo::TailFrom3(int x) {
[[clang::musttail]] return (this->*pmf)(x);
}
// CHECK: %call = musttail call i32 %8(%class.Foo* nonnull align 1 dereferenceable(1) %this.adjusted, i32 %9)
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 i32 @_Z10ReturnsInti(i32 %0)
struct Data {
int (*fptr)(Data *);
};
int Func7(Data *data) {
[[clang::musttail]] return data->fptr(data);
}
// CHECK: %call = musttail call i32 %1(%struct.Data* %2)
template <class T>
T TemplateFunc(T) {
return 5;
}
int Func9(int x) {
[[clang::musttail]] return TemplateFunc<int>(x);
}
// CHECK: %call = musttail call i32 @_Z12TemplateFuncIiET_S0_(i32 %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 i32 @_Z3Bari(i32 %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 i32 @_Z3Bari(i32 %0)
int Func14(int x) {
int vla[x];
[[clang::musttail]] return Bar(x);
}
// CHECK: %call = musttail call i32 @_Z3Bari(i32 %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(%struct.Struct3* nonnull align 1 dereferenceable(1) %this1, i32* %0)
struct HasNonTrivialCopyConstructor {
HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &);
};
HasNonTrivialCopyConstructor ReturnsClassByValue();
HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() {
[[clang::musttail]] return (((ReturnsClassByValue())));
}
// CHECK: musttail call void @_Z19ReturnsClassByValuev(%struct.HasNonTrivialCopyConstructor* 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 %1)
struct LargeWithCopyConstructor {
LargeWithCopyConstructor(const LargeWithCopyConstructor &);
char data[32];
};
LargeWithCopyConstructor ReturnsLarge();
LargeWithCopyConstructor TestLargeWithCopyConstructor() {
[[clang::musttail]] return ReturnsLarge();
}
// CHECK: define dso_local void @_Z28TestLargeWithCopyConstructorv(%struct.LargeWithCopyConstructor* noalias sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
// CHECK: musttail call void @_Z12ReturnsLargev(%struct.LargeWithCopyConstructor* sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
using IntFunctionType = int();
IntFunctionType *ReturnsIntFunction();
int TestRValueFunctionPointer() {
[[clang::musttail]] return ReturnsIntFunction()();
}
// CHECK: musttail call 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 i32 ()* @"_ZZ22TestNonCapturingLambdavENK3$_0cvPFivEEv"(%class.anon* nonnull align 1 dereferenceable(1) %lambda)
// CHECK: musttail call i32 %call()
class TestVirtual {
virtual void TailTo();
virtual void TailFrom();
};
void TestVirtual::TailFrom() {
[[clang::musttail]] return TailTo();
}
// CHECK: musttail call void %1(%class.TestVirtual* nonnull align 8 dereferenceable(8) %this1)