tint/resolver: Fix ICE when failing to materialize

If the abstract numeric cannot materialize to the target type, we could
ICE before the validation handles this bad case. To fix, simply hoist
the validation earlier.

Bug: chromium:1337524
Change-Id: Icc603b056900131cfdb029b517f1c3d030b2ecb4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94322
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton 2022-06-20 19:23:02 +00:00 committed by Dawn LUCI CQ
parent e4e4854b77
commit 22d8dea091
4 changed files with 44 additions and 14 deletions

View File

@ -33,6 +33,7 @@ using f16V = builder::vec<3, f16>;
using i32V = builder::vec<3, i32>; using i32V = builder::vec<3, i32>;
using u32V = builder::vec<3, u32>; using u32V = builder::vec<3, u32>;
using f32M = builder::mat<3, 2, f32>; using f32M = builder::mat<3, 2, f32>;
using i32Varr = builder::array<3, i32>;
constexpr double kHighestU32 = static_cast<double>(u32::kHighest); constexpr double kHighestU32 = static_cast<double>(u32::kHighest);
constexpr double kLowestU32 = static_cast<double>(u32::kLowest); constexpr double kLowestU32 = static_cast<double>(u32::kLowest);
@ -526,10 +527,14 @@ INSTANTIATE_TEST_SUITE_P(InvalidConversion,
testing::Combine(testing::Values(Expectation::kInvalidConversion), testing::Combine(testing::Values(Expectation::kInvalidConversion),
testing::ValuesIn(kScalarMethods), testing::ValuesIn(kScalarMethods),
testing::ValuesIn(std::vector<Data>{ testing::ValuesIn(std::vector<Data>{
Types<i32, AFloat>(), // Types<i32, AFloat>(), //
Types<u32, AFloat>(), // Types<u32, AFloat>(), //
Types<i32V, AFloatV>(), // Types<i32V, AFloatV>(), //
Types<u32V, AFloatV>(), // Types<u32V, AFloatV>(), //
Types<i32Varr, AInt>(), //
Types<i32Varr, AIntV>(), //
Types<i32Varr, AFloat>(), //
Types<i32Varr, AFloatV>(), //
}))); })));
INSTANTIATE_TEST_SUITE_P(ScalarValueCannotBeRepresented, INSTANTIATE_TEST_SUITE_P(ScalarValueCannotBeRepresented,
@ -959,5 +964,25 @@ INSTANTIATE_TEST_SUITE_P(ArrayLengthValueCannotBeRepresented,
} // namespace materialize_abstract_numeric_to_default_type } // namespace materialize_abstract_numeric_to_default_type
using MaterializeAbstractNumericToUnrelatedType = resolver::ResolverTest;
TEST_F(MaterializeAbstractNumericToUnrelatedType, AIntToStructVarCtor) {
Structure("S", {Member("a", ty.i32())});
WrapInFunction(Decl(Var("v", ty.type_name("S"), Expr(Source{{12, 34}}, 1_a))));
ASSERT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
testing::HasSubstr("error: cannot convert value of type 'abstract-int' to type 'S'"));
}
TEST_F(MaterializeAbstractNumericToUnrelatedType, AIntToStructLetCtor) {
Structure("S", {Member("a", ty.i32())});
WrapInFunction(Decl(Let("v", ty.type_name("S"), Expr(Source{{12, 34}}, 1_a))));
ASSERT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
testing::HasSubstr("error: cannot convert value of type 'abstract-int' to type 'S'"));
}
} // namespace } // namespace
} // namespace tint::resolver } // namespace tint::resolver

View File

@ -1243,7 +1243,11 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
// Helper for actually creating the the materialize node, performing the constant cast, updating // Helper for actually creating the the materialize node, performing the constant cast, updating
// the ast -> sem binding, and performing validation. // the ast -> sem binding, and performing validation.
auto materialize = [&](const sem::Type* target_ty) -> sem::Materialize* { auto materialize = [&](const sem::Type* target_ty) -> sem::Materialize* {
auto* src_ty = expr->Type();
auto* decl = expr->Declaration(); auto* decl = expr->Declaration();
if (!validator_.Materialize(target_ty, src_ty, decl->source)) {
return nullptr;
}
auto expr_val = EvaluateConstantValue(decl, expr->Type()); auto expr_val = EvaluateConstantValue(decl, expr->Type());
if (!expr_val) { if (!expr_val) {
return nullptr; return nullptr;
@ -1252,7 +1256,7 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
TINT_ICE(Resolver, builder_->Diagnostics()) TINT_ICE(Resolver, builder_->Diagnostics())
<< decl->source << decl->source
<< "EvaluateConstantValue() returned invalid value for materialized value of type: " << "EvaluateConstantValue() returned invalid value for materialized value of type: "
<< builder_->FriendlyName(expr->Type()); << builder_->FriendlyName(src_ty);
return nullptr; return nullptr;
} }
auto materialized_val = ConvertValue(expr_val.Get(), target_ty, decl->source); auto materialized_val = ConvertValue(expr_val.Get(), target_ty, decl->source);
@ -1269,7 +1273,7 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
builder_->create<sem::Materialize>(expr, current_statement_, materialized_val.Get()); builder_->create<sem::Materialize>(expr, current_statement_, materialized_val.Get());
m->Behaviors() = expr->Behaviors(); m->Behaviors() = expr->Behaviors();
builder_->Sem().Replace(decl, m); builder_->Sem().Replace(decl, m);
return validator_.Materialize(m) ? m : nullptr; return m;
}; };
// Helpers for constructing semantic types // Helpers for constructing semantic types

View File

@ -307,14 +307,13 @@ bool Validator::MultisampledTexture(const sem::MultisampledTexture* t, const Sou
return true; return true;
} }
bool Validator::Materialize(const sem::Materialize* m) const { bool Validator::Materialize(const sem::Type* to,
auto* from = m->Expr()->Type(); const sem::Type* from,
auto* to = m->Type(); const Source& source) const {
if (sem::Type::ConversionRank(from, to) == sem::Type::kNoConversion) { if (sem::Type::ConversionRank(from, to) == sem::Type::kNoConversion) {
AddError("cannot convert value of type '" + sem_.TypeNameOf(from) + "' to type '" + AddError("cannot convert value of type '" + sem_.TypeNameOf(from) + "' to type '" +
sem_.TypeNameOf(to) + "'", sem_.TypeNameOf(to) + "'",
m->Expr()->Declaration()->source); source);
return false; return false;
} }
return true; return true;

View File

@ -283,10 +283,12 @@ class Validator {
/// @returns true on success, false otherwise. /// @returns true on success, false otherwise.
bool LoopStatement(const sem::LoopStatement* stmt) const; bool LoopStatement(const sem::LoopStatement* stmt) const;
/// Validates a materialize of an abstract numeric value /// Validates a materialize of an abstract numeric value from the type `from` to the type `to`.
/// @param m the materialize to validate /// @param to the target type
/// @param from the abstract numeric type
/// @param source the source of the materialization
/// @returns true on success, false otherwise /// @returns true on success, false otherwise
bool Materialize(const sem::Materialize* m) const; bool Materialize(const sem::Type* to, const sem::Type* from, const Source& source) const;
/// Validates a matrix /// Validates a matrix
/// @param ty the matrix to validate /// @param ty the matrix to validate