xref: /llvm-project/clang/test/Sema/attr-nonblocking-syntax.cpp (revision 7fe43ada28c31a9e9d82a76650d987a8b209755e)
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