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