Skip to content

Commit

Permalink
Improve some diagnostics around ?Trait bounds
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Oct 30, 2023
1 parent 6d1fc53 commit 455cf5a
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 58 deletions.
57 changes: 31 additions & 26 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}
}
};
Expand All @@ -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`)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Span>,
}

#[derive(Diagnostic)]
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/issues/issue-37534.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
struct Foo<T: ?Hash> { }
struct Foo<T: ?Hash> {}
//~^ 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() {}
12 changes: 6 additions & 6 deletions tests/ui/issues/issue-37534.stderr
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
error[E0404]: expected trait, found derive macro `Hash`
--> $DIR/issue-37534.rs:1:16
|
LL | struct Foo<T: ?Hash> { }
LL | struct Foo<T: ?Hash> {}
| ^^^^ not a trait
|
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<T: ?Hash> { }
| ^
LL | struct Foo<T: ?Hash> {}
| ^^^^^

error[E0392]: parameter `T` is never used
--> $DIR/issue-37534.rs:1:12
|
LL | struct Foo<T: ?Hash> { }
LL | struct Foo<T: ?Hash> {}
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/issues/issue-87199.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

// Check that these function definitions only emit warnings, not errors
fn arg<T: ?Send>(_: 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: ?Send>(_: &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<Item = ()> + ?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() {
Expand Down
18 changes: 9 additions & 9 deletions tests/ui/issues/issue-87199.stderr
Original file line number Diff line number Diff line change
@@ -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: ?Send>(_: 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: ?Send>(_: &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<Item = ()> + ?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
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/unsized/maybe-bounds-where.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ trait Trait<'a> {}

struct S4<T>(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<T>(*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<T> S1<T> {
fn f() where T: ?Sized {}
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/unsized/maybe-bounds-where.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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>(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<T>(*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<T>(*const T) where T: ?Trait<'static> + ?Sized;
| ^
| ^^^^^^^^^^^^^^^

error: aborting due to 6 previous errors; 2 warnings emitted

Expand Down

0 comments on commit 455cf5a

Please sign in to comment.