From de6b219803421da9f50a85c108847c51abf2e74a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 23 Apr 2024 14:52:54 -0400 Subject: [PATCH] Make WHERE_CLAUSES_OBJECT_SAFETY a regular object safety violation --- compiler/rustc_lint_defs/src/builtin.rs | 42 ---------- .../src/traits/object_safety.rs | 81 +------------------ src/tools/miri/tests/fail/issue-miri-2432.rs | 19 ----- .../miri/tests/fail/issue-miri-2432.stderr | 15 ---- .../object-safety-err-where-bounds.rs | 5 +- .../object-safety-err-where-bounds.stderr | 35 +++++--- tests/ui/issues/issue-50781.rs | 8 +- tests/ui/issues/issue-50781.stderr | 52 +++++++++--- tests/ui/object-safety/issue-106247.rs | 2 - tests/ui/traits/vtable/vtable-vacant.rs | 1 - tests/ui/traits/vtable/vtable-vacant.stderr | 2 +- .../self-in-where-clause-allowed.rs | 1 - .../self-in-where-clause-allowed.stderr | 4 +- 13 files changed, 75 insertions(+), 192 deletions(-) delete mode 100644 src/tools/miri/tests/fail/issue-miri-2432.rs delete mode 100644 src/tools/miri/tests/fail/issue-miri-2432.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 93995fe60a3..a3044489fdc 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -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() { ::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 ", - }; -} - declare_lint! { /// The `proc_macro_derive_resolution_fallback` lint detects proc macro /// derives using inaccessible names from parent modules. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0f32b6ef9e3..201f71b079b 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -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 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 \ - ", - ); - 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>, diff --git a/src/tools/miri/tests/fail/issue-miri-2432.rs b/src/tools/miri/tests/fail/issue-miri-2432.rs deleted file mode 100644 index f822479c436..00000000000 --- a/src/tools/miri/tests/fail/issue-miri-2432.rs +++ /dev/null @@ -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() { - ::foo(&()); //~ERROR: trying to call something that is not a method -} diff --git a/src/tools/miri/tests/fail/issue-miri-2432.stderr b/src/tools/miri/tests/fail/issue-miri-2432.stderr deleted file mode 100644 index 3befe31dc5a..00000000000 --- a/src/tools/miri/tests/fail/issue-miri-2432.stderr +++ /dev/null @@ -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 | ::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 - diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs index 42c1cc507b5..b3bbb842638 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs @@ -1,14 +1,11 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -#![deny(where_clauses_object_safety)] const fn bar() -> usize { 7 } trait Foo { fn test(&self) where [u8; bar::()]: 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() {} diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr index 9e480ce9b85..fde5d3ce772 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr @@ -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::()]: 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 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 - --> $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::()]: 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 + --> $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::()]: 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`. diff --git a/tests/ui/issues/issue-50781.rs b/tests/ui/issues/issue-50781.rs index 3c5e5a9f69a..32253c3c236 100644 --- a/tests/ui/issues/issue-50781.rs +++ b/tests/ui/issues/issue-50781.rs @@ -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. ::foo(&()); + //~^ ERROR the trait `X` cannot be made into an object + //~| ERROR the trait `X` cannot be made into an object } diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr index beaea1e634c..6b0b42ca53a 100644 --- a/tests/ui/issues/issue-50781.stderr +++ b/tests/ui/issues/issue-50781.stderr @@ -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 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 - --> $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 | ::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 + --> $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 | ::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 + --> $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`. diff --git a/tests/ui/object-safety/issue-106247.rs b/tests/ui/object-safety/issue-106247.rs index 78bae568161..20a451a59a1 100644 --- a/tests/ui/object-safety/issue-106247.rs +++ b/tests/ui/object-safety/issue-106247.rs @@ -1,7 +1,5 @@ //@ check-pass -#![deny(where_clauses_object_safety)] - pub trait Trait { fn method(&self) where Self: Sync; } diff --git a/tests/ui/traits/vtable/vtable-vacant.rs b/tests/ui/traits/vtable/vtable-vacant.rs index 26de3f60621..b3c76815703 100644 --- a/tests/ui/traits/vtable/vtable-vacant.rs +++ b/tests/ui/traits/vtable/vtable-vacant.rs @@ -1,7 +1,6 @@ //@ build-fail #![feature(rustc_attrs)] #![feature(negative_impls)] -#![allow(where_clauses_object_safety)] // B --> A diff --git a/tests/ui/traits/vtable/vtable-vacant.stderr b/tests/ui/traits/vtable/vtable-vacant.stderr index 9ce1d0b7632..f6961ca010e 100644 --- a/tests/ui/traits/vtable/vtable-vacant.stderr +++ b/tests/ui/traits/vtable/vtable-vacant.stderr @@ -7,7 +7,7 @@ error: vtable entries for ``: [ Method(::foo_b1), Vacant, ] - --> $DIR/vtable-vacant.rs:15:1 + --> $DIR/vtable-vacant.rs:14:1 | LL | trait B: A { | ^^^^^^^^^^ diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.rs b/tests/ui/where-clauses/self-in-where-clause-allowed.rs index fd2cfe2bf65..a4c2d82b483 100644 --- a/tests/ui/where-clauses/self-in-where-clause-allowed.rs +++ b/tests/ui/where-clauses/self-in-where-clause-allowed.rs @@ -1,7 +1,6 @@ //@ check-fail #![feature(auto_traits)] -#![deny(where_clauses_object_safety)] auto trait AutoTrait {} diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.stderr b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr index 7f92ac102f0..5d23c4bee00 100644 --- a/tests/ui/where-clauses/self-in-where-clause-allowed.stderr +++ b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr @@ -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`