Skip to content

Tracking issue for future-incompatibility lint where_clauses_object_safety #51443

Closed

Description

@leoyvens

This is the summary issue for the WHERE_CLAUSES_OBJECT_SAFETY future-compatibility warning and other related errors. The goal of this page is describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our [breaking change policy guidelines (https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md).

What is the warning for?

As was discovered in #50781 a combination of implementing a trait directly for a dyn type and where clauses involving Self can punch a hole in our dyn-capability rules rules. See the minimization:

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(&()); }

The fix applied in #50966 is to tighten the dyn-capability rules to make X not dyn-capable in this case, in general making any trait that contains Self in where clauses not dyn-capable, much like we disallow Self in arguments or return type. Few root regressions appeared in the crater run and those were fixable, though some crates being unmaintained complicates things.

However that fix is heavy handed and disallows things we actually wish to support, still we went ahead with the warning as a stop gap while we look for a better, more targeted fix. The original issue contains some discussion of alternative fixes. With tight chalk integration, we could do some clever things.

Other alternatives discussed for the short-term:

  • Checking from an impl Foo for dyn Bar + .. whether that impl is causing trouble. This seems to be a dead end because it's hard to tell which dyn types are targeted by a blanket impl such as impl<U: ?Sized + Bounds> Trait for U.
  • Checking the cast sites with a rule like "if dyn Foo: Trait then to cast T into dyn Foo we require that T: Trait must also hold", probably for every Trait such that Self: Trait appears in where clauses in the traits methods. This would alleviate the warning for Self: Trait where clauses. This may be practical to implement now, but seems subtle, we'd need to give it more thought.

When will this warning become a hard error?

Hopefully we will develop a finer-grained rule and this warning will never be an error.

How to fix this?

Either drop the where clause or stop using dyn types with the affected trait. If this is not viable, that's probably ok, it's very unlikely that your code is actually unsound. But please do report your case here so take we may take it into consideration and see how to better support it!

