diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 9b4ffc7ea27f6..c2dfc4a147ee3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -396,9 +396,7 @@ pub(crate) fn parse_format_string( .map(|piece| match piece { RpfPiece::Lit(lit) => Piece::Lit(Symbol::intern(lit)), RpfPiece::NextArgument(arg) => { - warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal); - let arg = parse_arg(&arg, mode, &mut warnings, span, parser.is_source_literal); - Piece::Arg(arg) + Piece::Arg(parse_arg(&arg, mode, &mut warnings, span, parser.is_source_literal)) } }) .collect(); @@ -415,15 +413,25 @@ fn parse_arg( ) -> FormatArg { let span = slice_span(input_span, arg.position_span.clone(), is_source_literal); - match arg.position { + let mut check_format = true; + + let ret = match arg.position { // Something like "hello {name}" Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) { (Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext, - // Like `{This}`, but sugared. - // FIXME(mejrs) maybe rename/rework this or something - // if we want to apply this to other attrs? - (Mode::RustcOnUnimplemented, sym::Trait) => FormatArg::Trait, + // `{This:ty}` + (Mode::RustcOnUnimplemented, sym::This) => match arg.format.ty { + "resolved" => { + check_format = false; + FormatArg::ThisResolved + } + "path" => { + check_format = false; + FormatArg::ThisPath + } + _ => FormatArg::This, + }, // Some diagnostic attributes can use `{This}` to refer to the annotated item. // For those that don't, we continue and maybe use it as a generic parameter. @@ -431,10 +439,7 @@ fn parse_arg( // FIXME(mejrs) `DiagnosticOnUnimplemented` is intentionally not here; // that requires lang approval which is best kept for a standalone PR. ( - Mode::RustcOnUnimplemented - | Mode::DiagnosticOnUnknown - | Mode::DiagnosticOnMove - | Mode::DiagnosticOnUnmatchArgs, + Mode::DiagnosticOnUnknown | Mode::DiagnosticOnMove | Mode::DiagnosticOnUnmatchArgs, sym::This, ) => FormatArg::This, @@ -471,11 +476,11 @@ fn parse_arg( attr: mode.as_str(), allowed: mode.allowed_format_arguments(), }); - return FormatArg::AsIs(Symbol::intern(&format!("{{{as_is}}}"))); + FormatArg::AsIs(Symbol::intern(&format!("{{{as_is}}}"))) } }, - // `{:1}` and `{}` are ignored + // `{1}` and `{}` are ignored Position::ArgumentIs(idx) => { warnings.push(FormatWarning::IndexedArgument { span }); FormatArg::AsIs(Symbol::intern(&format!("{{{idx}}}"))) @@ -484,7 +489,11 @@ fn parse_arg( warnings.push(FormatWarning::PositionalArgument { span }); FormatArg::AsIs(sym::empty_braces) } + }; + if check_format { + warn_on_format_spec(&arg.format, warnings, input_span, is_source_literal); } + ret } /// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything @@ -495,12 +504,8 @@ fn warn_on_format_spec( input_span: Span, is_source_literal: bool, ) { - if spec.ty != "" { - let span = spec - .ty_span - .as_ref() - .map(|inner| slice_span(input_span, inner.clone(), is_source_literal)) - .unwrap_or(input_span); + if let Some(ty_span) = &spec.ty_span { + let span = slice_span(input_span, ty_span.clone(), is_source_literal); warnings.push(FormatWarning::InvalidSpecifier { span }) } } diff --git a/compiler/rustc_hir/src/attrs/diagnostic.rs b/compiler/rustc_hir/src/attrs/diagnostic.rs index 7cbb0ea45b969..7d4ae803cee59 100644 --- a/compiler/rustc_hir/src/attrs/diagnostic.rs +++ b/compiler/rustc_hir/src/attrs/diagnostic.rs @@ -147,11 +147,12 @@ impl FormatString { }; ret.push_str(&slf); } + Piece::Arg(FormatArg::This) => ret.push_str(&args.this), // It's only `rustc_onunimplemented` from here - Piece::Arg(FormatArg::This) => ret.push_str(&args.this), - Piece::Arg(FormatArg::Trait) => { - let _ = fmt::write(&mut ret, format_args!("{}", &args.this_sugared)); + Piece::Arg(FormatArg::ThisPath) => ret.push_str(&args.this_path), + Piece::Arg(FormatArg::ThisResolved) => { + let _ = fmt::write(&mut ret, format_args!("{}", &args.this_resolved)); } Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context), } @@ -197,7 +198,7 @@ impl FormatString { /// ```rust,ignore (just an example) /// FormatArgs { /// this: "FromResidual", -/// this_sugared: "FromResidual>", +/// this_resolved: "FromResidual>", /// item_context: "an async function", /// generic_args: [("Self", "u32"), ("R", "Option")], /// } @@ -206,7 +207,8 @@ impl FormatString { pub struct FormatArgs { /// The name of the item the attribute is on. pub this: String, - pub this_sugared: String = String::new(), + pub this_resolved: String = String::new(), + pub this_path: String = String::new(), pub item_context: &'static str = "", pub generic_args: Vec<(Symbol, String)> = Vec::new(), } @@ -226,10 +228,12 @@ pub enum FormatArg { }, // `{Self}` SelfUpper, - /// `{This}` or `{TraitName}` + /// `{This}` and `{This:name}`. This, - /// The sugared form of the trait - Trait, + /// The sugared form: `{This:sugared}`. + ThisResolved, + /// The full path: `{This:path}`. + ThisPath, /// what we're in, like a function, method, closure etc. ItemContext, /// What the user typed, if it doesn't match anything we can use. diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 20f4646490a6b..9e1281fb82cdc 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -750,15 +750,15 @@ impl<'input> Parser<'input> { spec } - /// Always returns an empty `FormatSpec` + /// Always returns an empty `FormatSpec`, except for the `ty` and `ty_span` fields. fn diagnostic(&mut self) -> FormatSpec<'input> { let mut spec = FormatSpec::default(); - let Some((Range { start, .. }, start_idx)) = self.consume_pos(':') else { + let Some((Range { start, .. }, _)) = self.consume_pos(':') else { return spec; }; - spec.ty = self.string(start_idx); + spec.ty = self.string(self.input_vec_index); spec.ty_span = { let end = self.input_vec_index2range(self.input_vec_index).start; Some(start..end) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 695103a249b49..998588d2d835e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -317,7 +317,6 @@ symbols! { Target, This, TokenStream, - Trait, TrivialClone, Try, TryCaptureGeneric, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index b15f528b7261e..89dd0cf22f612 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -217,7 +217,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { })); let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id); - let this_sugared = trait_pred.trait_ref.print_trait_sugared().to_string(); + let this_resolved = trait_pred.trait_ref.print_trait_sugared().to_string(); + let this_path = + ty::TraitRef::identity(self.tcx, def_id).print_only_trait_path().to_string(); let filter_options = FilterOptions { self_types, from_desugaring, cause, crate_local, direct, generic_args }; @@ -249,7 +251,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) .collect(); - let format_args = FormatArgs { this, this_sugared, generic_args, item_context }; + let format_args = FormatArgs { this, this_path, this_resolved, generic_args, item_context }; (filter_options, format_args) } } diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index efe5c0871fb8b..57b41e6ad6ccd 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -67,8 +67,8 @@ use crate::marker::Tuple; // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), - message = "expected a `{Trait}` closure, found `{Self}`", - label = "expected an `{Trait}` closure, found `{Self}`" + message = "expected a `{This:resolved}` closure, found `{Self}`", + label = "expected an `{This:resolved}` closure, found `{Self}`" )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] @@ -154,8 +154,8 @@ pub const trait Fn: [const] FnMut { // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), - message = "expected a `{Trait}` closure, found `{Self}`", - label = "expected an `{Trait}` closure, found `{Self}`" + message = "expected a `{This:resolved}` closure, found `{Self}`", + label = "expected an `{This:resolved}` closure, found `{Self}`" )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] @@ -233,8 +233,8 @@ pub const trait FnMut: FnOnce { // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), - message = "expected a `{Trait}` closure, found `{Self}`", - label = "expected an `{Trait}` closure, found `{Self}`" + message = "expected a `{This:resolved}` closure, found `{Self}`", + label = "expected an `{This:resolved}` closure, found `{Self}`" )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 554bcfcf8e4b6..7e3da67d872c1 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -1018,12 +1018,13 @@ pub trait From: Sized { ### Formatting The string literals are format strings that accept parameters wrapped in braces -but positional and listed parameters and format specifiers are not accepted. +but positional and listed parameters are not accepted. The following parameter names are valid: - `Self` and all generic parameters of the trait. - `This`: the name of the trait the attribute is on, without generics. -- `Trait`: the name of the "sugared" trait. - See `TraitRefPrintSugared`. +- `This:path`: the full path of the trait the attribute is on, with unresolved generics. +- `This:resolved`: the full path of the trait the attribute is on, with resolved generics. +Additionally, this will "sugar" the `Fn(...)` traits. - `ItemContext`: the kind of `hir::Node` we're in, things like `"an async block"`, `"a function"`, `"an async function"`, etc. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index 983f871dde109..b193d4be83c8d 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr @@ -16,18 +16,18 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] | = help: you can print empty braces by escaping them -warning: format specifiers are not permitted in diagnostic attributes - --> $DIR/broken_format.rs:10:50 - | -LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] - | ^ remove this format specifier - warning: indexed format arguments are not permitted in diagnostic attributes --> $DIR/broken_format.rs:10:49 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] | ^ remove this format argument +warning: format specifiers are not permitted in diagnostic attributes + --> $DIR/broken_format.rs:10:50 + | +LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] + | ^ remove this format specifier + warning: format specifiers are not permitted in diagnostic attributes --> $DIR/broken_format.rs:15:53 | diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index e3c38c7f55c95..aa4e14fb04f2f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -35,13 +35,16 @@ impl Bar for i32 {} //~|WARN there is no parameter `r#struct` on trait `Baz` //~|WARN there is no parameter `r#enum` on trait `Baz` //~|WARN there is no parameter `union` on trait `Baz` - label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" + label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" //~^WARN there is no parameter `float` on trait `Baz` //~|WARN there is no parameter `_Self` on trait `Baz` //~|WARN there is no parameter `crate_local` on trait `Baz` - //~|WARN there is no parameter `Trait` on trait `Baz` //~|WARN there is no parameter `ItemContext` on trait `Baz` //~|WARN there is no parameter `This` on trait `Baz` + //~|WARN there is no parameter `This` on trait `Baz` + //~|WARN there is no parameter `This` on trait `Baz` + //~|WARN format specifiers are not permitted in diagnostic attributes + //~|WARN format specifiers are not permitted in diagnostic attributes )] trait Baz {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index 9ed72d334b271..7ab7f25ee6964 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -66,7 +66,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{ warning: there is no parameter `float` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:15 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -74,7 +74,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" warning: there is no parameter `_Self` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:22 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -82,32 +82,40 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" warning: there is no parameter `crate_local` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:29 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument -warning: there is no parameter `Trait` on trait `Baz` +warning: there is no parameter `This` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:42 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" - | ^^^^^ +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" + | ^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:49 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:48 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" - | ^^^^^^^^^^^ +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" + | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `This` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:62 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:61 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" - | ^^^^ +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" + | ^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `This` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:72 + | +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" + | ^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -152,8 +160,20 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl | = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default +warning: format specifiers are not permitted in diagnostic attributes + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:65 + | +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" + | ^^^^^ remove this format specifier + +warning: format specifiers are not permitted in diagnostic attributes + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:76 + | +LL | label = "{float}{_Self}{crate_local}{This}{ItemContext}{This:path}{This:resolved}" + | ^^^^^^^^^ remove this format specifier + error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -168,13 +188,13 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:48:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:51:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^^^^^^ required by this bound in `takes_foo` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -187,31 +207,31 @@ help: the trait `Bar` is implemented for `i32` LL | impl Bar for i32 {} | ^^^^^^^^^^^^^^^^ note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:49:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:15 | LL | takes_baz(()); - | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This} + | --------- ^^ {float}{_Self}{crate_local}{This}{ItemContext}{This}{This} | | | required by a bound introduced by this call | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:49:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` -error: aborting due to 3 previous errors; 19 warnings emitted +error: aborting due to 3 previous errors; 22 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/format_specs.rs b/tests/ui/on-unimplemented/format_specs.rs new file mode 100644 index 0000000000000..f92674ab4a888 --- /dev/null +++ b/tests/ui/on-unimplemented/format_specs.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented( + message = "normal: {This}, path: {This:path}, resolved: {This:resolved}" +)] +pub trait Trait<'lifetime, const CONST_GENERIC: usize, A, B> where A: Send {} + +fn take_trait<'a, T: Trait<'a, 6, u8, U>, U>(_: T) {} + +fn main() { + take_trait(()); + //~^ERROR normal: Trait, path: Trait<'lifetime, CONST_GENERIC, A, B>, resolved: Trait<'_, 6, u8, _> +} diff --git a/tests/ui/on-unimplemented/format_specs.stderr b/tests/ui/on-unimplemented/format_specs.stderr new file mode 100644 index 0000000000000..3163323f34026 --- /dev/null +++ b/tests/ui/on-unimplemented/format_specs.stderr @@ -0,0 +1,22 @@ +error[E0277]: normal: Trait, path: Trait<'lifetime, CONST_GENERIC, A, B>, resolved: Trait<'_, 6, u8, _> + --> $DIR/format_specs.rs:11:16 + | +LL | take_trait(()); + | ---------- ^^ the trait `Trait<'_, 6, u8, _>` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/format_specs.rs:6:1 + | +LL | pub trait Trait<'lifetime, const CONST_GENERIC: usize, A, B> where A: Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `take_trait` + --> $DIR/format_specs.rs:8:22 + | +LL | fn take_trait<'a, T: Trait<'a, 6, u8, U>, U>(_: T) {} + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `take_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.