• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/resolver/resolver.h"
16 
17 #include "gmock/gmock.h"
18 #include "src/ast/struct_block_decoration.h"
19 #include "src/resolver/resolver_test_helper.h"
20 #include "src/sem/struct.h"
21 
22 namespace tint {
23 namespace resolver {
24 namespace {
25 
26 using ResolverStorageClassValidationTest = ResolverTest;
27 
TEST_F(ResolverStorageClassValidationTest,GlobalVariableNoStorageClass_Fail)28 TEST_F(ResolverStorageClassValidationTest, GlobalVariableNoStorageClass_Fail) {
29   // var g : f32;
30   Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kNone);
31 
32   EXPECT_FALSE(r()->Resolve());
33   EXPECT_EQ(r()->error(),
34             "12:34 error: global variables must have a storage class");
35 }
36 
TEST_F(ResolverStorageClassValidationTest,StorageBufferBool)37 TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
38   // var<storage> g : i32;
39   Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
40          ast::DecorationList{
41              create<ast::BindingDecoration>(0),
42              create<ast::GroupDecoration>(0),
43          });
44 
45   ASSERT_FALSE(r()->Resolve());
46 
47   EXPECT_EQ(
48       r()->error(),
49       R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
50 }
51 
TEST_F(ResolverStorageClassValidationTest,StorageBufferPointer)52 TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
53   // var<storage> g : vec4<f32>;
54   Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
55          ast::DecorationList{
56              create<ast::BindingDecoration>(0),
57              create<ast::GroupDecoration>(0),
58          });
59 
60   ASSERT_FALSE(r()->Resolve());
61 
62   EXPECT_EQ(
63       r()->error(),
64       R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
65 }
66 
TEST_F(ResolverStorageClassValidationTest,StorageBufferArray)67 TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
68   // var<storage, read> g : array<S, 3>;
69   auto* s = Structure("S", {Member("a", ty.f32())});
70   auto* a = ty.array(ty.Of(s), 3);
71   Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
72          ast::Access::kRead,
73          ast::DecorationList{
74              create<ast::BindingDecoration>(0),
75              create<ast::GroupDecoration>(0),
76          });
77 
78   ASSERT_FALSE(r()->Resolve());
79 
80   EXPECT_EQ(
81       r()->error(),
82       R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
83 }
84 
TEST_F(ResolverStorageClassValidationTest,StorageBufferBoolAlias)85 TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
86   // type a = bool;
87   // var<storage, read> g : a;
88   auto* a = Alias("a", ty.bool_());
89   Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
90          ast::DecorationList{
91              create<ast::BindingDecoration>(0),
92              create<ast::GroupDecoration>(0),
93          });
94 
95   ASSERT_FALSE(r()->Resolve());
96 
97   EXPECT_EQ(
98       r()->error(),
99       R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
100 56:78 note: while instantiating variable g)");
101 }
102 
TEST_F(ResolverStorageClassValidationTest,NotStorage_AccessMode)103 TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
104   // var<private, read> g : a;
105   Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate,
106          ast::Access::kRead);
107 
108   ASSERT_FALSE(r()->Resolve());
109 
110   EXPECT_EQ(
111       r()->error(),
112       R"(56:78 error: only variables in <storage> storage class may declare an access mode)");
113 }
114 
TEST_F(ResolverStorageClassValidationTest,StorageBufferNoBlockDecoration)115 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
116   // struct S { x : i32 };
117   // var<storage, read> g : S;
118   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
119   Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
120          ast::Access::kRead,
121          ast::DecorationList{
122              create<ast::BindingDecoration>(0),
123              create<ast::GroupDecoration>(0),
124          });
125 
126   ASSERT_FALSE(r()->Resolve());
127 
128   EXPECT_EQ(
129       r()->error(),
130       R"(12:34 error: structure used as a storage buffer must be declared with the [[block]] decoration
131 56:78 note: structure used as storage buffer here)");
132 }
133 
TEST_F(ResolverStorageClassValidationTest,StorageBufferNoError_Basic)134 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
135   // [[block]] struct S { x : i32 };
136   // var<storage, read> g : S;
137   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
138                       {create<ast::StructBlockDecoration>()});
139   Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
140          ast::Access::kRead,
141          ast::DecorationList{
142              create<ast::BindingDecoration>(0),
143              create<ast::GroupDecoration>(0),
144          });
145 
146   ASSERT_TRUE(r()->Resolve());
147 }
148 
TEST_F(ResolverStorageClassValidationTest,StorageBufferNoError_Aliases)149 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
150   // [[block]] struct S { x : i32 };
151   // type a1 = S;
152   // var<storage, read> g : a1;
153   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
154                       {create<ast::StructBlockDecoration>()});
155   auto* a1 = Alias("a1", ty.Of(s));
156   auto* a2 = Alias("a2", ty.Of(a1));
157   Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage,
158          ast::Access::kRead,
159          ast::DecorationList{
160              create<ast::BindingDecoration>(0),
161              create<ast::GroupDecoration>(0),
162          });
163 
164   ASSERT_TRUE(r()->Resolve());
165 }
166 
TEST_F(ResolverStorageClassValidationTest,UniformBuffer_Struct_Runtime)167 TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
168   // [[block]] struct S { m:  array<f32>; };
169   // [[group(0), binding(0)]] var<uniform, > svar : S;
170 
171   auto* s = Structure(Source{{12, 34}}, "S", {Member("m", ty.array<i32>())},
172                       {create<ast::StructBlockDecoration>()});
173 
174   Global(Source{{56, 78}}, "svar", ty.Of(s), ast::StorageClass::kUniform,
175          ast::DecorationList{
176              create<ast::BindingDecoration>(0),
177              create<ast::GroupDecoration>(0),
178          });
179 
180   ASSERT_FALSE(r()->Resolve());
181   EXPECT_EQ(r()->error(),
182             "56:78 error: structure containing a runtime sized array cannot be "
183             "used as a uniform buffer\n12:34 note: structure is declared here");
184 }
185 
TEST_F(ResolverStorageClassValidationTest,UniformBufferBool)186 TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
187   // var<uniform> g : bool;
188   Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
189          ast::DecorationList{
190              create<ast::BindingDecoration>(0),
191              create<ast::GroupDecoration>(0),
192          });
193 
194   ASSERT_FALSE(r()->Resolve());
195 
196   EXPECT_EQ(
197       r()->error(),
198       R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
199 56:78 note: while instantiating variable g)");
200 }
201 
TEST_F(ResolverStorageClassValidationTest,UniformBufferPointer)202 TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
203   // var<uniform> g : vec4<f32>;
204   Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
205          ast::DecorationList{
206              create<ast::BindingDecoration>(0),
207              create<ast::GroupDecoration>(0),
208          });
209 
210   ASSERT_FALSE(r()->Resolve());
211 
212   EXPECT_EQ(
213       r()->error(),
214       R"(56:78 error: variables declared in the <uniform> storage class must be of a structure type)");
215 }
216 
TEST_F(ResolverStorageClassValidationTest,UniformBufferArray)217 TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
218   // var<uniform> g : array<S, 3>;
219   auto* s = Structure("S", {Member("a", ty.f32())});
220   auto* a = ty.array(ty.Of(s), 3);
221   Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
222          ast::DecorationList{
223              create<ast::BindingDecoration>(0),
224              create<ast::GroupDecoration>(0),
225          });
226 
227   ASSERT_FALSE(r()->Resolve());
228 
229   EXPECT_EQ(
230       r()->error(),
231       R"(56:78 error: variables declared in the <uniform> storage class must be of a structure type)");
232 }
233 
TEST_F(ResolverStorageClassValidationTest,UniformBufferBoolAlias)234 TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
235   // type a = bool;
236   // var<uniform> g : a;
237   auto* a = Alias("a", ty.bool_());
238   Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
239          ast::DecorationList{
240              create<ast::BindingDecoration>(0),
241              create<ast::GroupDecoration>(0),
242          });
243 
244   ASSERT_FALSE(r()->Resolve());
245 
246   EXPECT_EQ(
247       r()->error(),
248       R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
249 56:78 note: while instantiating variable g)");
250 }
251 
TEST_F(ResolverStorageClassValidationTest,UniformBufferNoBlockDecoration)252 TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
253   // struct S { x : i32 };
254   // var<uniform> g : S;
255   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
256   Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform,
257          ast::DecorationList{
258              create<ast::BindingDecoration>(0),
259              create<ast::GroupDecoration>(0),
260          });
261 
262   ASSERT_FALSE(r()->Resolve());
263 
264   EXPECT_EQ(
265       r()->error(),
266       R"(12:34 error: structure used as a uniform buffer must be declared with the [[block]] decoration
267 56:78 note: structure used as uniform buffer here)");
268 }
269 
TEST_F(ResolverStorageClassValidationTest,UniformBufferNoError_Basic)270 TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
271   // [[block]] struct S { x : i32 };
272   // var<uniform> g :  S;
273   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
274                       {create<ast::StructBlockDecoration>()});
275   Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform,
276          ast::DecorationList{
277              create<ast::BindingDecoration>(0),
278              create<ast::GroupDecoration>(0),
279          });
280 
281   ASSERT_TRUE(r()->Resolve()) << r()->error();
282 }
283 
TEST_F(ResolverStorageClassValidationTest,UniformBufferNoError_Aliases)284 TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
285   // [[block]] struct S { x : i32 };
286   // type a1 = S;
287   // var<uniform> g : a1;
288   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
289                       {create<ast::StructBlockDecoration>()});
290   auto* a1 = Alias("a1", ty.Of(s));
291   Global(Source{{56, 78}}, "g", ty.Of(a1), ast::StorageClass::kUniform,
292          ast::DecorationList{
293              create<ast::BindingDecoration>(0),
294              create<ast::GroupDecoration>(0),
295          });
296 
297   ASSERT_TRUE(r()->Resolve()) << r()->error();
298 }
299 
300 }  // namespace
301 }  // namespace resolver
302 }  // namespace tint
303