Do I truly have to treat you like a child? That's the last thing I want to do, but it looks like I have to state this a million ways when I've been as clear as I can be. I've been as respectful as possible, but you're blatantly ignoring my legitimate question, and I've stated it multiple different ways. I am not asking about malloc!
I have provided a very specific snippet, asking if you can acknowledge that there is no unsafety there. This is a yes/no question. You're proposing an enormous change to the language that is backwards-incompatible, yet you can't answer a yes/no question. Surely I can't be the only one that sees a problem with that?
It does not trigger undefined behaviour, regardless of the presence of absence of unsafe blocks, which is not an escape-hatch mechanism for triggering undefined behaviour, but a marker to identify code the compiler can't reason about.
Also of note is that that code is actually considered const-unsafe, in const eval context.
Ok? As with malloc, I did not ask about that. It's irrelevant to the question I posed.
So what would the compiler be suddenly unable to reason about in a future edition that it already can today? There is no potential unsafety, as you've acknowledged, so why should we be required to place some subset of that code in an unsafe block?
It depends on whether we want safe APIs to be able to opt-out of some optimizations by using *const T instead of &T, and instead of adding an attribute like #[safe_for_unsafe_code_to_use].
Alright. I'm bowing out of this thread. This follows a large number of threads that you've posted that have no sound reasoning behind them and wherein you're unable to answer simple questions about it. I am strongly recommending that you think about the implications of what you are about to post before you do so. As I've stated, editions do not give you carte blanche to do anything you want, and disregarding that, you've still neglected to demonstrate the inherent unsafety in possessing a raw pointer. As such, I will not continue wasting my time requesting the same information time and time again. You need to show why this is truly needed, address potential drawbacks, and investigate potential interactions with other language features. There are plenty of high-quality threads on this forum if you'd like examples.
Don't bother pinging or DM'ing me with regard to this thread, to be clear.
As far as I understand your idea is changing the pointer type (*const T) in a way that disallows just about any interaction with the pointer type in safe rust except for a very few things, including converting a reference to a pointer and passing the result of that to a function. In particular the changes are supposed to make it impossible to pass a pointer that doesn't point or valid memory to a function.
The problem you're trying to solve to avoid the need to duplicate API for atomic types such as AtomicUsize into a safe version taking references (&AtomicUsize) and an unsafe version taking a pointer. The unsafe version is needed in the issue you linked because the safe version is keeping its argument around in the function body even after an atomic operation such as e.g. "swap" is executed. In the use case for Arc::drop the AtomicUsize can be deallocate by another thread as soon as the atomic operation is done, even before the function in the AtomicUsize API returns. This might violate compiler guarantees that the reference has to be valid all the way until the function returns.
One way to avoid the need for duplication is by offering an API that doesn't take an &AtomicUsize parameter while still allowing it to be called from safe code somehow. In current Rust a *const AtomicUsize parameter would not be sound unless the function is marked unsafe.
While your proposal might work, and possibly even be achievable in a way that is "technically" not a breaking change (though I'm not sure if this really is the case), this change would fundamentally change the meaning of Rust's pointer types. This is an unnecessary change, it would cause lots of churn, as far as I can tell there's little gain, you've gone nowhere near getting into all the details of this pointer-types-redesign by mostly focusing on just the pointer coercion from *const T to *const U, you've done a rather bad job explaining your motivation instead using non-constructive language, "Unfortunately", "Which sucks", "best described as an oversight or a mistake", "maybe it exists this way to actively prevent safe abstractions from using raw pointers".
One potentially much better alternative IMO would be to think about introducing a new type that takes the role of a reference with less compiler guarantees instead of trying to force *const T into this role. Such a type would probably also have a lifetime which would make a lot of details easier AFAICT. In any case it would also be important to try and find out if there are more than just this one case of the Arc::drop implementation where a type like this could be helpful.
Eh. Meh. Guesses and feelings aren't against the rules.
Thank you. With raw pointers it's easy to see what the type represents, so these changes would more or less "just work" (if with some churn). However, with something like that, what exactly would such type represent? Do we want a whole type for "references which are only dereferenceable on entry, but may be dropped between last use and exit"? What would it be called?
Hypothetically, it would make sense for all (unsafe) operations on UnsafeCell to return such references, but that would be a breaking change. (It's actually one of the proposed fixes for this soundness hole - make UnsafeCell somehow turn off dereferenceable.) Does the churn from deprecating existing methods on UnsafeCell and adding new ones with these hypothetical reference types make any more sense than the churn of adding more unsafe around existing unsafe code?
UnsafeCell doesn't actually have any unsafe operations - in particular, UnsafeCell::get is safe, because simply creating a raw pointer can't cause undefined behavior.
There is no need for UnsafeCell methods to return anything other than a raw pointer - a raw pointer represents the weakest possible guarantees for a pointer (i.e. no guarantees at all). Unsafe code is free to assert strongly guarantees by converting the raw pointer to a different type (a normal reference, or the hypothetical new type mentioned by @steffahn).
In contrast, the relevant AtomicCell methods consume (and dereference) some kind of pointer. Those methods need to be able to guarantee that their use of the pointer is safe. This happens automatically if they take in &self (due to the guarantees made by normal references), or via an explicit unsafe block in the caller if a raw pointer is used.
and to think we looked at the UnsafeCell docs just a few days ago
ah well, that does make it easier we guess. so we guess it's just a matter of, do we want this new reference type, that is weaker than existing references, and can be autoconverted from existing references? (it's best for the existing methods on AtomicUsize to take such a hypothetical reference type, if it is to be added, so the autoconversion is necessary for backwards-compatibility.)
If you want to make passing a raw pointer to a function an unsafe operation, how do you think of managing the fact that this is still safe in 2015 and 2018 editions? You won't be able to consider those pointers dereferencable in 2021 because a 2015/2018 crate could pass an invalid pointer or you should make them not callable from 2015/2018 editions, which however completely breaks compatibility between editions
Nah they'd be downgraded to take references in earlier editions. Note this would only apply to functions marked safe, and some functions blessed by the compiler (in particular some std::ptr::* ones) would be able to opt-out of it (for backwards compatibility).
No, it isnât that simple. You can strengthen the requirements of a fn(*const T) to fn(&T), sure, but you canât strengthen fn(&mut *const T) into fn(&mut &T).
Once again, we have very limited âbudgetâ for sweeping deprecations, breaking changes, or significant new language features. Designing, implementing, and documenting such things uses up time and effort from our contributors. Churn in the language causes friction for users, who now have more things to learn/unlearn/relearn, and more outdated code and docs to encounter in the wild, and uses up their goodwill.
When I talked about needing âmotivationâ for such changes, I didn't mean here's one use case that it improves, or the existing way is unpleasant. For a major change, people are looking for reasons that this is not just something we could do, but something we must do: strong evidence that the benefit is huge and there are no alternative ways to achieve it.
As a moderator, I am asking you one last time to back off from constantly requesting breaking changes and deprecations. To keep this forum productive, we need people working together, with a common framework for how the project evolves. It can be useful to explore a wider design-space, including points that might be unreachable for post-1.0 Rust. However, such explorations should be clearly labeled, and the fact that Rust can't evolve in arbitrary directions should not be taken to mean it is bad or broken.