Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions impl/src/fmt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::ast::Field;
use crate::attr::{Display, Trait};
use crate::scan_expr::scan_expr;
use proc_macro2::{TokenStream, TokenTree};
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use std::collections::{BTreeSet as Set, HashMap as Map};
use syn::ext::IdentExt;
Expand Down Expand Up @@ -87,14 +87,10 @@ impl Display<'_> {
};
implied_bounds.insert((field, bound));
}
let local = match &member {
let formatvar = match &member {
Member::Unnamed(index) => format_ident!("_{}", index),
Member::Named(ident) => ident.clone(),
};
let mut formatvar = local.clone();
if formatvar.to_string().starts_with("r#") {
formatvar = format_ident!("r_{}", formatvar);
}
out += &formatvar.to_string();
if !named_args.insert(formatvar.clone()) {
// Already specified in the format argument list.
Expand All @@ -103,6 +99,7 @@ impl Display<'_> {
if !has_trailing_comma {
args.extend(quote_spanned!(span=> ,));
}
let local = raw_if_needed(&formatvar);
args.extend(quote_spanned!(span=> #formatvar = #local));
if read.starts_with('}') && member_index.contains_key(&member) {
has_bonus_display = true;
Expand Down Expand Up @@ -233,11 +230,6 @@ fn take_int(read: &mut &str) -> String {

fn take_ident(read: &mut &str) -> Ident {
let mut ident = String::new();
let raw = read.starts_with("r#");
if raw {
ident.push_str("r#");
*read = &read[2..];
}
for (i, ch) in read.char_indices() {
match ch {
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
Expand All @@ -247,5 +239,17 @@ fn take_ident(read: &mut &str) -> Ident {
}
}
}
Ident::parse_any.parse_str(&ident).unwrap()
Ident::new(&ident, Span::call_site())
}

fn raw_if_needed(ident: &Ident) -> Ident {
let repr = ident.to_string();
if syn::parse_str::<Ident>(&repr).is_err() {
if let "_" | "super" | "self" | "Self" | "crate" = repr.as_str() {
// Some identifiers are never allowed to appear as raw, like r#self and r#_.
} else {
return Ident::new_raw(&repr, Span::call_site());
}
}
ident.clone()
}
15 changes: 2 additions & 13 deletions tests/test_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ fn test_macro_rules() {
#[test]
fn test_raw() {
#[derive(Error, Debug)]
#[error("braced raw error: {r#fn}")]
#[error("braced raw error: {fn}")]
struct Error {
r#fn: &'static str,
}
Expand All @@ -291,24 +291,13 @@ fn test_raw() {
fn test_raw_enum() {
#[derive(Error, Debug)]
enum Error {
#[error("braced raw error: {r#fn}")]
#[error("braced raw error: {fn}")]
Braced { r#fn: &'static str },
}

assert("braced raw error: T", Error::Braced { r#fn: "T" });
}

#[test]
fn test_raw_conflict() {
#[derive(Error, Debug)]
enum Error {
#[error("braced raw error: {r#func}, {func}", func = "U")]
Braced { r#func: &'static str },
}

assert("braced raw error: T, U", Error::Braced { r#func: "T" });
}

#[test]
fn test_keyword() {
#[derive(Error, Debug)]
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/raw-identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use thiserror::Error;

#[derive(Error, Debug)]
#[error("error: {r#fn}")]
pub struct Error {
r#fn: &'static str,
}

fn main() {
let r#fn = "...";
let _ = format!("error: {r#fn}");
}
21 changes: 21 additions & 0 deletions tests/ui/raw-identifier.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error: invalid format string: raw identifiers are not supported
--> tests/ui/raw-identifier.rs:4:18
|
4 | #[error("error: {r#fn}")]
| --^^
| |
| raw identifier used here in format string
| help: remove the `r#`
|
= note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`

error: invalid format string: raw identifiers are not supported
--> tests/ui/raw-identifier.rs:11:30
|
11 | let _ = format!("error: {r#fn}");
| --^^
| |
| raw identifier used here in format string
| help: remove the `r#`
|
= note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`