Path: blob/main/cranelift/filetests/src/test_verifier.rs
1691 views
//! Test command for checking the IR verifier.1//!2//! The `test verifier` test command looks for annotations on instructions like this:3//!4//! ```clif5//! jump block3 ; error: jump to non-existent block6//! ```7//!8//! This annotation means that the verifier is expected to given an error for the jump instruction9//! containing the substring "jump to non-existent block".1011use crate::match_directive::match_directive;12use crate::subtest::{Context, SubTest};13use cranelift_codegen::ir::Function;14use cranelift_codegen::verify_function;15use cranelift_reader::TestCommand;16use std::borrow::{Borrow, Cow};17use std::fmt::Write;1819struct TestVerifier;2021pub fn subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn SubTest>> {22assert_eq!(parsed.command, "verifier");23if !parsed.options.is_empty() {24anyhow::bail!("No options allowed on {}", parsed);25}26Ok(Box::new(TestVerifier))27}2829impl SubTest for TestVerifier {30fn name(&self) -> &'static str {31"verifier"32}3334fn needs_verifier(&self) -> bool {35// Running the verifier before this test would defeat its purpose.36false37}3839fn run(&self, func: Cow<Function>, context: &Context) -> anyhow::Result<()> {40let func = func.borrow();4142// Scan source annotations for "error:" directives.43let mut expected = Vec::new();4445for comment in &context.details.comments {46if let Some(tail) = match_directive(comment.text, "error:") {47expected.push((comment.entity, tail));48}49}5051match verify_function(func, context.flags_or_isa()) {52Ok(()) if expected.is_empty() => Ok(()),53Ok(()) => anyhow::bail!("passed, but expected errors: {:?}", expected),5455Err(ref errors) if expected.is_empty() => {56anyhow::bail!("expected no error, but got:\n{}", errors);57}5859Err(errors) => {60let mut errors = errors.0;61let mut msg = String::new();6263// For each expected error, find a suitable match.64for expect in expected {65let pos = errors66.iter()67.position(|err| err.location == expect.0 && err.message.contains(expect.1));6869match pos {70None => {71writeln!(msg, " expected error {}: {}", expect.0, expect.1).unwrap();72}73Some(pos) => {74errors.swap_remove(pos);75}76}77}7879// Report remaining errors.80for err in errors {81writeln!(msg, "unexpected error {err}").unwrap();82}8384if msg.is_empty() {85Ok(())86} else {87anyhow::bail!("{}", msg);88}89}90}91}92}939495