dawn-cmake/src/ast/function_test.cc
Ben Clayton 93e8f527ee wgsl: Deprecate [[access]] decorations
Handle access control on var declarations instead of via [[access]]
decorations. This change does the minimal work to migrate the WGSL
parser over to the new syntax. Additional changes will be needed
to correctly generate defaulted access qualifiers, as well as
validating access usage.

The [[access]] decorations are still supported by the WGSL parser,
with new deprecated warnings, but not for aliases. Example:
   var x : [[access(x)]] alias_to_struct;

Making this work is far more effort than I want to dedicate to backwards
compatibility, and I do not beleive any real-world usage will be doing
this.

Still TODO:
* Adding access control as the optional, third parameter to ptr<>.
* Calculating default accesses for the various storage types.
* Validating usage of variables against the different accesses.

Bug: tint:846
Change-Id: If8ca82e5d16ec319ecd01f9a2cafffd930963bde
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53088
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
2021-06-04 20:41:47 +00:00

288 lines
7.8 KiB
C++

// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gtest/gtest-spi.h"
#include "src/ast/discard_statement.h"
#include "src/ast/stage_decoration.h"
#include "src/ast/test_helper.h"
#include "src/ast/workgroup_decoration.h"
namespace tint {
namespace ast {
namespace {
using FunctionTest = TestHelper;
TEST_F(FunctionTest, Creation) {
VariableList params;
params.push_back(Param("var", ty.i32()));
auto* var = params[0];
auto* f = Func("func", params, ty.void_(), StatementList{}, DecorationList{});
EXPECT_EQ(f->symbol(), Symbols().Get("func"));
ASSERT_EQ(f->params().size(), 1u);
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
EXPECT_EQ(f->params()[0], var);
}
TEST_F(FunctionTest, Creation_WithSource) {
VariableList params;
params.push_back(Param("var", ty.i32()));
auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(),
StatementList{}, DecorationList{});
auto src = f->source();
EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u);
}
TEST_F(FunctionTest, Assert_InvalidName) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.Func("", VariableList{}, b.ty.void_(), StatementList{},
DecorationList{});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_Null_ReturnType) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.Func("f", VariableList{}, nullptr, StatementList{}, DecorationList{});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_Null_Param) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
VariableList params;
params.push_back(b.Param("var", b.ty.i32()));
params.push_back(nullptr);
b.Func("f", params, b.ty.void_(), StatementList{}, DecorationList{});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_DifferentProgramID_Symbol) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.Func(b2.Sym("func"), VariableList{}, b1.ty.void_(), StatementList{});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_DifferentProgramID_Param) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.Func("func", VariableList{b2.Param("var", b2.ty.i32())},
b1.ty.void_(), StatementList{});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_DifferentProgramID_Deco) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{},
DecorationList{
b2.WorkgroupSize(2, 4, 6),
});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnDeco) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{},
DecorationList{},
DecorationList{
b2.WorkgroupSize(2, 4, 6),
});
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_NonConstParam) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
VariableList params;
params.push_back(b.Var("var", b.ty.i32(), ast::StorageClass::kNone));
b.Func("f", params, b.ty.void_(), StatementList{}, DecorationList{});
},
"internal compiler error");
}
TEST_F(FunctionTest, ToStr) {
auto* f = Func("func", VariableList{}, ty.void_(),
StatementList{
create<DiscardStatement>(),
},
DecorationList{});
EXPECT_EQ(str(f), R"(Function func -> __void
()
{
Discard{}
}
)");
}
TEST_F(FunctionTest, ToStr_WithDecoration) {
auto* f = Func("func", VariableList{}, ty.void_(),
StatementList{
create<DiscardStatement>(),
},
DecorationList{WorkgroupSize(2, 4, 6)});
EXPECT_EQ(str(f), R"(Function func -> __void
WorkgroupDecoration{
ScalarConstructor[not set]{2}
ScalarConstructor[not set]{4}
ScalarConstructor[not set]{6}
}
()
{
Discard{}
}
)");
}
TEST_F(FunctionTest, ToStr_WithParams) {
VariableList params;
params.push_back(Param("var", ty.i32()));
auto* f = Func("func", params, ty.void_(),
StatementList{
create<DiscardStatement>(),
},
DecorationList{});
EXPECT_EQ(str(f), R"(Function func -> __void
(
VariableConst{
var
none
undefined
__i32
}
)
{
Discard{}
}
)");
}
TEST_F(FunctionTest, TypeName) {
auto* f = Func("func", VariableList{}, ty.void_(), StatementList{},
DecorationList{});
EXPECT_EQ(f->type_name(), "__func__void");
}
TEST_F(FunctionTest, TypeName_WithParams) {
VariableList params;
params.push_back(Param("var1", ty.i32()));
params.push_back(Param("var2", ty.f32()));
auto* f = Func("func", params, ty.void_(), StatementList{}, DecorationList{});
EXPECT_EQ(f->type_name(), "__func__void__i32__f32");
}
TEST_F(FunctionTest, GetLastStatement) {
VariableList params;
auto* stmt = create<DiscardStatement>();
auto* f =
Func("func", params, ty.void_(), StatementList{stmt}, DecorationList{});
EXPECT_EQ(f->get_last_statement(), stmt);
}
TEST_F(FunctionTest, GetLastStatement_nullptr) {
VariableList params;
auto* f = Func("func", params, ty.void_(), StatementList{}, DecorationList{});
EXPECT_EQ(f->get_last_statement(), nullptr);
}
using FunctionListTest = TestHelper;
TEST_F(FunctionListTest, FindSymbol) {
auto* func = Func("main", VariableList{}, ty.f32(), StatementList{},
ast::DecorationList{});
FunctionList list;
list.Add(func);
EXPECT_EQ(func, list.Find(Symbols().Register("main")));
}
TEST_F(FunctionListTest, FindSymbolMissing) {
FunctionList list;
EXPECT_EQ(nullptr, list.Find(Symbols().Register("Missing")));
}
TEST_F(FunctionListTest, FindSymbolStage) {
auto* fs = Func("main", VariableList{}, ty.f32(), StatementList{},
ast::DecorationList{
Stage(PipelineStage::kFragment),
});
auto* vs = Func("main", VariableList{}, ty.f32(), StatementList{},
ast::DecorationList{
Stage(PipelineStage::kVertex),
});
FunctionList list;
list.Add(fs);
list.Add(vs);
EXPECT_EQ(fs,
list.Find(Symbols().Register("main"), PipelineStage::kFragment));
EXPECT_EQ(vs, list.Find(Symbols().Register("main"), PipelineStage::kVertex));
}
TEST_F(FunctionListTest, FindSymbolStageMissing) {
FunctionList list;
list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
ast::DecorationList{
Stage(PipelineStage::kFragment),
}));
EXPECT_EQ(nullptr,
list.Find(Symbols().Register("main"), PipelineStage::kVertex));
}
TEST_F(FunctionListTest, HasStage) {
FunctionList list;
list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
ast::DecorationList{
Stage(PipelineStage::kFragment),
}));
EXPECT_TRUE(list.HasStage(PipelineStage::kFragment));
EXPECT_FALSE(list.HasStage(PipelineStage::kVertex));
}
} // namespace
} // namespace ast
} // namespace tint