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
no_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
returnNotViableDontOptimize(Enum e)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
trivial()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
nonTrivialCopy()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 
NonTrivialDefaultConstructorNonTrivialDefaultConstructor69   NonTrivialDefaultConstructor() { }
70 };
71 
72 // CHECK-NOSTRICT-LABEL: @_Z28nonTrivialDefaultConstructorv
nonTrivialDefaultConstructor()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
nonTrivialDestructor()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
lambdaTest()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