Skip to content

Commit

Permalink
Auto merge of rust-lang#12942 - lowr:fix/concat-with-char, r=Veykril
Browse files Browse the repository at this point in the history
fix: make `concat!` work with char

Fixes rust-lang#12921

- I avoided making `unquote_str()` take char literals as well because it's depended on by another function `parse_string()` that's only supposed to take strings.
- Even with this patch, we don't output `\0` as `\u{0}` which rust-lang#12921 pointed out ~~, but we're not actually responsible for serializing it but rowan is~~. They are functionally equivalent and I don't think it'd cause any confusion, but we *could* try escaping them before serialization (for reference, `rustc -Zunpretty=expanded`, which `cargo expand` uses under the hood, [makes use of `str::escape_default()`](https://github.com/rust-lang/rust/blob/3830ecaa8db798d2727cbdfa4ddf314ff938f268/compiler/rustc_ast/src/util/literal.rs#L161).
  • Loading branch information
bors committed Aug 8, 2022
2 parents 634cfe3 + 4d5873e commit b569bbb
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 6 deletions.
4 changes: 2 additions & 2 deletions crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,13 @@ fn test_concat_expand() {
#[rustc_builtin_macro]
macro_rules! concat {}
fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false); }
fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '"', '\0'); }
"##,
expect![[r##"
#[rustc_builtin_macro]
macro_rules! concat {}
fn main() { "foor0bar\nfalse"; }
fn main() { "foor0bar\nfalse\"\u{0}"; }
"##]],
);
}
Expand Down
14 changes: 12 additions & 2 deletions crates/hir-expand/src/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
token.value().map(|it| it.into_owned())
}

fn unquote_char(lit: &tt::Literal) -> Option<char> {
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::Char::cast(lit)?;
token.value()
}

fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::ByteString::cast(lit)?;
Expand Down Expand Up @@ -408,8 +414,12 @@ fn concat_expand(
// concat works with string and char literals, so remove any quotes.
// It also works with integer, float and boolean literals, so just use the rest
// as-is.
let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
text.push_str(&component);
if let Some(c) = unquote_char(it) {
text.push(c);
} else {
let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
text.push_str(&component);
}
}
// handle boolean literals
tt::TokenTree::Leaf(tt::Leaf::Ident(id))
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-expand/src/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ impl_to_to_tokentrees! {
tt::Literal => self { self };
tt::Ident => self { self };
tt::Punct => self { self };
&str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}};
String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}
&str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}};
String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}
}

#[cfg(test)]
Expand Down

0 comments on commit b569bbb

Please sign in to comment.