resolver: Fix for-loop conditional validation
It wasn't unwrapping the reference before type checking Change-Id: I4bfc038c468c32c2a164bbcbef0a97a3e385d5ba Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/60210 Auto-Submit: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
f5490c732d
commit
ada4864ffe
|
@ -1447,105 +1447,105 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
Source source,
|
Source source,
|
||||||
ParamOrRetType param_or_ret,
|
ParamOrRetType param_or_ret,
|
||||||
bool is_struct_member) {
|
bool is_struct_member) {
|
||||||
// Scan decorations for pipeline IO attributes.
|
// Scan decorations for pipeline IO attributes.
|
||||||
// Check for overlap with attributes that have been seen previously.
|
// Check for overlap with attributes that have been seen previously.
|
||||||
ast::Decoration* pipeline_io_attribute = nullptr;
|
ast::Decoration* pipeline_io_attribute = nullptr;
|
||||||
ast::InvariantDecoration* invariant_attribute = nullptr;
|
ast::InvariantDecoration* invariant_attribute = nullptr;
|
||||||
for (auto* deco : decos) {
|
for (auto* deco : decos) {
|
||||||
auto is_invalid_compute_shader_decoration = false;
|
auto is_invalid_compute_shader_decoration = false;
|
||||||
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
||||||
if (pipeline_io_attribute) {
|
if (pipeline_io_attribute) {
|
||||||
AddError("multiple entry point IO attributes", deco->source());
|
AddError("multiple entry point IO attributes", deco->source());
|
||||||
AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
|
AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
|
||||||
pipeline_io_attribute->source());
|
pipeline_io_attribute->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pipeline_io_attribute = deco;
|
pipeline_io_attribute = deco;
|
||||||
|
|
||||||
if (builtins.count(builtin->value())) {
|
if (builtins.count(builtin->value())) {
|
||||||
AddError(deco_to_str(builtin) +
|
AddError(deco_to_str(builtin) +
|
||||||
" attribute appears multiple times as pipeline " +
|
" attribute appears multiple times as pipeline " +
|
||||||
(param_or_ret == ParamOrRetType::kParameter ? "input"
|
(param_or_ret == ParamOrRetType::kParameter ? "input"
|
||||||
: "output"),
|
: "output"),
|
||||||
func->source());
|
func->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateBuiltinDecoration(
|
if (!ValidateBuiltinDecoration(
|
||||||
builtin, ty,
|
builtin, ty,
|
||||||
/* is_input */ param_or_ret == ParamOrRetType::kParameter,
|
/* is_input */ param_or_ret == ParamOrRetType::kParameter,
|
||||||
/* is_struct_member */ is_struct_member)) {
|
/* is_struct_member */ is_struct_member)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
builtins.emplace(builtin->value());
|
builtins.emplace(builtin->value());
|
||||||
} else if (auto* location = deco->As<ast::LocationDecoration>()) {
|
} else if (auto* location = deco->As<ast::LocationDecoration>()) {
|
||||||
if (pipeline_io_attribute) {
|
if (pipeline_io_attribute) {
|
||||||
AddError("multiple entry point IO attributes", deco->source());
|
AddError("multiple entry point IO attributes", deco->source());
|
||||||
AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
|
AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
|
||||||
pipeline_io_attribute->source());
|
pipeline_io_attribute->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pipeline_io_attribute = deco;
|
pipeline_io_attribute = deco;
|
||||||
|
|
||||||
bool is_input = param_or_ret == ParamOrRetType::kParameter;
|
bool is_input = param_or_ret == ParamOrRetType::kParameter;
|
||||||
if (!ValidateLocationDecoration(location, ty, locations, source,
|
if (!ValidateLocationDecoration(location, ty, locations, source,
|
||||||
is_input)) {
|
is_input)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
|
} else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
|
||||||
if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
|
if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
|
||||||
is_invalid_compute_shader_decoration = true;
|
is_invalid_compute_shader_decoration = true;
|
||||||
} else if (!ValidateInterpolateDecoration(interpolate, ty)) {
|
} else if (!ValidateInterpolateDecoration(interpolate, ty)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
|
} else if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
|
||||||
if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
|
if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
|
||||||
is_invalid_compute_shader_decoration = true;
|
is_invalid_compute_shader_decoration = true;
|
||||||
}
|
}
|
||||||
invariant_attribute = invariant;
|
invariant_attribute = invariant;
|
||||||
}
|
}
|
||||||
if (is_invalid_compute_shader_decoration) {
|
if (is_invalid_compute_shader_decoration) {
|
||||||
std::string input_or_output =
|
std::string input_or_output =
|
||||||
param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
|
param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
|
||||||
AddError(
|
AddError(
|
||||||
"decoration is not valid for compute shader " + input_or_output,
|
"decoration is not valid for compute shader " + input_or_output,
|
||||||
deco->source());
|
deco->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValidationEnabled(decos,
|
if (IsValidationEnabled(decos,
|
||||||
ast::DisabledValidation::kEntryPointParameter)) {
|
ast::DisabledValidation::kEntryPointParameter)) {
|
||||||
if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
|
if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
|
||||||
std::string err = "missing entry point IO attribute";
|
std::string err = "missing entry point IO attribute";
|
||||||
if (!is_struct_member) {
|
if (!is_struct_member) {
|
||||||
err +=
|
err +=
|
||||||
(param_or_ret == ParamOrRetType::kParameter ? " on parameter"
|
(param_or_ret == ParamOrRetType::kParameter ? " on parameter"
|
||||||
: " on return type");
|
: " on return type");
|
||||||
}
|
}
|
||||||
AddError(err, source);
|
AddError(err, source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invariant_attribute) {
|
if (invariant_attribute) {
|
||||||
bool has_position = false;
|
bool has_position = false;
|
||||||
if (pipeline_io_attribute) {
|
if (pipeline_io_attribute) {
|
||||||
if (auto* builtin =
|
if (auto* builtin =
|
||||||
pipeline_io_attribute->As<ast::BuiltinDecoration>()) {
|
pipeline_io_attribute->As<ast::BuiltinDecoration>()) {
|
||||||
has_position = (builtin->value() == ast::Builtin::kPosition);
|
has_position = (builtin->value() == ast::Builtin::kPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_position) {
|
||||||
|
AddError(
|
||||||
|
"invariant attribute must only be applied to a position "
|
||||||
|
"builtin",
|
||||||
|
invariant_attribute->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!has_position) {
|
return true;
|
||||||
AddError(
|
};
|
||||||
"invariant attribute must only be applied to a position "
|
|
||||||
"builtin",
|
|
||||||
invariant_attribute->source());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Outer lambda for validating the entry point decorations for a type.
|
// Outer lambda for validating the entry point decorations for a type.
|
||||||
auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
|
auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
|
||||||
|
@ -2155,7 +2155,7 @@ bool Resolver::ForLoopStatement(ast::ForLoopStatement* stmt) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TypeOf(condition)->Is<sem::Bool>()) {
|
if (!TypeOf(condition)->UnwrapRef()->Is<sem::Bool>()) {
|
||||||
AddError(
|
AddError(
|
||||||
"for-loop condition must be bool, got " + TypeNameOf(condition),
|
"for-loop condition must be bool, got " + TypeNameOf(condition),
|
||||||
condition->source());
|
condition->source());
|
||||||
|
|
|
@ -768,6 +768,16 @@ TEST_F(ResolverTest, Stmt_Loop_ContinueInContinuing_Indirect) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, Stmt_ForLoop_CondIsBoolRef) {
|
||||||
|
// var cond : bool = true;
|
||||||
|
// for (; cond; ) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
auto* cond = Var("cond", ty.bool_(), Expr(true));
|
||||||
|
WrapInFunction(Decl(cond), For(nullptr, "cond", nullptr, Block()));
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Stmt_ForLoop_CondIsNotBool) {
|
TEST_F(ResolverTest, Stmt_ForLoop_CondIsNotBool) {
|
||||||
// for (; 1.0f; ) {
|
// for (; 1.0f; ) {
|
||||||
// }
|
// }
|
||||||
|
|
Loading…
Reference in New Issue