Validate sign of RHS matches LHS for scalar variable declarations
Statements like `var u : u32 = 0;` should fail because '0' is a signed
integer being used to initialize an unsigned variable.
Added test.
Bug: tint:79
Change-Id: I34f6d21b4355167f49f9a8b5d4ed34a808823185
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42702
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/ast/module_clone_test.cc b/src/ast/module_clone_test.cc
index 7ed6be0..22ffbb9 100644
--- a/src/ast/module_clone_test.cc
+++ b/src/ast/module_clone_test.cc
@@ -68,7 +68,7 @@
fn f1(p0 : f32, p1 : i32) -> f32 {
var l0 : i32 = 3;
- var l1 : f32 = 8;
+ var l1 : f32 = 8.0;
var l2 : u32 = bitcast<u32>(4);
var l3 : vec2<u32> = vec2<u32>(l0, l1);
var l4 : S;
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 9f8427a..8861cdb 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -194,6 +194,12 @@
bool TypeDeterminer::DetermineStatements(const ast::BlockStatement* stmts) {
for (auto* stmt : *stmts) {
+ if (auto* decl = stmt->As<ast::VariableDeclStatement>()) {
+ if (!ValidateVariableDeclStatement(decl)) {
+ return false;
+ }
+ }
+
if (!DetermineVariableStorageClass(stmt)) {
return false;
}
@@ -937,6 +943,28 @@
return true;
}
+bool TypeDeterminer::ValidateVariableDeclStatement(
+ const ast::VariableDeclStatement* stmt) {
+ auto* ctor = stmt->variable()->constructor();
+ if (!ctor) {
+ return true;
+ }
+
+ if (auto* sce = ctor->As<ast::ScalarConstructorExpression>()) {
+ auto* lhs_type = stmt->variable()->type()->UnwrapAliasIfNeeded();
+ auto* rhs_type = sce->literal()->type()->UnwrapAliasIfNeeded();
+
+ if (lhs_type != rhs_type) {
+ diagnostics_.add_error(
+ "constructor expression type does not match variable type",
+ stmt->source());
+ return false;
+ }
+ }
+
+ return true;
+}
+
TypeDeterminer::VariableInfo* TypeDeterminer::CreateVariableInfo(
ast::Variable* var) {
auto* info = variable_infos_.Create(var);
diff --git a/src/type_determiner.h b/src/type_determiner.h
index 8f0802a..fb1b7a9 100644
--- a/src/type_determiner.h
+++ b/src/type_determiner.h
@@ -175,6 +175,8 @@
bool DetermineMemberAccessor(ast::MemberAccessorExpression* expr);
bool DetermineUnaryOp(ast::UnaryOpExpression* expr);
+ bool ValidateVariableDeclStatement(const ast::VariableDeclStatement* stmt);
+
VariableInfo* CreateVariableInfo(ast::Variable*);
/// @returns the resolved type of the ast::Expression `expr`
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 9ae97b5..0c118a2 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -437,6 +437,52 @@
EXPECT_TRUE(TypeOf(init)->Is<type::I32>());
}
+TEST_F(TypeDeterminerTest, Stmt_VariableDecl_Alias) {
+ auto* my_int = ty.alias("MyInt", ty.i32());
+ auto* var = Var("my_var", my_int, ast::StorageClass::kNone, Expr(2));
+ auto* init = var->constructor();
+
+ auto* decl = create<ast::VariableDeclStatement>(var);
+ WrapInFunction(decl);
+
+ EXPECT_TRUE(td()->Determine()) << td()->error();
+
+ ASSERT_NE(TypeOf(init), nullptr);
+ EXPECT_TRUE(TypeOf(init)->Is<type::I32>());
+}
+
+TEST_F(TypeDeterminerTest, Stmt_VariableDecl_MismatchedTypeScalarConstructor) {
+ u32 unsigned_value = 2u; // Type does not match variable type
+ auto* var =
+ Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(unsigned_value));
+
+ auto* decl =
+ create<ast::VariableDeclStatement>(Source{{{3, 3}, {3, 22}}}, var);
+ WrapInFunction(decl);
+
+ EXPECT_FALSE(td()->Determine());
+ EXPECT_EQ(
+ td()->error(),
+ R"(3:3 error: constructor expression type does not match variable type)");
+}
+
+TEST_F(TypeDeterminerTest,
+ Stmt_VariableDecl_MismatchedTypeScalarConstructor_Alias) {
+ auto* my_int = ty.alias("MyInt", ty.i32());
+ u32 unsigned_value = 2u; // Type does not match variable type
+ auto* var =
+ Var("my_var", my_int, ast::StorageClass::kNone, Expr(unsigned_value));
+
+ auto* decl =
+ create<ast::VariableDeclStatement>(Source{{{3, 3}, {3, 22}}}, var);
+ WrapInFunction(decl);
+
+ EXPECT_FALSE(td()->Determine());
+ EXPECT_EQ(
+ td()->error(),
+ R"(3:3 error: constructor expression type does not match variable type)");
+}
+
TEST_F(TypeDeterminerTest, Stmt_VariableDecl_ModuleScope) {
auto* init = Expr(2);
Global("my_var", ty.i32(), ast::StorageClass::kNone, init);
diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc
index e486543..8b38d07 100644
--- a/src/validator/validator_test.cc
+++ b/src/validator/validator_test.cc
@@ -792,7 +792,7 @@
// func1 { var a : f32 = 3.0; return; }
auto* var0 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
- auto* var1 = Var("a", ty.void_(), ast::StorageClass::kNone, Expr(1.0f));
+ auto* var1 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1.0f));
Func("func0", ast::VariableList{}, ty.void_(),
ast::StatementList{