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:
parent
e5c105d40a
commit
6ce2edfa1f
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Reference in New Issue