1 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
2 // RUN:   | FileCheck %s --check-prefixes=CHECK,CHECK-NOM
3 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
4 // RUN:   -mfunction-return=keep | FileCheck %s \
5 // RUN:   --check-prefixes=CHECK,CHECK-KEEP
6 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
7 // RUN:  -mfunction-return=thunk-extern | FileCheck %s \
8 // RUN:  --check-prefixes=CHECK,CHECK-EXTERN
9 
10 #if !__has_attribute(function_return)
11 #error "missing attribute support for function_return"
12 #endif
13 
14 // CHECK: @keep() [[KEEP:#[0-9]+]]
15 __attribute__((function_return("keep"))) void keep(void) {}
16 
17 // CHECK: @keep2() [[KEEP:#[0-9]+]]
18 [[gnu::function_return("keep")]] void keep2(void) {}
19 
20 // CHECK: @thunk_extern() [[EXTERN:#[0-9]+]]
21 __attribute__((function_return("thunk-extern"))) void thunk_extern(void) {}
22 
23 // CHECK: @thunk_extern2() [[EXTERN:#[0-9]+]]
24 [[gnu::function_return("thunk-extern")]] void thunk_extern2(void) {}
25 
26 // CHECK: @double_thunk_keep() [[KEEP]]
27 // clang-format off
28 __attribute__((function_return("thunk-extern")))
29 __attribute__((function_return("keep")))
30 void double_thunk_keep(void) {}
31 
32 // CHECK: @double_thunk_keep2() [[KEEP]]
33 [[gnu::function_return("thunk-extern")]][[gnu::function_return("keep")]]
34 void double_thunk_keep2(void) {}
35 
36 // CHECK: @double_keep_thunk() [[EXTERN]]
37 __attribute__((function_return("keep")))
38 __attribute__((function_return("thunk-extern")))
39 void double_keep_thunk(void) {}
40 
41 // CHECK: @double_keep_thunk2() [[EXTERN]]
42 [[gnu::function_return("thunk-keep")]][[gnu::function_return("thunk-extern")]]
43 void double_keep_thunk2(void) {}
44 
45 // CHECK: @thunk_keep() [[KEEP]]
46 __attribute__((function_return("thunk-extern"), function_return("keep")))
47 void thunk_keep(void) {}
48 
49 // CHECK: @thunk_keep2() [[KEEP]]
50 [[gnu::function_return("thunk-extern"), gnu::function_return("keep")]]
51 void thunk_keep2(void) {}
52 
53 // CHECK: @keep_thunk() [[EXTERN]]
54 __attribute__((function_return("keep"), function_return("thunk-extern")))
55 void keep_thunk(void) {}
56 
57 // CHECK: @keep_thunk2() [[EXTERN]]
58 [[gnu::function_return("keep"), gnu::function_return("thunk-extern")]]
59 void keep_thunk2(void) {}
60 // clang-format on
61 
62 void undef(void);
63 // CHECK: @undef() [[KEEP]]
64 __attribute__((function_return("keep"))) void undef(void) {}
65 
66 void undef2(void);
67 // CHECK: @undef2() [[EXTERN]]
68 __attribute__((function_return("thunk-extern"))) void undef2(void) {}
69 
70 __attribute__((function_return("thunk-extern"))) void change_def(void);
71 // CHECK: @change_def() [[KEEP]]
72 __attribute__((function_return("keep"))) void change_def(void) {}
73 
74 __attribute__((function_return("keep"))) void change_def2(void);
75 // CHECK: @change_def2() [[EXTERN]]
76 __attribute__((function_return("thunk-extern"))) void change_def2(void) {}
77 
78 __attribute__((function_return("thunk-extern"))) void change_def3(void);
79 // CHECK: @change_def3() [[KEEP]]
80 [[gnu::function_return("keep")]] void change_def3(void) {}
81 
82 [[gnu::function_return("keep")]] void change_def4(void);
83 // CHECK: @change_def4() [[EXTERN]]
84 __attribute__((function_return("thunk-extern"))) void change_def4(void) {}
85 
86 // When there is no -mfunction-return= flag set (NOM) or it's set to keep,
87 // we don't emit anything into the IR for unattributed functions.
88 
89 // CHECK-NOM:    @no_attrs() [[NOATTR:#[0-9]+]]
90 // CHECK-KEEP:   @no_attrs() [[NOATTR:#[0-9]+]]
91 // CHECK-EXTERN: @no_attrs() [[EXTERN]]
92 void no_attrs(void) {}
93 
94 // CHECK-NOM-NOT:  [[NOATTR]] = {{.*}}fn_ret_thunk_extern
95 // CHECK-KEEP-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern
96 // CHECK: [[EXTERN]] = {{.*}}fn_ret_thunk_extern
97