[ir] Validate function parameters
Check that they are alive and have the correct parent function.
Change-Id: Id5c941b3dedd83d20e14c05894d373caf985132c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/185522
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 0dd852f..3634c7b 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -182,6 +182,10 @@
/// @param inst the instruction
diag::Diagnostic& AddNote(const Instruction* inst);
+ /// Adds a note to @p func and highlights the function in the disassembly
+ /// @param func the function
+ diag::Diagnostic& AddNote(const Function* func);
+
/// Adds a note to @p inst for operand @p idx and highlights the operand in the
/// disassembly
/// @param inst the instruction
@@ -441,6 +445,12 @@
return AddNote(src);
}
+diag::Diagnostic& Validator::AddNote(const Function* func) {
+ DisassembleIfNeeded();
+ auto src = dis_.FunctionSource(func);
+ return AddNote(src);
+}
+
diag::Diagnostic& Validator::AddNote(const Instruction* inst, size_t idx) {
DisassembleIfNeeded();
auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
@@ -510,8 +520,21 @@
void Validator::CheckFunction(const Function* func) {
CheckBlock(func->Block());
- // References not allowed on function signatures even with Capability::kAllowRefTypes
for (auto* param : func->Params()) {
+ if (!param->Alive()) {
+ AddError(param) << "destroyed parameter found in function parameter list";
+ return;
+ }
+ if (!param->Function()) {
+ AddError(param) << "function parameter has nullptr parent function";
+ return;
+ } else if (param->Function() != func) {
+ AddError(param) << "function parameter has incorrect parent function";
+ AddNote(param->Function()) << "parent function declared here";
+ return;
+ }
+
+ // References not allowed on function signatures even with Capability::kAllowRefTypes
if (HoldsType<type::Reference>(param->Type())) {
AddError(param) << "references are not permitted as parameter types";
}
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index ce5313b..681a6b2 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -157,6 +157,88 @@
)");
}
+TEST_F(IR_ValidatorTest, Function_DeadParameter) {
+ auto* f = b.Function("my_func", ty.void_());
+ auto* p = b.FunctionParam("my_param", ty.f32());
+ f->SetParams({p});
+ f->Block()->Append(b.Return(f));
+
+ p->Destroy();
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:1:17 error: destroyed parameter found in function parameter list
+%my_func = func(%my_param:f32):void -> %b1 {
+ ^^^^^^^^^^^^^
+
+note: # Disassembly
+%my_func = func(%my_param:f32):void -> %b1 {
+ %b1 = block {
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Function_ParameterWithNullFunction) {
+ auto* f = b.Function("my_func", ty.void_());
+ auto* p = b.FunctionParam("my_param", ty.f32());
+ f->SetParams({p});
+ f->Block()->Append(b.Return(f));
+
+ p->SetFunction(nullptr);
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:1:17 error: function parameter has nullptr parent function
+%my_func = func(%my_param:f32):void -> %b1 {
+ ^^^^^^^^^^^^^
+
+note: # Disassembly
+%my_func = func(%my_param:f32):void -> %b1 {
+ %b1 = block {
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Function_ParameterUsedInMultipleFunctions) {
+ auto* p = b.FunctionParam("my_param", ty.f32());
+ auto* f1 = b.Function("my_func1", ty.void_());
+ auto* f2 = b.Function("my_func2", ty.void_());
+ f1->SetParams({p});
+ f2->SetParams({p});
+ f1->Block()->Append(b.Return(f1));
+ f2->Block()->Append(b.Return(f2));
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:1:18 error: function parameter has incorrect parent function
+%my_func1 = func(%my_param:f32):void -> %b1 {
+ ^^^^^^^^^^^^^
+
+:6:1 note: parent function declared here
+%my_func2 = func(%my_param:f32):void -> %b2 {
+^^^^^^^^^
+
+note: # Disassembly
+%my_func1 = func(%my_param:f32):void -> %b1 {
+ %b1 = block {
+ ret
+ }
+}
+%my_func2 = func(%my_param:f32):void -> %b2 {
+ %b2 = block {
+ ret
+ }
+}
+)");
+}
+
TEST_F(IR_ValidatorTest, CallToFunctionOutsideModule) {
auto* f = b.Function("f", ty.void_());
auto* g = b.Function("g", ty.void_());