Activity

  1. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Jun 8, 2018
  2. nikomatsakis commented on Jun 25, 2018

    @nikomatsakis
    Contributor

    To clarify: we are specifically interested in getting feedback on places where this lint causes you issues, since that will help us to judge how well more precise fixes would work.

  3. cramertj commented on Jun 27, 2018

    @cramertj
    Member

    This caused a future-compat warning in the upcoming futures 0.3 crate. Minimized example:

    #![feature(arbitrary_self_types, pin)]
    
    use std::marker::Unpin;
    use std::mem::PinMut;
    
    trait Future {
        fn poll(self: PinMut<Self>);
    }
    
    trait FutureExt: Future {
        fn poll_unpin(&mut self) where Self: Unpin {
            PinMut::new(self).poll()
        }
    }

    The error:

    warning: the trait `FutureExt` cannot be made into an object
      --> foo.rs:11:5
       |
    11 | /     fn poll_unpin(&mut self) where Self: Unpin {
    12 | |         PinMut::new(self).poll()
    13 | |     }
       | |_____^
       |
       = note: #[warn(where_clauses_object_safety)] on by default
       = 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: method `poll_unpin` references the `Self` type in where clauses
    

    It seems like it should be possible to permit calls to poll_unpin in cases where Self is a dyn Trait type where Trait: Unpin.

  4. nikomatsakis commented on Jun 28, 2018

    @nikomatsakis
    Contributor

    Thanks @cramertj -- that falls pretty squarely into the rules we had in mind! Let's discuss the details of those rules in #50781 I guess, I want to try and "re-sync" (but I guess I'd rather keep this thread for people to report issues).

    But just to summarize, the rule we had in mind is roughly this:

    • If a trait Trait has a method method with a where-clause where Self: XXX
      • that is object-safe so long as dyn Trait: XXX cannot be proven
        • although it is a bit weird in the case where trait Trait: XXX -- we could perhaps try to distinguish those cases; in Chalk terms, XXX would be an implied bound of Trait

    That applies to your example, I believe, since dyn Future: Unpin does not hold.

    This is a kind of generalization of the rule around where Self: Sized -- except that, in that case, we know that dyn Trait: Sized could never be proven, and hence we can suspend the where-clause requirements entirely.

  5. locka99 commented on Jul 13, 2018

    @locka99

    For anyone reading this, I got the warning/error on a trait that was like this:

    pub trait Config {
        fn save(&self, path: &Path) -> Result<(), ()> where Self: serde::Serialize { ... }
    }
    

    In my case I was able to make the problem go away by requiring the thing implementing Config to also implement serde::Serialize:

    pub trait Config: serde::Serialize {
        fn save(&self, path: &Path) -> Result<(), ()> { ... }
    }
    
  6. emilio commented on Jul 30, 2018

    @emilio
    Contributor

    This broke bindgen:

    error: the trait `ir::template::TemplateParameters` cannot be made into an object
       --> src/ir/template.rs:134:5
        |
    134 | /     fn all_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
    135 | |     where
    136 | |         Self: ItemAncestors,
    137 | |     {
    ...   |
    141 | |         }).collect()
    142 | |     }
        | |_____^
        |
    note: lint level defined here
       --> src/lib.rs:11:9
        |
    11  | #![deny(warnings)]
        |         ^^^^^^^^
        = note: #[deny(where_clauses_object_safety)] implied by #[deny(warnings)]
        = 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: method `all_template_params` references the `Self` type in where clauses
    
    error: the trait `ir::template::TemplateParameters` cannot be made into an object
       --> src/ir/template.rs:147:5
        |
    147 | /     fn used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
    148 | |     where
    149 | |         Self: AsRef<ItemId>,
    150 | |     {
    ...   |
    160 | |                     .collect()
    161 | |     }
        | |_____^
        |
        = 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: method `used_template_params` references the `Self` type in where clauses
    
    error: aborting due to 2 previous errors
    
    error: Could not compile `bindgen`.
    

    This is on this bindgen commit fwiw: rust-lang/rust-bindgen@29dad40

  7. added a commit that references this issue on Jul 30, 2018
  8. Emerentius commented on Aug 1, 2018

    @Emerentius
    Contributor

    I have an extension trait that was never supposed to be made into an object which triggers this. It only exists to add a few methods.
    I could limit the implementors to just [T] down from T: AsRef<[T]> which would stop the lint from firing (and also be a better design), but it would also make the dyn capability pointless as there's only one type that could be made into the object.

    I like this as a lint but the it will become a hard error in a future release! part of the error message should go. Not all traits require dyn capability.

    Edit: In fact, the lint is a false positive. The trait isn't dyn capable already because it contains generic functions.

  9. alecmocatta commented on Aug 3, 2018

    @alecmocatta
    Contributor

    I bumped into this upcasting boxed trait objects with marker traits. There may be a way to do this safely that doesn't fall foul of this lint?

    use std::any::Any;
    
    trait Trait: Any {
    	fn into_any(self: Box<Self>) -> Box<Any>;
    	fn into_any_send(self: Box<Self>) -> Box<Any+Send> where Self: Send;
    	fn into_any_sync(self: Box<Self>) -> Box<Any+Sync> where Self: Sync;
    	fn into_any_send_sync(self: Box<Self>) -> Box<Any+Send+Sync> where Self: Send+Sync;
    }
    
    impl<T> Trait for T where T: Any {
    	fn into_any(self: Box<Self>) -> Box<Any> {
    		self
    	}
    	fn into_any_send(self: Box<Self>) -> Box<Any+Send> where Self: Send {
    		self
    	}
    	fn into_any_sync(self: Box<Self>) -> Box<Any+Sync> where Self: Sync {
    		self
    	}
    	fn into_any_send_sync(self: Box<Self>) -> Box<Any+Send+Sync> where Self: Send+Sync {
    		self
    	}
    }
    
    fn main() {
    	let a: usize = 123;
    	let b: Box<Trait+Send+Sync> = Box::new(a);
    	let c: Box<Any+Send+Sync> = b.into_any_send_sync();
    	let _d: usize = *Box::<Any>::downcast(c).unwrap();
    }

    (Playground)

  10. passcod commented on Aug 24, 2018

    @passcod
    Contributor

    This warns on AnyMap, but I don't understand enough to really figure out what's going on and how it should be fixed:

    warning: the trait `anymap::any::CloneToAny` cannot be made into an object
      --> /home/.cargo/registry/src/github.com-1ecc6299db9ec823/anymap-0.12.1/src/any.rs:21:5
       |
    21 |     fn clone_to_any_send_sync(&self) -> Box<CloneAny + Send + Sync> where Self: Send + Sync;
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       |
       = 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: method `clone_to_any_send_sync` references the `Self` type in where clauses
    
  11. rodrimati1992 commented on Sep 16, 2018

    @rodrimati1992
    Contributor

    I have an extension trait that i want to be usable with ?Sized types (including str) where this is causing a problem.

    This is the reduced version of the trait:

    trait SelfOps{
        fn piped_ref<'a,F, U>(&'a self, f: F) -> U
        where
            F: FnOnce(&'a Self) -> U,
        {
            f(self)
        }
    
        fn format_debug(&self)->String
        where Self:fmt::Debug
        {
            format!("{:?}",self)
        }
    }
    
    impl<This:?Sized> SelfOps for This{}
    
    

    With the previous 2 methods I get this somewhat confusing pair of warning and error :

    
    warning: the trait `SelfOps` cannot be made into an object
      --> src/main.rs:11:5
       |
    11 | /     fn format_debug(&self)->String
    12 | |     where Self:fmt::Debug
    13 | |     {
    14 | |         format!("{:?}",self)
    15 | |     }
       | |_____^
       |
       = 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: method `format_debug` references the `Self` type in where clauses
    
    error[E0038]: the trait `SelfOps` cannot be made into an object
      --> src/main.rs:23:18
       |
    23 |     let x=&() as &SelfOps;
       |                  ^^^^^^^^ the trait `SelfOps` cannot be made into an object
       |
       = note: method `piped_ref` has generic type parameters
    
    

    It seems to me that if it knows that it can't be turned into a trait object because it has a generic method,
    then it should not warn because of the Self type in the where clause of format_debug.

  12. 20 remaining items

  13. RalfJung commented on Jan 8, 2023

    @RalfJung
    Member

    Well, we need to change something to fix #50781. Have there been other plausible proposals?

  14. dtolnay commented on Jan 8, 2023

    @dtolnay
    Member

    Yes I tried to imply a counterproposal in the "2 reasons" in my comment.

    1. If a trait is unsafe, let it be used as bound in a where-clause of trait method of a dyn-safe trait.
    2. If a trait is an autotrait, let it be used as a bound in a where-clause of trait methods of a dyn-safe trait.
  15. added 2 commits that reference this issue on Feb 3, 2023
  16. changed the title [-]`where_clauses_object_safety` future compatibility lint[/-] [+]Tracking issue for future-incompatibility lint `where_clauses_object_safety`[/+] on Sep 14, 2024
  17. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    A-dyn-traitArea: trait objects, vtable layout
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    and removed
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Sep 14, 2024
  18. fmease commented on Sep 14, 2024

    @fmease
    Member

    This lint is no longer emitted by the compiler.
    It has been upgraded to a hard error.
    Closing as fixed by #125380.

  19. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    and removed
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    on Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-dyn-traitArea: trait objects, vtable layoutA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-trait-systemArea: Trait systemA-type-systemArea: Type systemC-future-incompatibilityCategory: Future-incompatibility lintsC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions