validation: unary operands
logical negation operand must be 'bool' or 'vecN<bool>' complement operand must be be 'i32', 'u32', 'vecN<i32>' or 'vecN<u32>' Negation operand must be 'i32', 'f32', 'vecN<i32>' or 'vecN<f32>' Bug: tint:916 chromium:1216597 Change-Id: Ic88a124a32d16b542560da3ca1c159968d4043a0 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/55860 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
ac5dbd2d0f
commit
a5715e3320
|
@ -2733,12 +2733,41 @@ bool Resolver::UnaryOp(ast::UnaryOpExpression* unary) {
|
||||||
const sem::Type* type = nullptr;
|
const sem::Type* type = nullptr;
|
||||||
|
|
||||||
switch (unary->op()) {
|
switch (unary->op()) {
|
||||||
case ast::UnaryOp::kComplement:
|
|
||||||
case ast::UnaryOp::kNegation:
|
|
||||||
case ast::UnaryOp::kNot:
|
case ast::UnaryOp::kNot:
|
||||||
// Result type matches the deref'd inner type.
|
// Result type matches the deref'd inner type.
|
||||||
type_name = TypeNameOf(unary->expr());
|
type_name = TypeNameOf(unary->expr());
|
||||||
type = expr_type->UnwrapRef();
|
type = expr_type->UnwrapRef();
|
||||||
|
if (!type->Is<sem::Bool>() && !type->is_bool_vector()) {
|
||||||
|
AddError("cannot logical negate expression of type '" +
|
||||||
|
TypeNameOf(unary->expr()),
|
||||||
|
unary->expr()->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ast::UnaryOp::kComplement:
|
||||||
|
// Result type matches the deref'd inner type.
|
||||||
|
type_name = TypeNameOf(unary->expr());
|
||||||
|
type = expr_type->UnwrapRef();
|
||||||
|
if (!type->is_integer_scalar_or_vector()) {
|
||||||
|
AddError("cannot bitwise complement expression of type '" +
|
||||||
|
TypeNameOf(unary->expr()),
|
||||||
|
unary->expr()->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ast::UnaryOp::kNegation:
|
||||||
|
// Result type matches the deref'd inner type.
|
||||||
|
type_name = TypeNameOf(unary->expr());
|
||||||
|
type = expr_type->UnwrapRef();
|
||||||
|
if (!(type->IsAnyOf<sem::F32, sem::I32>() ||
|
||||||
|
type->is_signed_integer_vector() || type->is_float_vector())) {
|
||||||
|
AddError(
|
||||||
|
"cannot negate expression of type '" + TypeNameOf(unary->expr()),
|
||||||
|
unary->expr()->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ast::UnaryOp::kAddressOf:
|
case ast::UnaryOp::kAddressOf:
|
||||||
|
|
|
@ -1917,7 +1917,13 @@ using UnaryOpExpressionTest = ResolverTestWithParam<ast::UnaryOp>;
|
||||||
TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
|
TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
|
||||||
auto op = GetParam();
|
auto op = GetParam();
|
||||||
|
|
||||||
Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
if (op == ast::UnaryOp::kNot) {
|
||||||
|
Global("ident", ty.vec4<bool>(), ast::StorageClass::kPrivate);
|
||||||
|
} else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
|
||||||
|
Global("ident", ty.vec4<i32>(), ast::StorageClass::kPrivate);
|
||||||
|
} else {
|
||||||
|
Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
||||||
|
}
|
||||||
auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
|
auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
|
||||||
WrapInFunction(der);
|
WrapInFunction(der);
|
||||||
|
|
||||||
|
@ -1925,7 +1931,13 @@ TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
|
||||||
|
|
||||||
ASSERT_NE(TypeOf(der), nullptr);
|
ASSERT_NE(TypeOf(der), nullptr);
|
||||||
ASSERT_TRUE(TypeOf(der)->Is<sem::Vector>());
|
ASSERT_TRUE(TypeOf(der)->Is<sem::Vector>());
|
||||||
EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::F32>());
|
if (op == ast::UnaryOp::kNot) {
|
||||||
|
EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::Bool>());
|
||||||
|
} else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
|
||||||
|
EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::I32>());
|
||||||
|
} else {
|
||||||
|
EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||||
|
}
|
||||||
EXPECT_EQ(TypeOf(der)->As<sem::Vector>()->size(), 4u);
|
EXPECT_EQ(TypeOf(der)->As<sem::Vector>()->size(), 4u);
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
||||||
|
@ -2181,6 +2193,38 @@ TEST_F(ResolverTest, ASTNodeReachedTwice) {
|
||||||
"encountered twice in the same AST of a Program");
|
"encountered twice in the same AST of a Program");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, UnaryOp_Not) {
|
||||||
|
Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
||||||
|
auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot,
|
||||||
|
Expr(Source{{12, 34}}, "ident"));
|
||||||
|
WrapInFunction(der);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"12:34 error: cannot logical negate expression of type 'vec4<f32>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, UnaryOp_Complement) {
|
||||||
|
Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
||||||
|
auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement,
|
||||||
|
Expr(Source{{12, 34}}, "ident"));
|
||||||
|
WrapInFunction(der);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
"12:34 error: cannot bitwise complement expression of type 'vec4<f32>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, UnaryOp_Negation) {
|
||||||
|
Global("ident", ty.u32(), ast::StorageClass::kPrivate);
|
||||||
|
auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation,
|
||||||
|
Expr(Source{{12, 34}}, "ident"));
|
||||||
|
WrapInFunction(der);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: cannot negate expression of type 'u32");
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace resolver
|
} // namespace resolver
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -35,7 +35,7 @@ TEST_F(HlslUnaryOpTest, AddressOf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslUnaryOpTest, Complement) {
|
TEST_F(HlslUnaryOpTest, Complement) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.u32(), ast::StorageClass::kPrivate);
|
||||||
auto* op =
|
auto* op =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
@ -64,7 +64,7 @@ TEST_F(HlslUnaryOpTest, Indirection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslUnaryOpTest, Not) {
|
TEST_F(HlslUnaryOpTest, Not) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
|
||||||
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
|
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ TEST_F(HlslUnaryOpTest, Not) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslUnaryOpTest, Negation) {
|
TEST_F(HlslUnaryOpTest, Negation) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.i32(), ast::StorageClass::kPrivate);
|
||||||
auto* op =
|
auto* op =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(MslUnaryOpTest, AddressOf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslUnaryOpTest, Complement) {
|
TEST_F(MslUnaryOpTest, Complement) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.i32(), ast::StorageClass::kPrivate);
|
||||||
auto* op =
|
auto* op =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
@ -61,7 +61,7 @@ TEST_F(MslUnaryOpTest, Indirection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslUnaryOpTest, Not) {
|
TEST_F(MslUnaryOpTest, Not) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
|
||||||
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
|
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ TEST_F(MslUnaryOpTest, Not) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslUnaryOpTest, Negation) {
|
TEST_F(MslUnaryOpTest, Negation) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.i32(), ast::StorageClass::kPrivate);
|
||||||
auto* op =
|
auto* op =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(WgslUnaryOpTest, AddressOf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslUnaryOpTest, Complement) {
|
TEST_F(WgslUnaryOpTest, Complement) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.u32(), ast::StorageClass::kPrivate);
|
||||||
auto* op =
|
auto* op =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
@ -61,7 +61,7 @@ TEST_F(WgslUnaryOpTest, Indirection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslUnaryOpTest, Not) {
|
TEST_F(WgslUnaryOpTest, Not) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
|
||||||
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
|
auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ TEST_F(WgslUnaryOpTest, Not) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslUnaryOpTest, Negation) {
|
TEST_F(WgslUnaryOpTest, Negation) {
|
||||||
Global("expr", ty.f32(), ast::StorageClass::kPrivate);
|
Global("expr", ty.i32(), ast::StorageClass::kPrivate);
|
||||||
auto* op =
|
auto* op =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
|
||||||
WrapInFunction(op);
|
WrapInFunction(op);
|
||||||
|
|
Loading…
Reference in New Issue