validator: Require constants to have initializers
Unless they are pipeline overridable. Fixed several tests that were violating this. Change-Id: Ibb10e03bb150086a4d9e68a3f7b2d3e21f282918 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50042 Commit-Queue: James Price <jrprice@google.com> Auto-Submit: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
ab3a9218b7
commit
08df57a75c
|
@ -522,6 +522,13 @@ bool Resolver::GlobalVariable(ast::Variable* var) {
|
||||||
if (!Expression(var->constructor())) {
|
if (!Expression(var->constructor())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (var->is_const() &&
|
||||||
|
!ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
|
||||||
|
diagnostics_.add_error("let declarations must have initializers",
|
||||||
|
var->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateGlobalVariable(info)) {
|
if (!ValidateGlobalVariable(info)) {
|
||||||
|
@ -2063,6 +2070,12 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
stmt->source());
|
stmt->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (stmt->variable()->is_const()) {
|
||||||
|
diagnostics_.add_error("let declarations must have initializers",
|
||||||
|
var->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* deco : var->decorations()) {
|
for (auto* deco : var->decorations()) {
|
||||||
|
|
|
@ -426,7 +426,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Alias_Array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_ArrayAccessor_Array_Constant) {
|
TEST_F(ResolverTest, Expr_ArrayAccessor_Array_Constant) {
|
||||||
GlobalConst("my_var", ty.array<f32, 3>());
|
GlobalConst("my_var", ty.array<f32, 3>(), array<f32, 3>());
|
||||||
|
|
||||||
auto* acc = IndexAccessor("my_var", 2);
|
auto* acc = IndexAccessor("my_var", 2);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
|
@ -624,7 +624,7 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
|
TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
|
||||||
auto* my_var = GlobalConst("my_var", ty.f32());
|
auto* my_var = GlobalConst("my_var", ty.f32(), Construct(ty.f32()));
|
||||||
|
|
||||||
auto* ident = Expr("my_var");
|
auto* ident = Expr("my_var");
|
||||||
WrapInFunction(ident);
|
WrapInFunction(ident);
|
||||||
|
@ -640,7 +640,7 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
|
TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
|
||||||
auto* my_var_a = Expr("my_var");
|
auto* my_var_a = Expr("my_var");
|
||||||
auto* var = Const("my_var", ty.f32());
|
auto* var = Const("my_var", ty.f32(), Construct(ty.f32()));
|
||||||
auto* decl = Decl(Var("b", ty.f32(), ast::StorageClass::kFunction, my_var_a));
|
auto* decl = Decl(Var("b", ty.f32(), ast::StorageClass::kFunction, my_var_a));
|
||||||
|
|
||||||
Func("my_func", ast::VariableList{}, ty.void_(),
|
Func("my_func", ast::VariableList{}, ty.void_(),
|
||||||
|
@ -1457,7 +1457,7 @@ TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
|
TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
|
||||||
auto* var = Const("var", ty.i32());
|
auto* var = Const("var", ty.i32(), Construct(ty.i32()));
|
||||||
auto* stmt = Decl(var);
|
auto* stmt = Decl(var);
|
||||||
Func("func", ast::VariableList{}, ty.void_(), ast::StatementList{stmt},
|
Func("func", ast::VariableList{}, ty.void_(), ast::StatementList{stmt},
|
||||||
ast::DecorationList{});
|
ast::DecorationList{});
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "src/ast/override_decoration.h"
|
||||||
#include "src/ast/return_statement.h"
|
#include "src/ast/return_statement.h"
|
||||||
#include "src/ast/stage_decoration.h"
|
#include "src/ast/stage_decoration.h"
|
||||||
#include "src/ast/struct_block_decoration.h"
|
#include "src/ast/struct_block_decoration.h"
|
||||||
|
@ -49,6 +50,35 @@ TEST_F(ResolverTypeValidationTest, VariableDeclNoConstructor_Pass) {
|
||||||
ASSERT_NE(TypeOf(rhs), nullptr);
|
ASSERT_NE(TypeOf(rhs), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTypeValidationTest, FunctionConstantNoConstructor_Fail) {
|
||||||
|
// {
|
||||||
|
// let a :i32;
|
||||||
|
// }
|
||||||
|
auto* var = Const(Source{{12, 34}}, "a", ty.i32(), nullptr);
|
||||||
|
WrapInFunction(var);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"12:34 error: let declarations must have initializers");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Fail) {
|
||||||
|
// let a :i32;
|
||||||
|
GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"12:34 error: let declarations must have initializers");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Pass) {
|
||||||
|
// [[override(0)]] let a :i32;
|
||||||
|
GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr,
|
||||||
|
ast::DecorationList{create<ast::OverrideDecoration>(0)});
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
|
TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
|
||||||
// var<in> global_var: f32;
|
// var<in> global_var: f32;
|
||||||
Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kInput);
|
Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kInput);
|
||||||
|
@ -71,7 +101,7 @@ TEST_F(ResolverTypeValidationTest, GlobalConstantWithStorageClass_Fail) {
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
|
TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
|
||||||
// let global_var: f32;
|
// let global_var: f32;
|
||||||
GlobalConst(Source{{12, 34}}, "global_var", ty.f32());
|
GlobalConst(Source{{12, 34}}, "global_var", ty.f32(), Construct(ty.f32()));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,10 @@ static const float pos = WGSL_SPEC_CONSTANT_23;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
|
TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
|
||||||
auto* var = Const("pos", ty.f32(), nullptr,
|
auto* var = GlobalConst("pos", ty.f32(), nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::OverrideDecoration>(23),
|
create<ast::OverrideDecoration>(23),
|
||||||
});
|
});
|
||||||
WrapInFunction(Decl(var));
|
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
|
TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
|
||||||
auto* var = Const("a", ty.f32());
|
auto* var = Const("a", ty.f32(), Construct(ty.f32()));
|
||||||
auto* stmt = Decl(var);
|
auto* stmt = Decl(var);
|
||||||
WrapInFunction(stmt);
|
WrapInFunction(stmt);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
|
||||||
gen.increment_indent();
|
gen.increment_indent();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
|
ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
|
||||||
EXPECT_EQ(result(), " const float a;\n");
|
EXPECT_EQ(result(), " const float a = 0.0f;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
|
TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
|
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
|
||||||
auto* var = Const("a", ty.f32());
|
auto* var = Const("a", ty.f32(), Construct(ty.f32()));
|
||||||
auto* stmt = Decl(var);
|
auto* stmt = Decl(var);
|
||||||
WrapInFunction(stmt);
|
WrapInFunction(stmt);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
|
||||||
gen.increment_indent();
|
gen.increment_indent();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
|
ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
|
||||||
EXPECT_EQ(gen.result(), " const float a = 0.0f;\n");
|
EXPECT_EQ(gen.result(), " const float a = float(0.0f);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
|
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
|
||||||
|
|
Loading…
Reference in New Issue