diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index 28084c9d4ac..f15fa779534 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -1046,11 +1046,22 @@ pub fn report_object_safety_error( let mut reported_violations = FxHashSet::default(); for violation in violations { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation { + if !sp.is_empty() { + // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations + // with a `Span`. + reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + } + } if reported_violations.insert(violation.clone()) { - match violation.span() { - Some(span) => err.span_label(span, violation.error_msg()), - None => err.note(&violation.error_msg()), - }; + let spans = violation.spans(); + if spans.is_empty() { + err.note(&violation.error_msg()); + } else { + for span in spans { + err.span_label(span, violation.error_msg()); + } + } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index bca0ecb1e79..8ceefb0abf0 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -18,15 +18,16 @@ use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; +use smallvec::SmallVec; use syntax::ast; use std::borrow::Cow; use std::iter::{self}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ObjectSafetyViolation { /// `Self: Sized` declared on the trait. - SizedSelf(Span), + SizedSelf(SmallVec<[Span; 1]>), /// Supertrait reference references `Self` an in illegal location /// (e.g., `trait Foo : Bar`). @@ -75,18 +76,18 @@ impl ObjectSafetyViolation { } } - pub fn span(&self) -> Option { + pub fn spans(&self) -> SmallVec<[Span; 1]> { // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so // diagnostics use a `note` instead of a `span_label`. - match *self { + match self { + ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::SizedSelf(span) | ObjectSafetyViolation::Method(_, _, span) - if span != DUMMY_SP => + if *span != DUMMY_SP => { - Some(span) + vec![*span].into() } - _ => None, + _ => vec![].into(), } } } @@ -189,10 +190,14 @@ fn object_safety_violations_for_trait( tcx.def_path_str(trait_def_id) ), ); - match violation.span() { - Some(span) => err.span_label(span, violation.error_msg()), - None => err.note(&violation.error_msg()), - }; + let spans = violation.spans(); + if spans.is_empty() { + err.note(&violation.error_msg()); + } else { + for span in spans { + err.span_label(span, violation.error_msg()); + } + } err.emit(); false } else { @@ -203,8 +208,9 @@ fn object_safety_violations_for_trait( // Check the trait itself. if trait_has_sized_self(tcx, trait_def_id) { - let span = get_sized_bound(tcx, trait_def_id); - violations.push(ObjectSafetyViolation::SizedSelf(span)); + // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. + let spans = get_sized_bounds(tcx, trait_def_id); + violations.push(ObjectSafetyViolation::SizedSelf(spans)); } if predicates_reference_self(tcx, trait_def_id, false) { violations.push(ObjectSafetyViolation::SupertraitSelf); @@ -224,25 +230,26 @@ fn object_safety_violations_for_trait( violations } -fn get_sized_bound(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Span { +fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { tcx.hir() .get_if_local(trait_def_id) .and_then(|node| match node { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., bounds, _), .. }) => bounds - .iter() - .filter_map(|b| match b { - hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) - if Some(trait_ref.trait_ref.trait_def_id()) - == tcx.lang_items().sized_trait() => - { - Some(trait_ref.span) - } - _ => None, - }) - .next(), + hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., bounds, _), .. }) => Some( + bounds + .iter() + .filter_map(|b| match b { + hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) + if trait_has_sized_self(tcx, trait_ref.trait_ref.trait_def_id()) => + { + Some(trait_ref.span) + } + _ => None, + }) + .collect::>(), + ), _ => None, }) - .unwrap_or(DUMMY_SP) + .unwrap_or_else(SmallVec::new) } fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool { diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr index de362e1cef0..237c22d3bf0 100644 --- a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -6,8 +6,6 @@ LL | trait NonObjectSafe1: Sized {} ... LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { | ^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `NonObjectSafe2` cannot be made into an object --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:36 @@ -44,8 +42,6 @@ LL | trait NonObjectSafe1: Sized {} ... LL | impl Trait for dyn NonObjectSafe1 {} | ^^^^^ the trait `NonObjectSafe1` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error: aborting due to 5 previous errors diff --git a/src/test/ui/issues/issue-20692.rs b/src/test/ui/issues/issue-20692.rs index 2a05bba7b16..1cb2d8c7302 100644 --- a/src/test/ui/issues/issue-20692.rs +++ b/src/test/ui/issues/issue-20692.rs @@ -1,4 +1,4 @@ -trait Array: Sized {} +trait Array: Sized + Copy {} fn f(x: &T) { let _ = x diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index 4757742a707..62efdfb2e91 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -1,24 +1,25 @@ error[E0038]: the trait `Array` cannot be made into an object --> $DIR/issue-20692.rs:7:5 | -LL | trait Array: Sized {} - | ----- the trait cannot require that `Self : Sized` +LL | trait Array: Sized + Copy {} + | ----- ---- the trait cannot require that `Self : Sized` + | | + | the trait cannot require that `Self : Sized` ... LL | &dyn Array; | ^^^^^^^^^^ the trait `Array` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Array` cannot be made into an object --> $DIR/issue-20692.rs:4:13 | -LL | trait Array: Sized {} - | ----- the trait cannot require that `Self : Sized` +LL | trait Array: Sized + Copy {} + | ----- ---- the trait cannot require that `Self : Sized` + | | + | the trait cannot require that `Self : Sized` ... LL | let _ = x | ^ the trait `Array` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T` = note: required by cast to type `&dyn Array` diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr index da1a7a7520e..a0ecca3020e 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -12,18 +12,21 @@ LL | take_param(&x); error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:19 | +LL | trait Foo : Copy { + | ---- the trait cannot require that `Self : Sized` +... LL | let z = &x as &dyn Foo; | ^^^^^^^^ the trait `Foo` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:13 | +LL | trait Foo : Copy { + | ---- the trait cannot require that `Self : Sized` +... LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>` = note: required by cast to type `&dyn Foo` diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index f272f829ba6..5694150ed7c 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -12,10 +12,12 @@ LL | take_param(&x); error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:13 | +LL | trait Foo : Copy { + | ---- the trait cannot require that `Self : Sized` +... LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box` = note: required by cast to type `&dyn Foo` diff --git a/src/test/ui/object-safety/object-safety-sized.curr.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr index be0a2519a46..473c8f8e6fa 100644 --- a/src/test/ui/object-safety/object-safety-sized.curr.stderr +++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr @@ -6,8 +6,6 @@ LL | trait Bar : Sized { ... LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^ the trait `Bar` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr index c20ddee54c0..217e2aa00da 100644 --- a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -7,7 +7,6 @@ LL | trait Bar : Sized { LL | t | ^ the trait `Bar` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr index f1c1a6bb972..91fa144032f 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr @@ -18,8 +18,6 @@ LL | trait A: Sized { | ----- the trait cannot require that `Self : Sized` LL | fn f(a: A) -> A; | ^ the trait `A` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` error: associated item referring to unboxed trait object for its own trait --> $DIR/object-unsafe-trait-should-use-self.rs:8:13 diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr index 4c033cfcd89..461ad97f2f0 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -7,7 +7,6 @@ LL | trait Trait: Sized {} LL | let t_box: Box = Box::new(S); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` = note: required by cast to type `std::boxed::Box` @@ -20,7 +19,6 @@ LL | trait Trait: Sized {} LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>` @@ -33,7 +31,6 @@ LL | trait Trait: Sized {} LL | Box::new(S) as Box; | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` = note: required by cast to type `std::boxed::Box` diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr index ba3792c362e..6fc57369b4e 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -7,7 +7,6 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = &S; | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` @@ -20,7 +19,6 @@ LL | trait Trait: Sized {} LL | takes_trait(&S); | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` @@ -33,7 +31,6 @@ LL | trait Trait: Sized {} LL | &S as &dyn Trait; | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr index a0082578d4d..36c60aefa6b 100644 --- a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -21,7 +21,6 @@ LL | trait Trait: Sized {} LL | Some(()) => &S, | ^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` @@ -34,7 +33,6 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = match opt() { | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R` = note: required by cast to type `&dyn Trait`