validation: disallow atomic type constructors

The type of a type constructor must be constructible, which forbids
atomics. Add checks for non-constructible types when validating arrays
and structures, and then error on any type that isn't explicitly
matched in the outer function. Replaces the separate check for
pointers, which is no longer necessary.

This also removes the validation for "an expression must not evaluate
to an atomic type". The only test that we had for this is no longer
valid (since the type constructor it used is now rejected). There are
no other ways of hitting this particular error, since other validation
rules will always kick in first.

Change-Id: I2172b57ee4e8ee3066aaf0cedc4a26aaca642376
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/61800
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
This commit is contained in:
James Price 2021-08-13 15:20:42 +00:00
parent 8094553c8a
commit cbbb420952
4 changed files with 51 additions and 21 deletions

View File

@ -327,14 +327,6 @@ TEST_F(ResolverAtomicValidationTest, Local) {
"12:34 error: function variable must have a constructible type"); "12:34 error: function variable must have a constructible type");
} }
TEST_F(ResolverAtomicValidationTest, NoAtomicExpr) {
WrapInFunction(Construct(Source{{12, 34}}, ty.atomic<u32>()));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: an expression must not evaluate to an atomic type");
}
} // namespace } // namespace
} // namespace resolver } // namespace resolver
} // namespace tint } // namespace tint

View File

@ -2241,13 +2241,6 @@ bool Resolver::Expression(ast::Expression* expr) {
return false; return false;
} }
auto* ty = TypeOf(expr);
if (ty->Is<sem::Atomic>()) {
AddError("an expression must not evaluate to an atomic type",
expr->source());
return false;
}
return true; return true;
} }
@ -2600,11 +2593,6 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
// Now that the argument types have been determined, make sure that they // Now that the argument types have been determined, make sure that they
// obey the constructor type rules laid out in // obey the constructor type rules laid out in
// https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr. // https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
if (type->Is<sem::Pointer>()) {
AddError("cannot cast to a pointer", expr->source());
return false;
}
bool ok = true; bool ok = true;
if (auto* vec_type = type->As<sem::Vector>()) { if (auto* vec_type = type->As<sem::Vector>()) {
ok = ValidateVectorConstructor(type_ctor, vec_type, type_name); ok = ValidateVectorConstructor(type_ctor, vec_type, type_name);
@ -2616,6 +2604,9 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
ok = ValidateArrayConstructor(type_ctor, arr_type); ok = ValidateArrayConstructor(type_ctor, arr_type);
} else if (auto* struct_type = type->As<sem::Struct>()) { } else if (auto* struct_type = type->As<sem::Struct>()) {
ok = ValidateStructureConstructor(type_ctor, struct_type); ok = ValidateStructureConstructor(type_ctor, struct_type);
} else {
AddError("type is not constructible", type_ctor->source());
return false;
} }
if (!ok) { if (!ok) {
return false; return false;
@ -2641,6 +2632,11 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
bool Resolver::ValidateStructureConstructor( bool Resolver::ValidateStructureConstructor(
const ast::TypeConstructorExpression* ctor, const ast::TypeConstructorExpression* ctor,
const sem::Struct* struct_type) { const sem::Struct* struct_type) {
if (!struct_type->IsConstructible()) {
AddError("struct constructor has non-constructible type", ctor->source());
return false;
}
if (ctor->values().size() > 0) { if (ctor->values().size() > 0) {
if (ctor->values().size() != struct_type->Members().size()) { if (ctor->values().size() != struct_type->Members().size()) {
std::string fm = ctor->values().size() < struct_type->Members().size() std::string fm = ctor->values().size() < struct_type->Members().size()
@ -2689,6 +2685,10 @@ bool Resolver::ValidateArrayConstructor(
if (array_type->IsRuntimeSized()) { if (array_type->IsRuntimeSized()) {
AddError("cannot init a runtime-sized array", ctor->source()); AddError("cannot init a runtime-sized array", ctor->source());
return false; return false;
} else if (!elem_type->IsConstructible()) {
AddError("array constructor has non-constructible element type",
ctor->type()->As<ast::Array>()->type()->source());
return false;
} else if (!values.empty() && (values.size() != array_type->Count())) { } else if (!values.empty() && (values.size() != array_type->Count())) {
std::string fm = values.size() < array_type->Count() ? "few" : "many"; std::string fm = values.size() < array_type->Count() ? "few" : "many";
AddError("array constructor has too " + fm + " elements: expected " + AddError("array constructor has too " + fm + " elements: expected " +

View File

@ -2148,6 +2148,44 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Empty) {
} }
} // namespace StructConstructor } // namespace StructConstructor
TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Atomic) {
WrapInFunction(
Call("ignore", Construct(Source{{12, 34}}, ty.atomic(ty.i32()))));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
}
TEST_F(ResolverTypeConstructorValidationTest,
NonConstructibleType_AtomicArray) {
WrapInFunction(Call(
"ignore", Construct(ty.array(ty.atomic(Source{{12, 34}}, ty.i32()), 4))));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: array constructor has non-constructible element type");
}
TEST_F(ResolverTypeConstructorValidationTest,
NonConstructibleType_AtomicStructMember) {
auto* str = Structure("S", {Member("a", ty.atomic(ty.i32()))});
WrapInFunction(Call("ignore", Construct(Source{{12, 34}}, ty.Of(str))));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: struct constructor has non-constructible type");
}
TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Sampler) {
WrapInFunction(Call(
"ignore",
Construct(Source{{12, 34}}, ty.sampler(ast::SamplerKind::kSampler))));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
}
} // namespace } // namespace
} // namespace resolver } // namespace resolver
} // namespace tint } // namespace tint

View File

@ -919,7 +919,7 @@ TEST_F(ResolverTest, Expr_Constructor_Cast_Pointer) {
WrapInFunction(Decl(vf), Decl(ip)); WrapInFunction(Decl(vf), Decl(ip));
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: cannot cast to a pointer"); EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
} }
} // namespace } // namespace