Skip to content

Commit a602654

Browse files
committed
Make where clause object safety be a warn-by-default lint
1 parent 1453b3a commit a602654

File tree

7 files changed

+61
-13
lines changed

7 files changed

+61
-13
lines changed

src/librustc/lint/builtin.rs

+7
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,12 @@ declare_lint! {
304304
"warn about documentation intra links resolution failure"
305305
}
306306

307+
declare_lint! {
308+
pub WHERE_CLAUSES_OBJECT_SAFETY,
309+
Warn,
310+
"checks the object safety of where clauses"
311+
}
312+
307313
/// Does nothing as a lint pass, but registers some `Lint`s
308314
/// which are used by other parts of the compiler.
309315
#[derive(Copy, Clone)]
@@ -358,6 +364,7 @@ impl LintPass for HardwiredLints {
358364
DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
359365
DUPLICATE_MACRO_EXPORTS,
360366
INTRA_DOC_LINK_RESOLUTION_FAILURE,
367+
WHERE_CLAUSES_OBJECT_SAFETY,
361368
)
362369
}
363370
}

src/librustc/traits/object_safety.rs

+31-3
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@
2020
use super::elaborate_predicates;
2121

2222
use hir::def_id::DefId;
23+
use lint;
2324
use traits;
2425
use ty::{self, Ty, TyCtxt, TypeFoldable};
2526
use ty::subst::Substs;
2627
use ty::util::ExplicitSelf;
2728
use std::borrow::Cow;
2829
use syntax::ast;
30+
use syntax_pos::Span;
2931

30-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
32+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
3133
pub enum ObjectSafetyViolation {
3234
/// Self : Sized declared on the trait
3335
SizedSelf,
@@ -56,6 +58,9 @@ impl ObjectSafetyViolation {
5658
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
5759
format!("method `{}` references the `Self` type \
5860
in its arguments or return type", name).into(),
61+
ObjectSafetyViolation::Method(name,
62+
MethodViolationCode::WhereClauseReferencesSelf(_)) =>
63+
format!("method `{}` references the `Self` type in where clauses", name).into(),
5964
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
6065
format!("method `{}` has generic type parameters", name).into(),
6166
ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
@@ -75,6 +80,9 @@ pub enum MethodViolationCode {
7580
/// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
7681
ReferencesSelf,
7782

83+
/// e.g. `fn foo(&self) where Self: Clone`
84+
WhereClauseReferencesSelf(Span),
85+
7886
/// e.g., `fn foo<A>()`
7987
Generic,
8088

@@ -123,6 +131,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
123131
.filter_map(|item| {
124132
self.object_safety_violation_for_method(trait_def_id, &item)
125133
.map(|code| ObjectSafetyViolation::Method(item.name, code))
134+
}).filter(|violation| {
135+
if let ObjectSafetyViolation::Method(_,
136+
MethodViolationCode::WhereClauseReferencesSelf(span)) = violation {
137+
// Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
138+
// It's also hard to get a use site span, so we use the method definition span.
139+
self.lint_node_note(
140+
lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
141+
ast::CRATE_NODE_ID,
142+
*span,
143+
&format!("the trait `{}` cannot be made into an object",
144+
self.item_path_str(trait_def_id)),
145+
&violation.error_msg());
146+
false
147+
} else {
148+
true
149+
}
126150
}).collect();
127151

128152
// Check the trait itself.
@@ -245,7 +269,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
245269
return false;
246270
}
247271

248-
self.virtual_call_violation_for_method(trait_def_id, method).is_none()
272+
match self.virtual_call_violation_for_method(trait_def_id, method) {
273+
None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
274+
Some(_) => false,
275+
}
249276
}
250277

251278
/// Returns `Some(_)` if this method cannot be called on a trait
@@ -296,7 +323,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
296323
// Do a shallow visit so that `contains_illegal_self_type_reference`
297324
// may apply it's custom visiting.
298325
.visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) {
299-
return Some(MethodViolationCode::ReferencesSelf);
326+
let span = self.def_span(method.def_id);
327+
return Some(MethodViolationCode::WhereClauseReferencesSelf(span));
300328
}
301329

302330
None

src/librustc_lint/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
292292
reference: "issue TBD",
293293
edition: Some(Edition::Edition2018),
294294
},
295+
FutureIncompatibleInfo {
296+
id: LintId::of(WHERE_CLAUSES_OBJECT_SAFETY),
297+
reference: "issue TBD",
298+
edition: None,
299+
},
295300
FutureIncompatibleInfo {
296301
id: LintId::of(DUPLICATE_ASSOCIATED_TYPE_BINDINGS),
297302
reference: "issue #50589 <https://github.com/rust-lang/rust/issues/50589>",

src/test/compile-fail/issue-43431.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![feature(fn_traits)]
1212

1313
trait CallSingle<A, B> {
14-
fn call(&self, a: A) -> B where Self: Fn(A) -> B;
14+
fn call(&self, a: A) -> B where Self: Sized, Self: Fn(A) -> B;
1515
}
1616

1717
impl<A, B, F: Fn(A) -> B> CallSingle<A, B> for F {

src/test/compile-fail/wf-trait-fn-where-clause.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
struct Bar<T:Eq+?Sized> { value: Box<T> }
1818

1919
trait Foo {
20-
fn bar(&self) where Bar<Self>: Copy;
20+
fn bar(&self) where Self: Sized, Bar<Self>: Copy;
2121
//~^ ERROR E0277
2222
//
2323
// Here, Eq ought to be implemented.

src/test/ui/issue-50781.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![deny(where_clauses_object_safety)]
12+
1113
trait Trait {}
1214

1315
trait X {
14-
fn foo(&self) where Self: Trait;
16+
fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object
17+
//~^ WARN this was previously accepted by the compiler but is being phased out
1518
}
1619

1720
impl X for () {
1821
fn foo(&self) {}
1922
}
2023

2124
impl Trait for dyn X {}
22-
//~^ ERROR the trait `X` cannot be made into an object
2325

2426
pub fn main() {
2527
// Check that this does not segfault.

src/test/ui/issue-50781.stderr

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
error[E0038]: the trait `X` cannot be made into an object
2-
--> $DIR/issue-50781.rs:21:6
1+
error: the trait `X` cannot be made into an object
2+
--> $DIR/issue-50781.rs:16:5
33
|
4-
LL | impl Trait for dyn X {}
5-
| ^^^^^ the trait `X` cannot be made into an object
4+
LL | fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: method `foo` references the `Self` type in its arguments or return type
7+
note: lint level defined here
8+
--> $DIR/issue-50781.rs:11:9
9+
|
10+
LL | #![deny(where_clauses_object_safety)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
13+
= note: for more information, see issue TBD
14+
= note: method `foo` references the `Self` type in where clauses
815

916
error: aborting due to previous error
1017

11-
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)