| // RUN: %clang_cc1 -emit-llvm -x c %s -triple x86_64-unknown-linux-gnu -o - -femit-all-decls -fblocks -DTEST_ATTR | FileCheck %s --check-prefix=C,C-ATTR | |
| // RUN: %clang_cc1 -emit-llvm -x c %s -triple x86_64-unknown-linux-gnu -o - -femit-all-decls -fblocks -mno-outline | FileCheck %s --check-prefix=C,C-ARG | |
| // RUN: %clang_cc1 -emit-llvm -x c %s -triple x86_64-unknown-linux-gnu -o - -femit-all-decls -fblocks | FileCheck %s --check-prefix=C,C-NONE | |
| // RUN: %clang_cc1 -emit-llvm -x c++ %s -triple x86_64-unknown-linux-gnu -o - -femit-all-decls -fblocks -std=c++23 -DTEST_ATTR | FileCheck %s --check-prefixes=CXX,CXX-ATTR | |
| // RUN: %clang_cc1 -emit-llvm -x c++ %s -triple x86_64-unknown-linux-gnu -o - -femit-all-decls -fblocks -std=c++23 -mno-outline | FileCheck %s --check-prefixes=CXX,CXX-ARG | |
| // RUN: %clang_cc1 -emit-llvm -x c++ %s -triple x86_64-unknown-linux-gnu -o - -femit-all-decls -fblocks -std=c++23 | FileCheck %s --check-prefixes=CXX,CXX-NONE | |
| // This test checks that: | |
| // - [[clang::no_outline]] adds the nooutline IR attribute to specific definitions | |
| // - `-mno-outline` adds the nooutline IR attribute to all definitions | |
| // - Lack of either does not add nooutline IR attribute | |
| #ifdef TEST_ATTR | |
| #define ATTR [[clang::no_outline]] | |
| #define ATTR_DUNDER __attribute__((no_outline)) | |
| #else | |
| #define ATTR | |
| #define ATTR_DUNDER | |
| #endif | |
| // C-LABEL: define dso_local i32 @toplevel_func( | |
| // C-SAME: ) #[[ATTR1:[0-9]+]] { | |
| // CXX-LABEL: define dso_local noundef i32 @_Z13toplevel_funci( | |
| // CXX-SAME: ) #[[ATTR1:[0-9]+]] { | |
| ATTR int toplevel_func(int x) { | |
| return x; | |
| } | |
| // C-LABEL: define dso_local i32 @toplevel_func_noattr( | |
| // C-ATTR-SAME: ) #[[ATTR2:[0-9]+]] { | |
| // C-ARG-SAME: ) #[[ATTR1]] { | |
| // C-NONE-SAME: ) #[[ATTR1]] { | |
| // CXX-LABEL: define dso_local noundef i32 @_Z20toplevel_func_noattri( | |
| // CXX-ATTR-SAME: ) #[[ATTR2:[0-9]+]] { | |
| // CXX-ARG-SAME: ) #[[ATTR1]] { | |
| // CXX-NONE-SAME: ) #[[ATTR1]] { | |
| int toplevel_func_noattr(int x) { | |
| return x; | |
| } | |
| // C-only: Function without prototype | |
| #ifndef __cplusplus | |
| #pragma clang diagnostic push | |
| #pragma clang diagnostic ignored "-Wdeprecated-non-prototype" | |
| #pragma clang diagnostic ignored "-Wimplicit-int" | |
| // C-LABEL: define dso_local i32 @no_proto_func( | |
| // C-SAME: ) #[[ATTR1]] { | |
| ATTR no_proto_func(x) | |
| int x; { | |
| return x; | |
| } | |
| #pragma clang diagnostic pop | |
| #endif | |
| // With Blocks | |
| #if __has_feature(blocks) | |
| // C-LABEL: define dso_local i32 @func_with_block( | |
| // C-ATTR-SAME: ) #[[ATTR2]] { | |
| // C-ARG-SAME: ) #[[ATTR1]] { | |
| // C-NONE-SAME: ) #[[ATTR1]] { | |
| // CXX-LABEL: define dso_local noundef i32 @_Z15func_with_blocki( | |
| // CXX-ATTR-SAME: ) #[[ATTR2]] { | |
| // CXX-ARG-SAME: ) #[[ATTR1]] { | |
| // CXX-NONE-SAME: ) #[[ATTR1]] { | |
| int func_with_block(int x) { | |
| // C-LABEL: define internal i32 @__func_with_block_block_invoke( | |
| // C-SAME: ) #[[ATTR1]] { | |
| // CXX-LABEL: define internal noundef i32 @___Z15func_with_blocki_block_invoke( | |
| // CXX-ATTR-SAME: ) #[[ATTR3:[0-9]+]] { | |
| // CXX-ARG-SAME: ) #[[ATTR2:[0-9]+]] { | |
| // CXX-NONE-SAME: ) #[[ATTR2:[0-9]+]] { | |
| int (^block)(int) = ^ ATTR_DUNDER int (int y) { return y; }; | |
| return block(x); | |
| } | |
| #endif | |
| // C++-only: Member Functions, Lambdas, Templates | |
| #ifdef __cplusplus | |
| struct my_struct { | |
| // CXX-LABEL: define linkonce_odr noundef i32 @_ZN9my_struct11member_funcEi( | |
| // CXX-SAME: ) #[[ATTR1]] comdat | |
| ATTR int member_func(int x) { | |
| return x; | |
| } | |
| // CXX-LABEL: define linkonce_odr noundef i32 @_ZN9my_struct11static_funcEi( | |
| // CXX-SAME: ) #[[ATTR1]] comdat | |
| ATTR static int static_func(int x) { | |
| return x; | |
| } | |
| }; | |
| template <typename T> struct templated_struct { | |
| ATTR T member_func(T x) { | |
| return x; | |
| } | |
| ATTR static T static_func(T x) { | |
| return x; | |
| } | |
| }; | |
| // CXX-LABEL: define weak_odr noundef i32 @_ZN16templated_structIiE11member_funcEi( | |
| // CXX-SAME: ) #[[ATTR1]] comdat | |
| // CXX-LABEL: define weak_odr noundef i32 @_ZN16templated_structIiE11static_funcEi( | |
| // CXX-SAME: ) #[[ATTR1]] comdat | |
| template struct templated_struct<int>; | |
| // CXX-LABEL: define dso_local noundef i32 @_Z16func_with_lambdai( | |
| // CXX-ATTR-SAME: ) #[[ATTR2]] | |
| // CXX-ARG-SAME: ) #[[ATTR1]] | |
| // CXX-NONE-SAME: ) #[[ATTR1]] | |
| int func_with_lambda(int x) { | |
| // CXX-LABEL: define internal noundef i32 @"_ZZ16func_with_lambdaiENK3$_0clEv"( | |
| // CXX-SAME: ) #[[ATTR1]] | |
| auto lambda = [x] ATTR () -> int { | |
| return x; | |
| }; | |
| return lambda(); | |
| } | |
| #endif | |
| // C: attributes #[[ATTR1]] = { | |
| // C-ATTR-SAME: nooutline | |
| // C-ARG-SAME: nooutline | |
| // C-NONE-NOT: nooutline | |
| // C-SAME: } | |
| // C-ATTR: attributes #[[ATTR2]] = { | |
| // C-ATTR-NOT: nooutline | |
| // C-ATTR-SAME: } | |
| // CXX: attributes #[[ATTR1]] = { | |
| // CXX-ATTR-SAME: nooutline | |
| // CXX-ARG-SAME: nooutline | |
| // CXX-NONE-NOT: nooutline | |
| // CXX-SAME: } | |
| // CXX: attributes #[[ATTR2]] = { | |
| // CXX-ATTR-NOT: nooutline | |
| // CXX-ARG-SAME: nooutline | |
| // CXX-NONE-NOT: nooutline | |
| // CXX-SAME: } | |
| // CXX-ATTR: attributes #[[ATTR3]] = { | |
| // CXX-ATTR-SAME: nooutline | |
| // CXX-ATTR-SAME: } |