From fb8d3a7f448aa2db8e9bb13fae03c687f64d112b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 8 Nov 2024 12:43:16 -0500 Subject: [PATCH 1/2] Add test using generic type with multiple bounds error[E0277]: the trait bound `T: UpperHex` is not satisfied --> tests/test_generics.rs:179:13 | 178 | #[derive(Error, Debug)] | ----- in this derive macro expansion 179 | #[error("0x{thing:x} 0x{thing:X}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `UpperHex` is not implemented for `T` | = note: required for `&T` to implement `UpperHex` note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` --> $RUSTUP_HOME/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/rt.rs:133:29 | 133 | pub fn new_upper_hex(x: &T) -> Argument<'_> { | ^^^^^^^^ required by this bound in `Argument::<'_>::new_upper_hex` = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info) --- tests/test_generics.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_generics.rs b/tests/test_generics.rs index 4d49edf5..36f11811 100644 --- a/tests/test_generics.rs +++ b/tests/test_generics.rs @@ -172,3 +172,15 @@ fn test_no_bound_on_named_fmt() { let error = Error { thing: DebugOnly }; assert_eq!(error.to_string(), "..."); } + +#[test] +fn test_multiple_bound() { + #[derive(Error, Debug)] + #[error("0x{thing:x} 0x{thing:X}")] + pub struct Error { + thing: T, + } + + let error = Error { thing: 0xFFi32 }; + assert_eq!(error.to_string(), "0xff 0xFF"); +} From 5948ee6ce45031a4520f7a6a345df36bf8a33be0 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 8 Nov 2024 12:48:02 -0500 Subject: [PATCH 2/2] Support generic types that need multiple bounds --- impl/src/fmt.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/impl/src/fmt.rs b/impl/src/fmt.rs index 36300e52..6dfdccf2 100644 --- a/impl/src/fmt.rs +++ b/impl/src/fmt.rs @@ -99,10 +99,6 @@ impl Display<'_> { formatvar = IdentUnraw::new(format_ident!("_{}", formatvar.to_string())); } out += &formatvar.to_string(); - if !macro_named_args.insert(member.clone()) { - // Already added to scope by a previous use. - continue; - } let local = formatvar.to_local(); let mut binding_value = ToTokens::into_token_stream(match &member { MemberUnraw::Unnamed(index) => format_ident!("_{}", index), @@ -142,7 +138,11 @@ impl Display<'_> { } ); } - bindings.push((local, binding_value)); + if macro_named_args.insert(member) { + bindings.push((local, binding_value)); + } else { + // Already added to bindings by a previous use. + } } out += read;