Add parsing and emission of the `must_use` attribute.

This CL adds parsing of the `@must_use` attribute into the WGSL parser. The WGSL
generator is also updated to emit the attribute.

Bug: tint:1844
Change-Id: If8821c9ac534b866cbe042128a00a582a245c3de
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/120821
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair 2023-02-22 13:36:01 +00:00 committed by Dawn LUCI CQ
parent dd57720d14
commit ce10962d82
7 changed files with 97 additions and 3 deletions

View File

@ -2931,6 +2931,7 @@ Expect<const ast::Attribute*> ParserImpl::expect_attribute() {
// interpolation_sample_name COMMA? PAREN_RIGHT // interpolation_sample_name COMMA? PAREN_RIGHT
// | ATTR 'invariant' // | ATTR 'invariant'
// | ATTR 'location' PAREN_LEFT expression COMMA? PAREN_RIGHT // | ATTR 'location' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'must_use'
// | ATTR 'size' PAREN_LEFT expression COMMA? PAREN_RIGHT // | ATTR 'size' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA? PAREN_RIGHT // | ATTR 'workgroup_size' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA? PAREN_RIGHT // | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA? PAREN_RIGHT
@ -3085,6 +3086,10 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
}); });
} }
if (t == "must_use") {
return create<ast::MustUseAttribute>(t.source());
}
if (t == "size") { if (t == "size") {
const char* use = "size attribute"; const char* use = "size attribute";
return expect_paren_block(use, [&]() -> Result { return expect_paren_block(use, [&]() -> Result {

View File

@ -435,5 +435,17 @@ TEST_F(ParserImplTest, Attribute_Fragment) {
EXPECT_EQ(func_attr->As<ast::StageAttribute>()->stage, ast::PipelineStage::kFragment); EXPECT_EQ(func_attr->As<ast::StageAttribute>()->stage, ast::PipelineStage::kFragment);
} }
TEST_F(ParserImplTest, Attribute_MustUse) {
auto p = parser("must_use");
auto attr = p->attribute();
EXPECT_TRUE(attr.matched);
EXPECT_FALSE(attr.errored);
ASSERT_NE(attr.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
auto* func_attr = attr.value->As<ast::Attribute>();
ASSERT_NE(func_attr, nullptr);
EXPECT_TRUE(func_attr->Is<ast::MustUseAttribute>());
}
} // namespace } // namespace
} // namespace tint::reader::wgsl } // namespace tint::reader::wgsl

View File

@ -262,6 +262,23 @@ TEST_F(ParserImplTest, FunctionDecl_ReturnTypeAttributeList) {
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }
TEST_F(ParserImplTest, FunctionDecl_MustUse) {
auto p = parser("@must_use fn main() { return; }");
auto attrs = p->attribute_list();
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(attrs.errored);
ASSERT_TRUE(attrs.matched);
auto f = p->function_decl(attrs.value);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(f.errored);
EXPECT_TRUE(f.matched);
ASSERT_NE(f.value, nullptr);
auto& attributes = f->attributes;
ASSERT_EQ(attributes.Length(), 1u);
ASSERT_TRUE(attributes[0]->Is<ast::MustUseAttribute>());
}
TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) { TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) {
auto p = parser("fn main() -> { }"); auto p = parser("fn main() -> { }");
auto attrs = p->attribute_list(); auto attrs = p->attribute_list();

View File

@ -61,6 +61,7 @@ enum class AttributeKind {
kInterpolate, kInterpolate,
kInvariant, kInvariant,
kLocation, kLocation,
kMustUse,
kOffset, kOffset,
kSize, kSize,
kStage, kStage,
@ -113,6 +114,8 @@ static utils::Vector<const ast::Attribute*, 2> createAttributes(const Source& so
return {builder.Location(source, 1_a)}; return {builder.Location(source, 1_a)};
case AttributeKind::kOffset: case AttributeKind::kOffset:
return {builder.MemberOffset(source, 4_a)}; return {builder.MemberOffset(source, 4_a)};
case AttributeKind::kMustUse:
return {builder.MustUse(source)};
case AttributeKind::kSize: case AttributeKind::kSize:
return {builder.MemberSize(source, 16_a)}; return {builder.MemberSize(source, 16_a)};
case AttributeKind::kStage: case AttributeKind::kStage:
@ -158,6 +161,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -195,6 +199,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -246,6 +251,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -284,6 +290,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
// kInterpolate tested separately (requires @location) // kInterpolate tested separately (requires @location)
TestParams{AttributeKind::kInvariant, true}, TestParams{AttributeKind::kInvariant, true},
TestParams{AttributeKind::kLocation, true}, TestParams{AttributeKind::kLocation, true},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -338,6 +345,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, true}, TestParams{AttributeKind::kInterpolate, true},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, true}, TestParams{AttributeKind::kLocation, true},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -389,6 +397,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -440,6 +449,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, true}, TestParams{AttributeKind::kInterpolate, true},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -489,6 +499,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
// kInterpolate tested separately (requires @location) // kInterpolate tested separately (requires @location)
TestParams{AttributeKind::kInvariant, true}, TestParams{AttributeKind::kInvariant, true},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -593,6 +604,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -629,6 +641,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
// kInterpolate tested separately (requires @location) // kInterpolate tested separately (requires @location)
// kInvariant tested separately (requires position builtin) // kInvariant tested separately (requires position builtin)
TestParams{AttributeKind::kLocation, true}, TestParams{AttributeKind::kLocation, true},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, true}, TestParams{AttributeKind::kOffset, true},
TestParams{AttributeKind::kSize, true}, TestParams{AttributeKind::kSize, true},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -871,6 +884,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -911,6 +925,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -963,6 +978,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -1007,6 +1023,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -1113,6 +1130,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kInterpolate, false}, TestParams{AttributeKind::kInterpolate, false},
TestParams{AttributeKind::kInvariant, false}, TestParams{AttributeKind::kInvariant, false},
TestParams{AttributeKind::kLocation, false}, TestParams{AttributeKind::kLocation, false},
TestParams{AttributeKind::kMustUse, false},
TestParams{AttributeKind::kOffset, false}, TestParams{AttributeKind::kOffset, false},
TestParams{AttributeKind::kSize, false}, TestParams{AttributeKind::kSize, false},
TestParams{AttributeKind::kStage, false}, TestParams{AttributeKind::kStage, false},
@ -1413,6 +1431,24 @@ TEST_F(InvariantAttributeTests, InvariantWithoutPosition) {
} // namespace } // namespace
} // namespace InvariantAttributeTests } // namespace InvariantAttributeTests
namespace MustUseAttributeTests {
namespace {
using MustUseAttributeTests = ResolverTest;
TEST_F(MustUseAttributeTests, MustUse) {
Func("main", utils::Empty, ty.vec4<f32>(),
utils::Vector{
Return(Call(ty.vec4<f32>())),
},
utils::Vector{
MustUse(Source{{12, 34}}),
});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
} // namespace
} // namespace MustUseAttributeTests
namespace WorkgroupAttributeTests { namespace WorkgroupAttributeTests {
namespace { namespace {

View File

@ -1016,7 +1016,7 @@ bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) co
return false; return false;
} }
} else if (!attr->IsAnyOf<ast::DiagnosticAttribute, ast::StageAttribute, } else if (!attr->IsAnyOf<ast::DiagnosticAttribute, ast::StageAttribute,
ast::InternalAttribute>()) { ast::MustUseAttribute, ast::InternalAttribute>()) {
AddError("attribute is not valid for functions", attr->source); AddError("attribute is not valid for functions", attr->source);
return false; return false;
} }
@ -2544,8 +2544,7 @@ bool Validator::CheckTypeAccessAddressSpace(
} }
if (address_space == builtin::AddressSpace::kStorage && access == builtin::Access::kWrite) { if (address_space == builtin::AddressSpace::kStorage && access == builtin::Access::kWrite) {
// The access mode for the storage address space can only be 'read' or // The access mode for the storage address space can only be 'read' or 'read_write'.
// 'read_write'.
AddError("access mode 'write' is not valid for the 'storage' address space", source); AddError("access mode 'write' is not valid for the 'storage' address space", source);
return false; return false;
} }

View File

@ -600,6 +600,10 @@ bool GeneratorImpl::EmitAttributes(std::ostream& out,
out << ")"; out << ")";
return true; return true;
}, },
[&](const ast::MustUseAttribute*) {
out << "must_use";
return true;
},
[&](const ast::StructMemberOffsetAttribute* offset) { [&](const ast::StructMemberOffsetAttribute* offset) {
out << "offset("; out << "offset(";
if (!EmitExpression(out, offset->expr)) { if (!EmitExpression(out, offset->expr)) {

View File

@ -86,6 +86,27 @@ TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize) {
)"); )");
} }
TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_MustUse) {
auto* func = Func("my_func", utils::Empty, ty.void_(),
utils::Vector{
Return(),
},
utils::Vector{
MustUse(),
});
GeneratorImpl& gen = Build();
gen.increment_indent();
ASSERT_TRUE(gen.EmitFunction(func));
EXPECT_EQ(gen.result(), R"( @must_use
fn my_func() {
return;
}
)");
}
TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIdent) { TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIdent) {
GlobalConst("height", ty.i32(), Expr(2_i)); GlobalConst("height", ty.i32(), Expr(2_i));
auto* func = Func("my_func", utils::Empty, ty.void_(), auto* func = Func("my_func", utils::Empty, ty.void_(),