diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 711da6db5accb..3e700f2da8696 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt}; use rustc_span::symbol::Ident; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; +use smallvec::SmallVec; use crate::astconv::{ AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter, @@ -28,15 +29,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { let tcx = self.tcx(); // Try to find an unbound in bounds. - let mut unbound = None; + let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| { for ab in ast_bounds { if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(&ptr.trait_ref); - } else { - tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span }); - } + unbounds.push(ptr) } } }; @@ -51,33 +48,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } } + if unbounds.len() > 1 { + tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { + spans: unbounds.iter().map(|ptr| ptr.span).collect(), + }); + } + let sized_def_id = tcx.lang_items().sized_trait(); - match (&sized_def_id, unbound) { - (Some(sized_def_id), Some(tpb)) - if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) => - { - // There was in fact a `?Sized` bound, return without doing anything - return; - } - (_, Some(_)) => { - // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default; only `?Sized` is supported", - ); - // Otherwise, add implicitly sized if `Sized` is available. - } - _ => { - // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + + let mut seen_sized_unbound = false; + for unbound in unbounds { + if let Some(sized_def_id) = sized_def_id { + if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { + seen_sized_unbound = true; + continue; + } } + // There was a `?Trait` bound, but it was not `?Sized`; warn. + tcx.sess.span_warn( + unbound.span, + "relaxing a default bound only does something for `?Sized`; \ + all other traits are not bound by default", + ); } + + // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available. if sized_def_id.is_none() { // No lang item for `Sized`, so we can't add it as a bound. return; } - bounds.push_sized(tcx, self_ty, span); + if seen_sized_unbound { + // There was in fact a `?Sized` bound, return without doing anything + } else { + // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + bounds.push_sized(tcx, self_ty, span); + } } /// This helper takes a *converted* parameter type (`param_ty`) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 6a2db1d06276c..dd83b5b6f2c03 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -96,7 +96,7 @@ pub struct CopyImplOnTypeWithDtor { #[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")] pub struct MultipleRelaxedDefaultBounds { #[primary_span] - pub span: Span, + pub spans: Vec, } #[derive(Diagnostic)] diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs index 1e67e9a815830..40f7186db098e 100644 --- a/tests/ui/issues/issue-37534.rs +++ b/tests/ui/issues/issue-37534.rs @@ -1,6 +1,6 @@ -struct Foo { } +struct Foo {} //~^ ERROR expected trait, found derive macro `Hash` //~^^ ERROR parameter `T` is never used -//~^^^ WARN default bound relaxed for a type parameter, but this does nothing +//~^^^ WARN relaxing a default bound only does something for `?Sized` -fn main() { } +fn main() {} diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 7d3dd8800bd34..03fea2c16486d 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -1,7 +1,7 @@ error[E0404]: expected trait, found derive macro `Hash` --> $DIR/issue-37534.rs:1:16 | -LL | struct Foo { } +LL | struct Foo {} | ^^^^ not a trait | help: consider importing this trait instead @@ -9,16 +9,16 @@ help: consider importing this trait instead LL + use std::hash::Hash; | -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/issue-37534.rs:1:12 +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/issue-37534.rs:1:15 | -LL | struct Foo { } - | ^ +LL | struct Foo {} + | ^^^^^ error[E0392]: parameter `T` is never used --> $DIR/issue-37534.rs:1:12 | -LL | struct Foo { } +LL | struct Foo {} | ^ unused parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs index a80a64a2f87ee..d16d406767300 100644 --- a/tests/ui/issues/issue-87199.rs +++ b/tests/ui/issues/issue-87199.rs @@ -6,11 +6,11 @@ // Check that these function definitions only emit warnings, not errors fn arg(_: T) {} -//~^ warning: default bound relaxed for a type parameter, but this does nothing +//~^ warning: relaxing a default bound only does something for `?Sized` fn ref_arg(_: &T) {} -//~^ warning: default bound relaxed for a type parameter, but this does nothing +//~^ warning: relaxing a default bound only does something for `?Sized` fn ret() -> impl Iterator + ?Send { std::iter::empty() } -//~^ warning: default bound relaxed for a type parameter, but this does nothing +//~^ warning: relaxing a default bound only does something for `?Sized` // Check that there's no `?Sized` relaxation! fn main() { diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr index 67949b37d4099..e02cd7fcfa9e4 100644 --- a/tests/ui/issues/issue-87199.stderr +++ b/tests/ui/issues/issue-87199.stderr @@ -1,20 +1,20 @@ -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/issue-87199.rs:8:8 +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/issue-87199.rs:8:11 | LL | fn arg(_: T) {} - | ^ + | ^^^^^ -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/issue-87199.rs:10:12 +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/issue-87199.rs:10:15 | LL | fn ref_arg(_: &T) {} - | ^ + | ^^^^^ -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/issue-87199.rs:12:13 +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error[E0277]: the size for values of type `[i32]` cannot be known at compilation time --> $DIR/issue-87199.rs:18:15 diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/maybe-bounds-where.rs index d7af0c4248056..7e82a3eb449cb 100644 --- a/tests/ui/unsized/maybe-bounds-where.rs +++ b/tests/ui/unsized/maybe-bounds-where.rs @@ -11,11 +11,11 @@ trait Trait<'a> {} struct S4(T) where for<'a> T: ?Trait<'a>; //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared -//~| WARN default bound relaxed for a type parameter +//~| WARN relaxing a default bound only does something for `?Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~^ ERROR type parameter has more than one relaxed default bound -//~| WARN default bound relaxed for a type parameter +//~| WARN relaxing a default bound only does something for `?Sized` impl S1 { fn f() where T: ?Sized {} diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/maybe-bounds-where.stderr index 39bc1b88e56d7..683bd387bb292 100644 --- a/tests/ui/unsized/maybe-bounds-where.stderr +++ b/tests/ui/unsized/maybe-bounds-where.stderr @@ -28,23 +28,23 @@ error: `?Trait` bounds are only permitted at the point where a type parameter is LL | fn f() where T: ?Sized {} | ^^^^^^ -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/maybe-bounds-where.rs:12:11 +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; - | ^ + | ^^^^^^^^^^ error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/maybe-bounds-where.rs:16:11 + --> $DIR/maybe-bounds-where.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; - | ^ + | ^^^^^^^^^^^^^^^ ^^^^^^ -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/maybe-bounds-where.rs:16:11 +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; - | ^ + | ^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors; 2 warnings emitted