cranelift_filetests/
test_verifier.rs1use crate::match_directive::match_directive;
13use crate::subtest::{Context, SubTest};
14use cranelift_codegen::ir::Function;
15use cranelift_codegen::verify_function;
16use cranelift_reader::TestCommand;
17use std::borrow::{Borrow, Cow};
18use std::fmt::Write;
19
20struct TestVerifier;
21
22pub fn subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn SubTest>> {
23 assert_eq!(parsed.command, "verifier");
24 if !parsed.options.is_empty() {
25 anyhow::bail!("No options allowed on {}", parsed);
26 }
27 Ok(Box::new(TestVerifier))
28}
29
30impl SubTest for TestVerifier {
31 fn name(&self) -> &'static str {
32 "verifier"
33 }
34
35 fn needs_verifier(&self) -> bool {
36 false
38 }
39
40 fn run(&self, func: Cow<Function>, context: &Context) -> anyhow::Result<()> {
41 let func = func.borrow();
42
43 let mut expected = Vec::new();
45
46 for comment in &context.details.comments {
47 if let Some(tail) = match_directive(comment.text, "error:") {
48 expected.push((comment.entity, tail));
49 }
50 }
51
52 match verify_function(func, context.flags_or_isa()) {
53 Ok(()) if expected.is_empty() => Ok(()),
54 Ok(()) => anyhow::bail!("passed, but expected errors: {:?}", expected),
55
56 Err(ref errors) if expected.is_empty() => {
57 anyhow::bail!("expected no error, but got:\n{}", errors);
58 }
59
60 Err(errors) => {
61 let mut errors = errors.0;
62 let mut msg = String::new();
63
64 for expect in expected {
66 let pos = errors
67 .iter()
68 .position(|err| err.location == expect.0 && err.message.contains(expect.1));
69
70 match pos {
71 None => {
72 writeln!(msg, " expected error {}: {}", expect.0, expect.1).unwrap();
73 }
74 Some(pos) => {
75 errors.swap_remove(pos);
76 }
77 }
78 }
79
80 for err in errors {
82 writeln!(msg, "unexpected error {err}").unwrap();
83 }
84
85 if msg.is_empty() {
86 Ok(())
87 } else {
88 anyhow::bail!("{}", msg);
89 }
90 }
91 }
92 }
93}