| // RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -Wno-error=return-type -o - %s | FileCheck --check-prefixes=CHECK,CHECK-COMMON %s | |
| // RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -Wno-error=return-type -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 -Wno-error=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 -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 -Wno-error=return-type -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 | |
| } |