-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lint: add internal mutability lint. #14241
Conversation
In IRC today I was strongly opposed to this lint. Thinking on it again, I can see why you might want to turn it on only for specific functions (as opposed to turning it on for a full module/crate, where I think it's overly broad and therefore useless). But once you start considering turning this on for specific functions, it seems like a poor man's way of trying to make the function pure. Except it's not good enough for that, because it doesn't handle |
I think a reasonable usecase for this is turning it on for a library like (If there something in that library that absolutely needs internal mutability, then it can turned on just for that type/module.) |
It's easy to remove a lint without breaking backwards compatibility (make it a no-op + warn) so I don't think there's harm in trying it. It might turn out to be useful because it's too restrictive and has too many false positives, but I don't think we'll ever find out if we don't try. |
@alexcrichton You tend to be a very slippery-slope kind of guy. What's your thought on the idea of just adding a lint to try it out? |
InteriorUnsafe is sufficient for memory aliasing that ignores pointers, but tracking whether a type semantically contains an Unsafe is useful (for lints).
This picks up any use of types with internal mutability (containing `Unsafe`) in function/method calls, since these may cause things to be modified unexpectedly. This lint is like the "heap memory" lints, in that using internally mutable types is perfectly valid in many instances, but it is easy to expose the compiler's internal knowledge for the cases when someone does wish to keep track of everything being mutated.
@huonw What would be the actual benefit of turning it on for something like |
Yes, it's to force people to design their APIs properly (or at least think about them) when adding new data structures. I've had to get the compiler to record ReachesUnsafe in addition to its current recording of InteriorUnsafe. cc @nikomatsakis |
Agreed with @thestinger. Lints are cheap. Lots of folks like purity, so this is a good one. Add 'em at will. |
Its currently off by default. My intuition would be that that means that it will see very little use which somewhat defeats the purpose of the lint. On the other hand, I don't think it should be on by default either since I would think it very strange if there is a lint that produces warning as soon as you use As mentioned by other comments, there are other forms of mutability that this won't touch - using a It doesn't feel to me like this really solves the currently awkward relationship between aliasability and mutability, at least when it comes to conveying useful information regarding programmer intent. Rust's story regarding mutability and programmer intent is currently very hazy, and I don't think this makes it significantly clearer. I don't see the harm in adding the lint, but, I don't think its all that useful either. |
This lint allows disabling all types with inherited mutability. Using a mutable global variable is an external effect rather than mutation of a variable. It could be saving state in POSIX shared memory or an on-disk file rather than a global. If Rust ever gains an effects system, modifying a global or task-local variable will be an effect outside of the work the mutability system needs to worry about. Venturing outside of inherited mutability always requires
This "awkward" relationship is the foundation of what makes Rust memory safe. It will always be painful, and no amount of obfuscation / renaming is going to make the borrow checker errors fade into the background. The borrow checker is implemented on top of the underlying ownership-based mutability system, and not all of the checks are related to aliasing.
Rust's mutability system is well defined without anything hazy or confusing involved. The It's not possible for a mutability system to take everything into account. It's trivial for "pure" Haskell code to spin in a loop consuming all of the system's memory, spinning up the CPU fan and heating up the room until the system grinds to a halt swapping to disk and finally the OOM killer is triggered and ends the misery of the Haskell program, perhaps after killing the user's Eclipse process. The lack of perfection doesn't make something any less useful. |
I thought of an even better way to do this: only warn if the type reaches at least one struct Inline {
x: Unsafe<uint>
}
struct Pointer<'a> {
y: &'a Unsafe<uint>
}
let inline: Inline = ...;
let ptr: Pointer = ...;
foo(&inline); // warn
foo(inline); // no warning: there's no way for `inline` itself to be visibly mutated
foo(&ptr); // warn
foo(ptr); // warn This allows e.g. However, the compiler doesn't directly support computing this property, so I'll not implement it for now (unless someone thinks this is very much better than also warning for the |
(That could be improved even more, by modelling pointer ownership, e.g. passing any of |
@thestinger A function that calculates the first 10,000 digits of PI might also be freestanding, but that isn't sufficient for it to be included in libcore. I disagree that there is anything wrong with If a type from the core library that is necessary to solve some problems needs to have a warning when it used because it breaks that mutability system, I think that's not a sign that there is something wrong with As I said, I don't see the harm in adding the lint and I can see it as useful in some contexts, but, I don't see it as a solution to the bigger issues. |
@DaGenix: If Any usage of |
Hm, so I actually ran this on real code rather than just what I conjured up for the test... i.e. This was a nice idea, but requires significantly more implementation work. :( |
feat: add an autofix for inserting an unsafe block to missing unsafe diagnostic close rust-lang#14241
…ang#14241) This lint was renamed in 50da775. While I'm here convert the list of separate lints into a proper list for ease of use. changelog: none
This picks up any use of types with internal mutability (containing
Unsafe
) in function/method calls, since these may cause things to bemodified unexpectedly.
This lint is like the "heap memory" lints, in that using internally
mutable types is perfectly valid in many instances, but it is easy to
expose the compiler's internal knowledge for the cases when someone does
wish to keep track of everything being mutated.