diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index e1395c3fa4427..280ce75720bcf 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -131,7 +131,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { parse_error(tcx, item.span, "this attribute must have a valid value", "expected value here", - Some(r#"eg `#[rustc_on_unimplemented = "foo"]`"#)); + Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#)); } if errored { @@ -170,7 +170,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { return Err(parse_error(tcx, attr.span, "`#[rustc_on_unimplemented]` requires a value", "value required here", - Some(r#"eg `#[rustc_on_unimplemented = "foo"]`"#))); + Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#))); }; debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result); result @@ -213,10 +213,13 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { } } + let options: FxHashMap = options.into_iter() + .filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned()))) + .collect(); OnUnimplementedNote { - label: label.map(|l| l.format(tcx, trait_ref)), - message: message.map(|m| m.format(tcx, trait_ref)), - note: note.map(|n| n.format(tcx, trait_ref)), + label: label.map(|l| l.format(tcx, trait_ref, &options)), + message: message.map(|m| m.format(tcx, trait_ref, &options)), + note: note.map(|n| n.format(tcx, trait_ref, &options)), } } } @@ -251,6 +254,10 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { Position::ArgumentNamed(s) if s == "Self" => (), // `{ThisTraitsName}` is allowed Position::ArgumentNamed(s) if s == name => (), + // `{from_method}` is allowed + Position::ArgumentNamed(s) if s == "from_method" => (), + // `{from_desugaring}` is allowed + Position::ArgumentNamed(s) if s == "from_desugaring" => (), // So is `{A}` if A is a type parameter Position::ArgumentNamed(s) => match generics.params.iter().find(|param| { param.name == s @@ -258,17 +265,14 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { Some(_) => (), None => { span_err!(tcx.sess, span, E0230, - "there is no parameter \ - {} on trait {}", - s, name); + "there is no parameter `{}` on trait `{}`", s, name); result = Err(ErrorReported); } }, // `{:1}` and `{}` are not to be used Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => { span_err!(tcx.sess, span, E0231, - "only named substitution \ - parameters are allowed"); + "only named substitution parameters are allowed"); result = Err(ErrorReported); } } @@ -280,7 +284,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { pub fn format(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_ref: ty::TraitRef<'tcx>) + trait_ref: ty::TraitRef<'tcx>, + options: &FxHashMap) -> String { let name = tcx.item_name(trait_ref.def_id); @@ -296,6 +301,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { let name = param.name.to_string(); Some((name, value)) }).collect::>(); + let empty_string = String::new(); let parser = Parser::new(&self.0, None); parser.map(|p| { @@ -308,14 +314,20 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { &trait_str } None => { - bug!("broken on_unimplemented {:?} for {:?}: \ - no argument matching {:?}", - self.0, trait_ref, s) + if let Some(val) = options.get(s) { + val + } else if s == "from_desugaring" || s == "from_method" { + // don't break messages using these two arguments incorrectly + &empty_string + } else { + bug!("broken on_unimplemented {:?} for {:?}: \ + no argument matching {:?}", + self.0, trait_ref, s) + } } }, _ => { - bug!("broken on_unimplemented {:?} - bad \ - format arg", self.0) + bug!("broken on_unimplemented {:?} - bad format arg", self.0) } } } diff --git a/src/test/ui/error-codes/E0232.stderr b/src/test/ui/error-codes/E0232.stderr index cb6cc44a73597..613b359c299b8 100644 --- a/src/test/ui/error-codes/E0232.stderr +++ b/src/test/ui/error-codes/E0232.stderr @@ -4,7 +4,7 @@ error[E0232]: `#[rustc_on_unimplemented]` requires a value LL | #[rustc_on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^ value required here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/bad-annotation.rs b/src/test/ui/on-unimplemented/bad-annotation.rs index 7ef155e5f2ebe..286c71bb29908 100644 --- a/src/test/ui/on-unimplemented/bad-annotation.rs +++ b/src/test/ui/on-unimplemented/bad-annotation.rs @@ -28,7 +28,7 @@ trait BadAnnotation1 {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] -//~^ ERROR there is no parameter C on trait BadAnnotation2 +//~^ ERROR there is no parameter `C` on trait `BadAnnotation2` trait BadAnnotation2 {} diff --git a/src/test/ui/on-unimplemented/bad-annotation.stderr b/src/test/ui/on-unimplemented/bad-annotation.stderr index 1c5d4d603afc6..212eb125f85b3 100644 --- a/src/test/ui/on-unimplemented/bad-annotation.stderr +++ b/src/test/ui/on-unimplemented/bad-annotation.stderr @@ -4,9 +4,9 @@ error[E0232]: `#[rustc_on_unimplemented]` requires a value LL | #[rustc_on_unimplemented] //~ ERROR `#[rustc_on_unimplemented]` requires a value | ^^^^^^^^^^^^^^^^^^^^^^^^^ value required here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` -error[E0230]: there is no parameter C on trait BadAnnotation2 +error[E0230]: there is no parameter `C` on trait `BadAnnotation2` --> $DIR/bad-annotation.rs:30:1 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] @@ -24,7 +24,7 @@ error[E0232]: this attribute must have a valid value LL | #[rustc_on_unimplemented(lorem="")] | ^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value --> $DIR/bad-annotation.rs:44:26 @@ -32,7 +32,7 @@ error[E0232]: this attribute must have a valid value LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value --> $DIR/bad-annotation.rs:48:39 @@ -40,7 +40,7 @@ error[E0232]: this attribute must have a valid value LL | #[rustc_on_unimplemented(message="x", message="y")] | ^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value --> $DIR/bad-annotation.rs:52:39 @@ -48,7 +48,7 @@ error[E0232]: this attribute must have a valid value LL | #[rustc_on_unimplemented(message="x", on(desugared, message="y"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` --> $DIR/bad-annotation.rs:56:26 @@ -62,7 +62,7 @@ error[E0232]: this attribute must have a valid value LL | #[rustc_on_unimplemented(on="x", message="y")] | ^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error[E0232]: this attribute must have a valid value --> $DIR/bad-annotation.rs:67:40 @@ -70,7 +70,7 @@ error[E0232]: this attribute must have a valid value LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented = "foo"]` + = note: eg `#[rustc_on_unimplemented(message="foo")]` error: aborting due to 10 previous errors