Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve some diagnostics around ?Trait bounds #117411

Merged
merged 1 commit into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading