1 | // RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK,CHECK-COMMON %s |
2 | // RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -O -o - %s | FileCheck %s --check-prefixes=CHECK-OPT,CHECK-COMMON |
3 | // 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 |
4 | // 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 |
5 | // 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 |
6 | |
7 | // CHECK-COMMON-LABEL: @_Z9no_return |
8 | int no_return() { |
9 | // CHECK: call void @llvm.trap |
10 | // CHECK-NEXT: unreachable |
11 | |
12 | // CHECK-OPT-NOT: call void @llvm.trap |
13 | // CHECK-OPT: unreachable |
14 | |
15 | // -fno-strict-return should not emit trap + unreachable but it should return |
16 | // an undefined value instead. |
17 | |
18 | // CHECK-NOSTRICT: alloca |
19 | // CHECK-NOSTRICT-NEXT: load |
20 | // CHECK-NOSTRICT-NEXT: ret i32 |
21 | // CHECK-NOSTRICT-NEXT: } |
22 | |
23 | // CHECK-NOSTRICT-OPT: ret i32 undef |
24 | } |
25 | |
26 | enum Enum { |
27 | A, B |
28 | }; |
29 | |
30 | // CHECK-COMMON-LABEL: @_Z27returnNotViableDontOptimize4Enum |
31 | int returnNotViableDontOptimize(Enum e) { |
32 | switch (e) { |
33 | case A: return 1; |
34 | case B: return 2; |
35 | } |
36 | // Undefined behaviour optimization shouldn't be used when -fno-strict-return |
37 | // is turned on, even if all the enum cases are covered in this function. |
38 | |
39 | // CHECK-NOSTRICT-NOT: call void @llvm.trap |
40 | // CHECK-NOSTRICT-NOT: unreachable |
41 | } |
42 | |
43 | struct Trivial { |
44 | int x; |
45 | }; |
46 | |
47 | // CHECK-NOSTRICT-LABEL: @_Z7trivialv |
48 | Trivial trivial() { |
49 | // This function returns a trivial record so -fno-strict-return should avoid |
50 | // the undefined behaviour optimization. |
51 | |
52 | // CHECK-NOSTRICT-NOT: call void @llvm.trap |
53 | // CHECK-NOSTRICT-NOT: unreachable |
54 | } |
55 | |
56 | struct NonTrivialCopy { |
57 | NonTrivialCopy(const NonTrivialCopy &); |
58 | }; |
59 | |
60 | // CHECK-NOSTRICT-LABEL: @_Z14nonTrivialCopyv |
61 | NonTrivialCopy nonTrivialCopy() { |
62 | // CHECK-NOSTRICT-NOT: call void @llvm.trap |
63 | // CHECK-NOSTRICT-NOT: unreachable |
64 | } |
65 | |
66 | struct NonTrivialDefaultConstructor { |
67 | int x; |
68 | |
69 | NonTrivialDefaultConstructor() { } |
70 | }; |
71 | |
72 | // CHECK-NOSTRICT-LABEL: @_Z28nonTrivialDefaultConstructorv |
73 | NonTrivialDefaultConstructor nonTrivialDefaultConstructor() { |
74 | // CHECK-NOSTRICT-NOT: call void @llvm.trap |
75 | // CHECK-NOSTRICT-NOT: unreachable |
76 | } |
77 | |
78 | // Functions that return records with non-trivial destructors should always use |
79 | // the -fstrict-return optimization. |
80 | |
81 | struct NonTrivialDestructor { |
82 | ~NonTrivialDestructor(); |
83 | }; |
84 | |
85 | // CHECK-NOSTRICT-LABEL: @_Z20nonTrivialDestructorv |
86 | NonTrivialDestructor nonTrivialDestructor() { |
87 | // CHECK-NOSTRICT: call void @llvm.trap |
88 | // CHECK-NOSTRICT-NEXT: unreachable |
89 | } |
90 | |
91 | // The behavior for lambdas should be identical to functions. |
92 | // CHECK-COMMON-LABEL: @_Z10lambdaTestv |
93 | void lambdaTest() { |
94 | auto lambda1 = []() -> int { |
95 | }; |
96 | lambda1(); |
97 | |
98 | // CHECK: call void @llvm.trap |
99 | // CHECK-NEXT: unreachable |
100 | |
101 | // CHECK-NOSTRICT-NOT: call void @llvm.trap |
102 | // CHECK-NOSTRICT-NOT: unreachable |
103 | } |
104 | |