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>
This commit is contained in:
Antonio Maiorano 2021-02-26 18:25:56 +00:00 committed by Commit Bot service account
parent e5c105d40a
commit 6ce2edfa1f
5 changed files with 78 additions and 2 deletions

View File

@ -68,7 +68,7 @@ fn f0(p0 : bool) -> f32 {
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;

View File

@ -194,6 +194,12 @@ bool TypeDeterminer::DetermineFunction(ast::Function* func) {
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 @@ bool TypeDeterminer::DetermineUnaryOp(ast::UnaryOpExpression* expr) {
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);

View File

@ -175,6 +175,8 @@ class TypeDeterminer {
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`

View File

@ -437,6 +437,52 @@ TEST_F(TypeDeterminerTest, Stmt_VariableDecl) {
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);

View File

@ -792,7 +792,7 @@ TEST_F(ValidatorTest, RedeclaredIdentifierDifferentFunctions_Pass) {
// 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{