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