Make WHERE_CLAUSES_OBJECT_SAFETY a regular object safety violation
This commit is contained in:
parent
8768db9912
commit
de6b219803
@ -136,7 +136,6 @@
|
||||
USELESS_DEPRECATED,
|
||||
WARNINGS,
|
||||
WASM_C_ABI,
|
||||
WHERE_CLAUSES_OBJECT_SAFETY,
|
||||
WRITES_THROUGH_IMMUTABLE_POINTER,
|
||||
// tidy-alphabetical-end
|
||||
]
|
||||
@ -2093,47 +2092,6 @@
|
||||
"detects labels that are never used"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `where_clauses_object_safety` lint detects for [object safety] of
|
||||
/// [where clauses].
|
||||
///
|
||||
/// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
|
||||
/// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// trait Trait {}
|
||||
///
|
||||
/// trait X { fn foo(&self) where Self: Trait; }
|
||||
///
|
||||
/// impl X for () { fn foo(&self) {} }
|
||||
///
|
||||
/// impl Trait for dyn X {}
|
||||
///
|
||||
/// // Segfault at opt-level 0, SIGILL otherwise.
|
||||
/// pub fn main() { <dyn X as X>::foo(&()); }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The compiler previously allowed these object-unsafe bounds, which was
|
||||
/// incorrect. This is a [future-incompatible] lint to transition this to
|
||||
/// a hard error in the future. See [issue #51443] for more details.
|
||||
///
|
||||
/// [issue #51443]: https://github.com/rust-lang/rust/issues/51443
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub WHERE_CLAUSES_OBJECT_SAFETY,
|
||||
Warn,
|
||||
"checks the object safety of where clauses",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `proc_macro_derive_resolution_fallback` lint detects proc macro
|
||||
/// derives using inaccessible names from parent modules.
|
||||
|
@ -13,7 +13,7 @@
|
||||
use crate::infer::TyCtxtInferExt;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{self, Obligation, ObligationCause};
|
||||
use rustc_errors::{FatalError, MultiSpan};
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::query::Providers;
|
||||
@ -23,7 +23,6 @@
|
||||
};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgs};
|
||||
use rustc_middle::ty::{TypeVisitableExt, Upcast};
|
||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::Abi;
|
||||
@ -66,44 +65,13 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object
|
||||
}
|
||||
|
||||
fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||
let violations = tcx.object_safety_violations(trait_def_id);
|
||||
|
||||
if violations.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the trait contains any other violations, then let the error reporting path
|
||||
// report it instead of emitting a warning here.
|
||||
if violations.iter().all(|violation| {
|
||||
matches!(
|
||||
violation,
|
||||
ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _)
|
||||
)
|
||||
}) {
|
||||
for violation in violations {
|
||||
if let ObjectSafetyViolation::Method(
|
||||
_,
|
||||
MethodViolationCode::WhereClauseReferencesSelf,
|
||||
span,
|
||||
) = violation
|
||||
{
|
||||
lint_object_unsafe_trait(tcx, *span, trait_def_id, violation);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
tcx.object_safety_violations(trait_def_id).is_empty()
|
||||
}
|
||||
|
||||
/// We say a method is *vtable safe* if it can be invoked on a trait
|
||||
/// object. Note that object-safe traits can have some
|
||||
/// non-vtable-safe methods, so long as they require `Self: Sized` or
|
||||
/// otherwise ensure that they cannot be used when `Self = Trait`.
|
||||
///
|
||||
/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards
|
||||
/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and
|
||||
/// [`WHERE_CLAUSES_OBJECT_SAFETY`].
|
||||
pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
|
||||
debug_assert!(tcx.generics_of(trait_def_id).has_self);
|
||||
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
|
||||
@ -112,9 +80,7 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual_call_violations_for_method(tcx, trait_def_id, method)
|
||||
.iter()
|
||||
.all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf))
|
||||
virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty()
|
||||
}
|
||||
|
||||
fn object_safety_violations_for_trait(
|
||||
@ -163,47 +129,6 @@ fn object_safety_violations_for_trait(
|
||||
violations
|
||||
}
|
||||
|
||||
/// Lint object-unsafe trait.
|
||||
fn lint_object_unsafe_trait(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
violation: &ObjectSafetyViolation,
|
||||
) {
|
||||
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
|
||||
// It's also hard to get a use site span, so we use the method definition span.
|
||||
tcx.node_span_lint(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |err| {
|
||||
err.primary_message(format!(
|
||||
"the trait `{}` cannot be made into an object",
|
||||
tcx.def_path_str(trait_def_id)
|
||||
));
|
||||
let node = tcx.hir().get_if_local(trait_def_id);
|
||||
let mut spans = MultiSpan::from_span(span);
|
||||
if let Some(hir::Node::Item(item)) = node {
|
||||
spans.push_span_label(item.ident.span, "this trait cannot be made into an object...");
|
||||
spans.push_span_label(span, format!("...because {}", violation.error_msg()));
|
||||
} else {
|
||||
spans.push_span_label(
|
||||
span,
|
||||
format!(
|
||||
"the trait cannot be made into an object because {}",
|
||||
violation.error_msg()
|
||||
),
|
||||
);
|
||||
};
|
||||
err.span_note(
|
||||
spans,
|
||||
"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>",
|
||||
);
|
||||
if node.is_some() {
|
||||
// Only provide the help if its a local trait, otherwise it's not
|
||||
violation.solution().add_to(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn sized_trait_bound_spans<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
bounds: hir::GenericBounds<'tcx>,
|
||||
|
@ -1,19 +0,0 @@
|
||||
#![allow(where_clauses_object_safety)]
|
||||
|
||||
trait Trait {}
|
||||
|
||||
trait X {
|
||||
fn foo(&self)
|
||||
where
|
||||
Self: Trait;
|
||||
}
|
||||
|
||||
impl X for () {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
impl Trait for dyn X {}
|
||||
|
||||
pub fn main() {
|
||||
<dyn X as X>::foo(&()); //~ERROR: trying to call something that is not a method
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
error: Undefined Behavior: `dyn` call trying to call something that is not a method
|
||||
--> $DIR/issue-miri-2432.rs:LL:CC
|
||||
|
|
||||
LL | <dyn X as X>::foo(&());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ `dyn` call trying to call something that is not a method
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/issue-miri-2432.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -1,14 +1,11 @@
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
#![deny(where_clauses_object_safety)]
|
||||
|
||||
|
||||
const fn bar<T: ?Sized>() -> usize { 7 }
|
||||
|
||||
trait Foo {
|
||||
fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||
//~| WARN this was previously accepted by the compiler but is being phased out
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
@ -16,7 +13,9 @@ impl Foo for () {
|
||||
}
|
||||
|
||||
fn use_dyn(v: &dyn Foo) {
|
||||
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||
v.test();
|
||||
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,24 +1,35 @@
|
||||
error: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/object-safety-err-where-bounds.rs:9:8
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/object-safety-err-where-bounds.rs:15:16
|
||||
|
|
||||
LL | fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
| ^^^^
|
||||
LL | fn use_dyn(v: &dyn Foo) {
|
||||
| ^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
|
||||
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>
|
||||
--> $DIR/object-safety-err-where-bounds.rs:9:8
|
||||
--> $DIR/object-safety-err-where-bounds.rs:8:8
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
LL | fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
| ^^^^ ...because method `test` references the `Self` type in its `where` clause
|
||||
= help: consider moving `test` to another trait
|
||||
note: the lint level is defined here
|
||||
--> $DIR/object-safety-err-where-bounds.rs:3:9
|
||||
= help: only type `()` implements the trait, consider using it directly instead
|
||||
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/object-safety-err-where-bounds.rs:17:5
|
||||
|
|
||||
LL | #![deny(where_clauses_object_safety)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | v.test();
|
||||
| ^^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
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>
|
||||
--> $DIR/object-safety-err-where-bounds.rs:8:8
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
LL | fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
| ^^^^ ...because method `test` references the `Self` type in its `where` clause
|
||||
= help: consider moving `test` to another trait
|
||||
= help: only type `()` implements the trait, consider using it directly instead
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
||||
|
@ -1,10 +1,7 @@
|
||||
#![deny(where_clauses_object_safety)]
|
||||
|
||||
trait Trait {}
|
||||
|
||||
trait X {
|
||||
fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object
|
||||
//~^ WARN this was previously accepted by the compiler but is being phased out
|
||||
fn foo(&self) where Self: Trait;
|
||||
}
|
||||
|
||||
impl X for () {
|
||||
@ -12,8 +9,11 @@ fn foo(&self) {}
|
||||
}
|
||||
|
||||
impl Trait for dyn X {}
|
||||
//~^ ERROR the trait `X` cannot be made into an object
|
||||
|
||||
pub fn main() {
|
||||
// Check that this does not segfault.
|
||||
<dyn X as X>::foo(&());
|
||||
//~^ ERROR the trait `X` cannot be made into an object
|
||||
//~| ERROR the trait `X` cannot be made into an object
|
||||
}
|
||||
|
@ -1,24 +1,52 @@
|
||||
error: the trait `X` cannot be made into an object
|
||||
--> $DIR/issue-50781.rs:6:8
|
||||
error[E0038]: the trait `X` cannot be made into an object
|
||||
--> $DIR/issue-50781.rs:11:16
|
||||
|
|
||||
LL | fn foo(&self) where Self: Trait;
|
||||
| ^^^
|
||||
LL | impl Trait for dyn X {}
|
||||
| ^^^^^ `X` cannot be made into an object
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
|
||||
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>
|
||||
--> $DIR/issue-50781.rs:6:8
|
||||
--> $DIR/issue-50781.rs:4:8
|
||||
|
|
||||
LL | trait X {
|
||||
| - this trait cannot be made into an object...
|
||||
LL | fn foo(&self) where Self: Trait;
|
||||
| ^^^ ...because method `foo` references the `Self` type in its `where` clause
|
||||
= help: consider moving `foo` to another trait
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-50781.rs:1:9
|
||||
= help: only type `()` implements the trait, consider using it directly instead
|
||||
|
||||
error[E0038]: the trait `X` cannot be made into an object
|
||||
--> $DIR/issue-50781.rs:16:23
|
||||
|
|
||||
LL | #![deny(where_clauses_object_safety)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | <dyn X as X>::foo(&());
|
||||
| ^^^ `X` cannot be made into an object
|
||||
|
|
||||
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>
|
||||
--> $DIR/issue-50781.rs:4:8
|
||||
|
|
||||
LL | trait X {
|
||||
| - this trait cannot be made into an object...
|
||||
LL | fn foo(&self) where Self: Trait;
|
||||
| ^^^ ...because method `foo` references the `Self` type in its `where` clause
|
||||
= help: consider moving `foo` to another trait
|
||||
= help: only type `()` implements the trait, consider using it directly instead
|
||||
= note: required for the cast from `&()` to `&dyn X`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0038]: the trait `X` cannot be made into an object
|
||||
--> $DIR/issue-50781.rs:16:6
|
||||
|
|
||||
LL | <dyn X as X>::foo(&());
|
||||
| ^^^^^ `X` cannot be made into an object
|
||||
|
|
||||
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>
|
||||
--> $DIR/issue-50781.rs:4:8
|
||||
|
|
||||
LL | trait X {
|
||||
| - this trait cannot be made into an object...
|
||||
LL | fn foo(&self) where Self: Trait;
|
||||
| ^^^ ...because method `foo` references the `Self` type in its `where` clause
|
||||
= help: consider moving `foo` to another trait
|
||||
= help: only type `()` implements the trait, consider using it directly instead
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
||||
|
@ -1,7 +1,5 @@
|
||||
//@ check-pass
|
||||
|
||||
#![deny(where_clauses_object_safety)]
|
||||
|
||||
pub trait Trait {
|
||||
fn method(&self) where Self: Sync;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ build-fail
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(negative_impls)]
|
||||
#![allow(where_clauses_object_safety)]
|
||||
|
||||
// B --> A
|
||||
|
||||
|
@ -7,7 +7,7 @@ error: vtable entries for `<S as B>`: [
|
||||
Method(<S as B>::foo_b1),
|
||||
Vacant,
|
||||
]
|
||||
--> $DIR/vtable-vacant.rs:15:1
|
||||
--> $DIR/vtable-vacant.rs:14:1
|
||||
|
|
||||
LL | trait B: A {
|
||||
| ^^^^^^^^^^
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ check-fail
|
||||
|
||||
#![feature(auto_traits)]
|
||||
#![deny(where_clauses_object_safety)]
|
||||
|
||||
auto trait AutoTrait {}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0277]: the trait bound `dyn Trait: AutoTrait` is not satisfied
|
||||
--> $DIR/self-in-where-clause-allowed.rs:22:18
|
||||
--> $DIR/self-in-where-clause-allowed.rs:21:18
|
||||
|
|
||||
LL | trait_object.autotrait_bound();
|
||||
| ^^^^^^^^^^^^^^^ the trait `AutoTrait` is not implemented for `dyn Trait`
|
||||
|
|
||||
note: required by a bound in `Trait::autotrait_bound`
|
||||
--> $DIR/self-in-where-clause-allowed.rs:13:43
|
||||
--> $DIR/self-in-where-clause-allowed.rs:12:43
|
||||
|
|
||||
LL | fn autotrait_bound(&self) where Self: AutoTrait {}
|
||||
| ^^^^^^^^^ required by this bound in `Trait::autotrait_bound`
|
||||
|
Loading…
Reference in New Issue
Block a user