File: attr-nonblocking-syntax.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,998,492 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (216 lines) | stat: -rw-r--r-- 8,389 bytes parent folder | download | duplicates (2)
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))'
}