Skip to content

Commit 78ef946

Browse files
committed
Account for object unsafe traits
Fix #119525.
1 parent 771966b commit 78ef946

File tree

4 files changed

+98
-25
lines changed

4 files changed

+98
-25
lines changed

compiler/rustc_hir_analysis/src/astconv/lint.rs

+41-25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_ast::TraitObjectSyntax;
22
use rustc_errors::{Diagnostic, StashKey};
33
use rustc_hir as hir;
4+
use rustc_hir::def::{DefKind, Res};
45
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
56
use rustc_span::Span;
67
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
@@ -90,15 +91,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
9091
return false;
9192
};
9293
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
94+
let is_object_safe = match self_ty.kind {
95+
hir::TyKind::TraitObject(objects, ..) => {
96+
objects.iter().all(|o| match o.trait_ref.path.res {
97+
Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
98+
_ => false,
99+
})
100+
}
101+
_ => false,
102+
};
93103
if let hir::FnRetTy::Return(ty) = sig.decl.output
94104
&& ty.hir_id == self_ty.hir_id
95105
{
96-
diag.multipart_suggestion_verbose(
97-
format!("use `impl {trait_name}` to return an opaque type, as long as you return a single underlying type"),
98-
impl_sugg,
99-
Applicability::MachineApplicable,
106+
let pre = if !is_object_safe {
107+
format!("`{trait_name}` is not object safe, ")
108+
} else {
109+
String::new()
110+
};
111+
let msg = format!(
112+
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
113+
single underlying type",
100114
);
101-
if tcx.check_is_object_safe(def_id) {
115+
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
116+
if is_object_safe {
102117
diag.multipart_suggestion_verbose(
103118
"alternatively, you can return an owned trait object",
104119
vec![
@@ -111,25 +126,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
111126
return true;
112127
}
113128
for ty in sig.decl.inputs {
114-
if ty.hir_id == self_ty.hir_id {
115-
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
116-
if !sugg.is_empty() {
117-
diag.multipart_suggestion_verbose(
118-
format!("use a new generic type parameter, constrained by `{trait_name}`"),
119-
sugg,
120-
Applicability::MachineApplicable,
121-
);
122-
diag.multipart_suggestion_verbose(
123-
"you can also use an opaque type, but users won't be able to specify the \
124-
type parameter when calling the `fn`, having to rely exclusively on type \
125-
inference",
126-
impl_sugg,
127-
Applicability::MachineApplicable,
128-
);
129-
}
130-
if !tcx.check_is_object_safe(def_id) {
131-
diag.note(format!("it is not object safe, so it can't be `dyn`"));
132-
}
129+
if ty.hir_id != self_ty.hir_id {
130+
continue;
131+
}
132+
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
133+
if !sugg.is_empty() {
134+
diag.multipart_suggestion_verbose(
135+
format!("use a new generic type parameter, constrained by `{trait_name}`"),
136+
sugg,
137+
Applicability::MachineApplicable,
138+
);
139+
diag.multipart_suggestion_verbose(
140+
"you can also use an opaque type, but users won't be able to specify the type \
141+
parameter when calling the `fn`, having to rely exclusively on type inference",
142+
impl_sugg,
143+
Applicability::MachineApplicable,
144+
);
145+
}
146+
if !is_object_safe {
147+
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
148+
} else {
133149
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
134150
// There are more than one trait bound, we need surrounding parentheses.
135151
vec![
@@ -147,8 +163,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
147163
sugg,
148164
Applicability::MachineApplicable,
149165
);
150-
return true;
151166
}
167+
return true;
152168
}
153169
false
154170
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
#![deny(bare_trait_objects)]
3+
fn ord_prefer_dot(s: String) -> impl Ord {
4+
//~^ ERROR trait objects without an explicit `dyn` are deprecated
5+
//~| ERROR the trait `Ord` cannot be made into an object
6+
//~| WARNING this is accepted in the current edition (Rust 2015)
7+
(s.starts_with("."), s)
8+
}
9+
fn main() {
10+
let _ = ord_prefer_dot(String::new());
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
#![deny(bare_trait_objects)]
3+
fn ord_prefer_dot(s: String) -> Ord {
4+
//~^ ERROR trait objects without an explicit `dyn` are deprecated
5+
//~| ERROR the trait `Ord` cannot be made into an object
6+
//~| WARNING this is accepted in the current edition (Rust 2015)
7+
(s.starts_with("."), s)
8+
}
9+
fn main() {
10+
let _ = ord_prefer_dot(String::new());
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: trait objects without an explicit `dyn` are deprecated
2+
--> $DIR/bare-trait-dont-suggest-dyn.rs:3:33
3+
|
4+
LL | fn ord_prefer_dot(s: String) -> Ord {
5+
| ^^^
6+
|
7+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
8+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
9+
note: the lint level is defined here
10+
--> $DIR/bare-trait-dont-suggest-dyn.rs:2:9
11+
|
12+
LL | #![deny(bare_trait_objects)]
13+
| ^^^^^^^^^^^^^^^^^^
14+
help: `Ord` is not object safe, use `impl Ord` to return an opaque type, as long as you return a single underlying type
15+
|
16+
LL | fn ord_prefer_dot(s: String) -> impl Ord {
17+
| ++++
18+
19+
error[E0038]: the trait `Ord` cannot be made into an object
20+
--> $DIR/bare-trait-dont-suggest-dyn.rs:3:33
21+
|
22+
LL | fn ord_prefer_dot(s: String) -> Ord {
23+
| ^^^ `Ord` cannot be made into an object
24+
|
25+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
26+
--> $SRC_DIR/core/src/cmp.rs:LL:COL
27+
|
28+
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
29+
::: $SRC_DIR/core/src/cmp.rs:LL:COL
30+
|
31+
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
32+
33+
error: aborting due to 2 previous errors
34+
35+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)