1 // RUN: %clang_cc1 %s -ast-dump -fblocks | FileCheck %s 2 3 // Make sure that the attribute gets parsed and attached to the correct AST elements. 4 5 #pragma clang diagnostic ignored "-Wunused-variable" 6 #pragma clang diagnostic ignored "-Wperf-constraint-implies-noexcept" 7 8 // ========================================================================================= 9 // Square brackets, true 10 11 namespace square_brackets { 12 13 // 1. On the type of the FunctionDecl 14 void nl_function() [[clang::nonblocking]]; 15 // CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' 16 17 // 2. On the type of the VarDecl holding a function pointer 18 void (*nl_func_a)() [[clang::nonblocking]]; 19 // CHECK: VarDecl {{.*}} nl_func_a 'void (*)() __attribute__((nonblocking))' 20 21 // 3. On the type of the ParmVarDecl of a function parameter 22 static void nlReceiver(void (*nl_func)() [[clang::nonblocking]]); 23 // CHECK: ParmVarDecl {{.*}} nl_func 'void (*)() __attribute__((nonblocking))' 24 25 // 4. As an AttributedType within the nested types of a typedef 26 typedef void (*nl_fp_type)() [[clang::nonblocking]]; 27 // CHECK: TypedefDecl {{.*}} nl_fp_type 'void (*)() __attribute__((nonblocking))' 28 using nl_fp_talias = void (*)() [[clang::nonblocking]]; 29 // CHECK: TypeAliasDecl {{.*}} nl_fp_talias 'void (*)() __attribute__((nonblocking))' 30 31 // 5. From a typedef or typealias, on a VarDecl 32 nl_fp_type nl_fp_var1; 33 // CHECK: VarDecl {{.*}} nl_fp_var1 'nl_fp_type':'void (*)() __attribute__((nonblocking))' 34 nl_fp_talias nl_fp_var2; 35 // CHECK: VarDecl {{.*}} nl_fp_var2 'nl_fp_talias':'void (*)() __attribute__((nonblocking))' 36 37 // 6. On type of a FieldDecl 38 struct Struct { 39 void (*nl_func_field)() [[clang::nonblocking]]; 40 // CHECK: FieldDecl {{.*}} nl_func_field 'void (*)() __attribute__((nonblocking))' 41 }; 42 43 // nonallocating should NOT be subsumed into nonblocking 44 void nl1() [[clang::nonblocking]] [[clang::nonallocating]]; 45 // CHECK: FunctionDecl {{.*}} nl1 'void () __attribute__((nonblocking)) __attribute__((nonallocating))' 46 47 void nl2() [[clang::nonallocating]] [[clang::nonblocking]]; 48 // CHECK: FunctionDecl {{.*}} nl2 'void () __attribute__((nonblocking)) __attribute__((nonallocating))' 49 50 decltype(nl1) nl3; 51 // CHECK: FunctionDecl {{.*}} nl3 'decltype(nl1)':'void () __attribute__((nonblocking)) __attribute__((nonallocating))' 52 53 // Attribute propagates from base class virtual method to overrides. 54 struct Base { 55 virtual void nb_method() [[clang::nonblocking]]; 56 }; 57 struct Derived : public Base { 58 void nb_method() override; 59 // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' 60 }; 61 62 // Dependent expression 63 template <bool V> 64 struct Dependent { 65 void nb_method2() [[clang::nonblocking(V)]]; 66 // CHECK: CXXMethodDecl {{.*}} nb_method2 'void () __attribute__((nonblocking(V)))' 67 }; 68 69 // --- Blocks --- 70 71 // On the type of the VarDecl holding a BlockDecl 72 void (^nl_block1)() [[clang::nonblocking]] = ^() [[clang::nonblocking]] {}; 73 // CHECK: VarDecl {{.*}} nl_block1 'void (^)() __attribute__((nonblocking))' 74 75 int (^nl_block2)() [[clang::nonblocking]] = ^() [[clang::nonblocking]] { return 0; }; 76 // CHECK: VarDecl {{.*}} nl_block2 'int (^)() __attribute__((nonblocking))' 77 78 // The operand of the CallExpr is an ImplicitCastExpr of a DeclRefExpr -> nl_block which hold the attribute 79 static void blockCaller() { nl_block1(); } 80 // CHECK: DeclRefExpr {{.*}} 'nl_block1' 'void (^)() __attribute__((nonblocking))' 81 82 // --- Lambdas --- 83 84 // On the operator() of a lambda's CXXMethodDecl 85 auto nl_lambda = []() [[clang::nonblocking]] {}; 86 // CHECK: CXXMethodDecl {{.*}} operator() 'void () const __attribute__((nonblocking))' inline 87 88 // ========================================================================================= 89 // Square brackets, false 90 91 void nl_func_false() [[clang::blocking]]; 92 // CHECK: FunctionDecl {{.*}} nl_func_false 'void () __attribute__((blocking))' 93 94 auto nl_lambda_false = []() [[clang::blocking]] {}; 95 // CHECK: CXXMethodDecl {{.*}} operator() 'void () const __attribute__((blocking))' 96 97 } // namespace square_brackets 98 99 // ========================================================================================= 100 // GNU-style attribute, true 101 102 namespace gnu_style { 103 104 // 1. On the type of the FunctionDecl 105 void nl_function() __attribute__((nonblocking)); 106 // CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' 107 108 // 1a. Alternate placement on the FunctionDecl 109 __attribute__((nonblocking)) void nl_function(); 110 // CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' 111 112 // 2. On the type of the VarDecl holding a function pointer 113 void (*nl_func_a)() __attribute__((nonblocking)); 114 // CHECK: VarDecl {{.*}} nl_func_a 'void (*)() __attribute__((nonblocking))' 115 116 // 2a. Alternate attribute placement on VarDecl 117 __attribute__((nonblocking)) void (*nl_func_b)(); 118 // CHECK: VarDecl {{.*}} nl_func_b 'void (*)() __attribute__((nonblocking))' 119 120 // 3. On the type of the ParmVarDecl of a function parameter 121 static void nlReceiver(void (*nl_func)() __attribute__((nonblocking))); 122 // CHECK: ParmVarDecl {{.*}} nl_func 'void (*)() __attribute__((nonblocking))' 123 124 // 4. As an AttributedType within the nested types of a typedef 125 // Note different placement from square brackets for the typealias. 126 typedef void (*nl_fp_type)() __attribute__((nonblocking)); 127 // CHECK: TypedefDecl {{.*}} nl_fp_type 'void (*)() __attribute__((nonblocking))' 128 using nl_fp_talias = __attribute__((nonblocking)) void (*)(); 129 // CHECK: TypeAliasDecl {{.*}} nl_fp_talias 'void (*)() __attribute__((nonblocking))' 130 131 // 5. From a typedef or typealias, on a VarDecl 132 nl_fp_type nl_fp_var1; 133 // CHECK: VarDecl {{.*}} nl_fp_var1 'nl_fp_type':'void (*)() __attribute__((nonblocking))' 134 nl_fp_talias nl_fp_var2; 135 // CHECK: VarDecl {{.*}} nl_fp_var2 'nl_fp_talias':'void (*)() __attribute__((nonblocking))' 136 137 // 6. On type of a FieldDecl 138 struct Struct { 139 void (*nl_func_field)() __attribute__((nonblocking)); 140 // CHECK: FieldDecl {{.*}} nl_func_field 'void (*)() __attribute__((nonblocking))' 141 }; 142 143 } // namespace gnu_style 144 145 // ========================================================================================= 146 // nonallocating and allocating - quick checks because the code paths are generally 147 // identical after parsing. 148 149 void na_function() [[clang::nonallocating]]; 150 // CHECK: FunctionDecl {{.*}} na_function 'void () __attribute__((nonallocating))' 151 152 void na_true_function() [[clang::nonallocating(true)]]; 153 // CHECK: FunctionDecl {{.*}} na_true_function 'void () __attribute__((nonallocating))' 154 155 void na_false_function() [[clang::nonallocating(false)]]; 156 // CHECK: FunctionDecl {{.*}} na_false_function 'void () __attribute__((allocating))' 157 158 void alloc_function() [[clang::allocating]]; 159 // CHECK: FunctionDecl {{.*}} alloc_function 'void () __attribute__((allocating))' 160 161 162 // ========================================================================================= 163 // Non-blocking with an expression parameter 164 165 void t0() [[clang::nonblocking(1 - 1)]]; 166 // CHECK: FunctionDecl {{.*}} t0 'void () __attribute__((blocking))' 167 void t1() [[clang::nonblocking(1 + 1)]]; 168 // CHECK: FunctionDecl {{.*}} t1 'void () __attribute__((nonblocking))' 169 170 template <bool V> 171 struct ValueDependent { 172 void nb_method() [[clang::nonblocking(V)]]; 173 }; 174 175 void t3() [[clang::nonblocking]] 176 { 177 ValueDependent<false> x1; 178 x1.nb_method(); 179 // CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent 180 // CHECK: TemplateArgument integral 'false' 181 // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((blocking))' 182 183 ValueDependent<true> x2; 184 x2.nb_method(); 185 // CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent 186 // CHECK: TemplateArgument integral 'true' 187 // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' 188 } 189 190 template <typename X> 191 struct TypeDependent { 192 void td_method() [[clang::nonblocking(X::is_nb)]]; 193 }; 194 195 struct NBPolicyTrue { 196 static constexpr bool is_nb = true; 197 }; 198 199 struct NBPolicyFalse { 200 static constexpr bool is_nb = false; 201 }; 202 203 void t4() 204 { 205 TypeDependent<NBPolicyFalse> x1; 206 x1.td_method(); 207 // CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent 208 // CHECK: TemplateArgument type 'NBPolicyFalse' 209 // CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((blocking))' 210 211 TypeDependent<NBPolicyTrue> x2; 212 x2.td_method(); 213 // CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent 214 // CHECK: TemplateArgument type 'NBPolicyTrue' 215 // CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((nonblocking))' 216 } 217 218