// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK,CHECK-COMMON %s
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -O -o - %s | FileCheck %s --check-prefixes=CHECK-OPT,CHECK-COMMON
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT,CHECK-COMMON
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -Wno-return-type -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT,CHECK-COMMON
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -O -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT-OPT,CHECK-COMMON
// CHECK-COMMON-LABEL: @_Z9no_return
int no_return() {
// CHECK: call void @llvm.trap
// CHECK-NEXT: unreachable
// CHECK-OPT-NOT: call void @llvm.trap
// CHECK-OPT: unreachable
// -fno-strict-return should not emit trap + unreachable but it should return
// an undefined value instead.
// CHECK-NOSTRICT: alloca
// CHECK-NOSTRICT-NEXT: load
// CHECK-NOSTRICT-NEXT: ret i32
// CHECK-NOSTRICT-NEXT: }
// CHECK-NOSTRICT-OPT: ret i32 undef
}
enum Enum {
A, B
};
// CHECK-COMMON-LABEL: @_Z27returnNotViableDontOptimize4Enum
int returnNotViableDontOptimize(Enum e) {
switch (e) {
case A: return 1;
case B: return 2;
}
// Undefined behaviour optimization shouldn't be used when -fno-strict-return
// is turned on, even if all the enum cases are covered in this function.
// CHECK-NOSTRICT-NOT: call void @llvm.trap
// CHECK-NOSTRICT-NOT: unreachable
}
struct Trivial {
int x;
};
// CHECK-NOSTRICT-LABEL: @_Z7trivialv
Trivial trivial() {
// This function returns a trivial record so -fno-strict-return should avoid
// the undefined behaviour optimization.
// CHECK-NOSTRICT-NOT: call void @llvm.trap
// CHECK-NOSTRICT-NOT: unreachable
}
struct NonTrivialCopy {
NonTrivialCopy(const NonTrivialCopy &);
};
// CHECK-NOSTRICT-LABEL: @_Z14nonTrivialCopyv
NonTrivialCopy nonTrivialCopy() {
// CHECK-NOSTRICT-NOT: call void @llvm.trap
// CHECK-NOSTRICT-NOT: unreachable
}
struct NonTrivialDefaultConstructor {
int x;
NonTrivialDefaultConstructor() { }
};
// CHECK-NOSTRICT-LABEL: @_Z28nonTrivialDefaultConstructorv
NonTrivialDefaultConstructor nonTrivialDefaultConstructor() {
// CHECK-NOSTRICT-NOT: call void @llvm.trap
// CHECK-NOSTRICT-NOT: unreachable
}
// Functions that return records with non-trivial destructors should always use
// the -fstrict-return optimization.
struct NonTrivialDestructor {
~NonTrivialDestructor();
};
// CHECK-NOSTRICT-LABEL: @_Z20nonTrivialDestructorv
NonTrivialDestructor nonTrivialDestructor() {
// CHECK-NOSTRICT: call void @llvm.trap
// CHECK-NOSTRICT-NEXT: unreachable
}
// The behavior for lambdas should be identical to functions.
// CHECK-COMMON-LABEL: @_Z10lambdaTestv
void lambdaTest() {
auto lambda1 = []() -> int {
};
lambda1();
// CHECK: call void @llvm.trap
// CHECK-NEXT: unreachable
// CHECK-NOSTRICT-NOT: call void @llvm.trap
// CHECK-NOSTRICT-NOT: unreachable
}