matklad / xshell

Apache License 2.0
696 stars 30 forks source link

`cmd!` panics when string contains backslash followed by a line break #65

Open Aloso opened 1 year ago

Aloso commented 1 year ago

This panics during macro expansion:

cmd!(
    sh,
    "grcov . --binary-path ./target/debug/deps -s . -t {fmt} --branch --ignore-not-existing \
    --ignore ../* --ignore /* --ignore xtask/* --ignore */src/tests/* -o {file}"
)
ssmendon commented 1 year ago

Thought I'd add some extra information. I recompiled a sample on nightly -Z macro-backtrace enabled.

use xshell::{cmd, Shell};

fn main() -> anyhow::Result<()> {
    let sh = Shell::new()?;

    cmd!(
        sh,
        "scoop \
        --help"
    );

    Ok(())
}
error[E0765]: unterminated double quote string
   --> source\github\xshell\src\lib.rs:348:32
    |
343 |   macro_rules! cmd {
    |   ---------------- in this expansion of `cmd!` (#1)
...
348 |           let cmd: $crate::Cmd = $crate::__cmd!(f $cmd);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation (#2)
    |
   ::: source\github\xshell\xshell-macros\src\lib.rs:12:1
    |
12  |   pub fn __cmd(macro_arg: TokenStream) -> TokenStream {
    |   --------------------------------------------------- in this expansion of `$crate::__cmd!` (#2)
    |
   ::: examples\65.rs:6:5
    |
6   | /     cmd!(
7   | |         sh,
8   | |         "\
9   | |         --help"
10  | |     );
    | |_____- in this macro invocation (#1)

error: proc macro panicked
   --> source\github\xshell\src\lib.rs:348:32
    |
343 |   macro_rules! cmd {
    |   ---------------- in this expansion of `cmd!`
...
348 |           let cmd: $crate::Cmd = $crate::__cmd!(f $cmd);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
    |
   ::: examples\65.rs:6:5
    |
6   | /     cmd!(
7   | |         sh,
8   | |         "\
9   | |         --help"
10  | |     );
    | |_____- in this macro invocation

For more information about this error, try `rustc --explain E0765`.
error: could not compile `xshell` (example "65") due to 2 previous errors
matklad commented 1 year ago

Yeah, this is a bug, will get to fixing this one day if no-one beats me to it.

The semantics we want here is the following:

That's the same semantics of escapes that println! uses:

fn main() {
    println!("{\x7d", 93)
}

The problem with implementing this is that the first step, parsing string literal into string value, is part of Rust semantics, and ideally should be implemented by the compiler. So the proper solution here is to go & RFC https://internals.rust-lang.org/t/getting-value-out-of-proc-macro-literal/14140.

While we are waiting for that to happen, we should approximate what rustc is doing. I don't think we need to aim to be 100% correct here, but we obviously should fix panics

matklad commented 1 year ago

And see also https://github.com/matklad/xshell/issues/4#issuecomment-711415717, we need to figure out the correct semantics for quotes as well...