blob: 4c56fabaecc00d32c7e8598274d747b8468be69e [file] [edit]
// -fkeep-inline-functions has an effect without optimization, although it is
// primarily useful with optimization enabled.
// RUN: %clang_cc1 -O2 -fkeep-inline-functions -emit-llvm %s -o - -triple x86_64-unknown-linux-gnu | FileCheck %s
// RUN: %clang_cc1 -O2 -fkeep-inline-functions -emit-llvm %s -o - -triple x86_64-pc-windows-msvc | FileCheck %s --check-prefix=MSVC
// RUN: %clang_cc1 -O2 -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s
// RUN: %clang_cc1 -O0 -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s
// RUN: %clang_cc1 -O0 -mconstructor-aliases -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s --check-prefix=CONSTRUCTOR-ALIASES
// -fkeep-inline-functions retains inline function definitions available in
// this translation unit. Definitions emitted with available_externally
// linkage are excluded.
// Retained:
// f1 explicit inline and referenced
// f2 static inline
// f3 constexpr (implicit inline)
// f4 in-class member definition (implicit inline)
// f7 explicit inline and unreferenced
// f8 explicitly instantiated inline template
// TestCtorDtor implicitly inline constructor/destructor variants.
// Also exercises the GlobalDecl construction path in MustBeEmitted() for
// constructors/destructors. Without the special handling, debug builds hit
// the GlobalDecl(FunctionDecl*) assertion.
// Not retained:
// f5 non-inline
// f6 GNU extern inline
// f9 extern template specialization
inline int f1(int x) { return x + 1; }
static inline int f2(int x) { return x + 2; }
constexpr int f3(int x) { return x + 3; }
struct S {
int f4() { return 4; }
};
int f5(int x) { return x + 5; }
__attribute__((gnu_inline)) inline int f6(int x) { return x + 6; }
inline int f7(int x) { return x + 7; }
template <typename T> inline T f8(T x) { return x + 8; }
template int f8<int>(int);
template <typename T>
struct A {
static int f9() { return 9; }
};
extern template int A<int>::f9();
// Implicitly inline ctor and dtor intentionally unreferenced so
// MustBeEmitted() is the sole mechanism that forces their emission.
struct TestCtorDtor {
TestCtorDtor() {}
~TestCtorDtor() {}
};
int use(S s) {
return f1(0) + f5(0) + f6(0) + A<int>::f9();
}
// CHECK: @llvm{{(\.compiler)?}}.used = appending global [10 x ptr]
// CHECK-DAG: define {{.*}}@_Z2f1i
// CHECK-DAG: define internal {{.*}}@_ZL2f2i
// CHECK-DAG: define {{.*}}@_Z2f3i
// CHECK-DAG: define {{.*}}@_ZN1S2f4Ev
// CHECK-DAG: define {{.*}}@_Z2f7i
// CHECK-DAG: define {{.*}}@_Z2f8IiET_S0_
// CHECK-DAG: define {{.*}}@_ZN12TestCtorDtorC1Ev
// CHECK-DAG: define {{.*}}@_ZN12TestCtorDtorD1Ev
// CHECK-DAG: define {{.*}}@_ZN12TestCtorDtorC2Ev
// CHECK-DAG: define {{.*}}@_ZN12TestCtorDtorD2Ev
// FIXME: -mconstructor-aliases is enabled by default by the driver for this
// target, but is not enabled by default for -cc1. With -mconstructor-aliases,
// the C1/D1 constructor and destructor variants are not emitted as separate
// definitions.
// CONSTRUCTOR-ALIASES: @llvm{{(\.compiler)?}}.used = appending global [8 x ptr]
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f1i
// CONSTRUCTOR-ALIASES-DAG: define internal {{.*}}@_ZL2f2i
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f3i
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_ZN1S2f4Ev
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f7i
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f8IiET_S0_
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_ZN12TestCtorDtorC2Ev
// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_ZN12TestCtorDtorD2Ev
// MSVC: @llvm{{(\.compiler)?}}.used = appending global [8 x ptr]
// MSVC-DAG: define {{.*}}@"?f1@@YAHH@Z"
// MSVC-DAG: define internal {{.*}}@"?f2@@YAHH@Z"
// MSVC-DAG: define {{.*}}@"?f3@@YAHH@Z"
// MSVC-DAG: define {{.*}}@"?f4@S@@QEAAHXZ"
// MSVC-DAG: define {{.*}}@"?f7@@YAHH@Z"
// MSVC-DAG: define {{.*}}@"??$f8@H@@YAHH@Z"
// MSVC-DAG: define {{.*}}@"??0TestCtorDtor@@QEAA@XZ"
// MSVC-DAG: define {{.*}}@"??1TestCtorDtor@@QEAA@XZ"