maud icon indicating copy to clipboard operation
maud copied to clipboard

Spurious `unreachable_code` warning when `todo!` or `unreachable!` is used inside `html!`

Open coreyja opened this issue 2 years ago • 4 comments

Thanks for the awesome Library! I'm using it in a couple of small projects, and really liking it!

One thing I was realizing today is that it doesn't seem like I can use 'panicking' macros like todo! or unreachable! from within the html! macro, without a warning

For example in my blog I have some code to convert a Markdown AST to HTML using Maud. I wanted to use a match like this to get the correct heading element, but the following gives a warning about unreachable_code. Adding allow[unreachable_code] above the macro just leads to a new warning telling that allow is not needed

Since this is a warning its not the end of the world, but since I usually turn warnings into errors I've worked around this in my application by moving the panics out the macro

html! {
  @match self.depth {
    1 => h1 { (self.content) },
    _ => todo!(),
  }
}

coreyja avatar Apr 26 '23 23:04 coreyja

Of course about 2 minutes after posting this, and using the rust-analyzer expand macro tool I got a version I'm happy with! This compiles without warnings for me!

        html! {
            @match self.depth {
                1 => h1 { (content) },
                2 => h2 { (content) },
                3 => h3 { (content) },
                4 => h4 { (content) },
                5 => h5 { (content) },
                6 => h6 { (content) },
                #[allow(unreachable_code)]
                _ => (unreachable!("Invalid heading depth")),
            }
        }

Feel free to close this issue, if you would like! Thanks again for the awesome tool!

coreyja avatar Apr 26 '23 23:04 coreyja

Hi @coreyja, thanks for the report. I'm curious why this warning comes up. Would you like to share the output of the expand tool?

lambda-fairy avatar Jul 30 '23 04:07 lambda-fairy

This produces the warning

 let output = html! {
    @match self.depth {
    1 => h1 { (content) },
    _ => (unreachable!()),
    }
};

And expands to (I expanded a call to render_to! as well)

let output = {
  extern crate alloc;
  extern crate maud;
  let mut __maud_output = alloc::string::String::with_capacity(70usize);
  match self.depth {
    1 => {
      __maud_output.push_str("<h1>");
      maud::macro_private::render_to!(&content, &mut __maud_output);
      __maud_output.push_str("</h1>");
    }
     _ => {
       {
         use maud::macro_private::*;
         match ChooseRenderOrDisplay(&unreachable!()) {
           x => x
                .implements_render_or_display()
                .render_to(x.0, &mut __maud_output),
         }
       };
      }
    }maud::PreEscaped(__maud_output)
};

I believe this fires the warning because we are using the values of the unreachable to pass into the ChooseRenderOrDisplay struct

Adding the #[allow(unreachable_code)] above that level in the match produces the following and DOES silence the warning: [Left the render_to! unexpanded this time for brevity]

let output = {
  extern crate alloc;
  extern crate maud;
  let mut __maud_output = alloc::string::String::with_capacity(99usize);
  match self.depth {
    1 => {
      __maud_output.push_str("<h1>");
      maud::macro_private::render_to!(&content, &mut __maud_output);
      __maud_output.push_str("</h1>");
    }
    #[allow(unreachable_code)]
    _ => {
      maud::macro_private::render_to!(&unreachable!(), &mut __maud_output);
    }
  
    }maud::PreEscaped(__maud_output)
};

coreyja avatar Jul 31 '23 20:07 coreyja

I wonder why the warning is triggering on generated code. Marking #[allow(unreachable_code)] will fix the immediate issue, but might hide actual unreachable code (however unlikely that might be). I remember the codegen used to be quite sloppy about spans, so perhaps the real fix is in there.

lambda-fairy avatar Dec 30 '23 08:12 lambda-fairy