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");
}
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 resolver
} // namespace tint

View File

@ -2241,13 +2241,6 @@ bool Resolver::Expression(ast::Expression* expr) {
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;
}
@ -2600,11 +2593,6 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
// Now that the argument types have been determined, make sure that they
// obey the constructor type rules laid out in
// 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;
if (auto* vec_type = type->As<sem::Vector>()) {
ok = ValidateVectorConstructor(type_ctor, vec_type, type_name);
@ -2616,6 +2604,9 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
ok = ValidateArrayConstructor(type_ctor, arr_type);
} else if (auto* struct_type = type->As<sem::Struct>()) {
ok = ValidateStructureConstructor(type_ctor, struct_type);
} else {
AddError("type is not constructible", type_ctor->source());
return false;
}
if (!ok) {
return false;
@ -2641,6 +2632,11 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
bool Resolver::ValidateStructureConstructor(
const ast::TypeConstructorExpression* ctor,
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() != 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()) {
AddError("cannot init a runtime-sized array", ctor->source());
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())) {
std::string fm = values.size() < array_type->Count() ? "few" : "many";
AddError("array constructor has too " + fm + " elements: expected " +

View File

@ -2148,6 +2148,44 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Empty) {
}
} // 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 resolver
} // namespace tint

View File

@ -919,7 +919,7 @@ TEST_F(ResolverTest, Expr_Constructor_Cast_Pointer) {
WrapInFunction(Decl(vf), Decl(ip));
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