-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Amend #911 const-fn to allow unsafe const functions #1245
Conversation
I have implemented this in a branch (won't PR until this RFC is accepted). Link Appears to work properly with just a simple change to the parser. |
Yay! For motivation: The |
Other motivation is NonZero and Unique, which underlie most collections. Having these be able to be const allows empty collections to be compile-time constructed. |
@Ericson2314 |
I think it should be made clear somewhere that |
@glaebhoerl constants are pure right now, so unsafety at compile-time is out of the question. |
```rust | ||
struct OptionalInt(u32); | ||
impl OptionalInt { | ||
/// Value must be non-zero |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't NonZero::new_unchecked
be a better example here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly, however Unique is more directly related to the collection types (as that's the libcore type they're built on)
@eddyb Oops, I've discussed this on IRC, probably with you. For the short term, |
@Ericson2314 That's still problematic, what would it do for |
Sandbox compile time evaluation. For this case, I think it would suffice to keep an extra "taint flag" on pointer values, and not allow dereferencing tainted ones. |
@glaebhoerl I would assume that's implicit in the idea of CTFE... but it may require explicit stating in the RFC. |
I'd like to note that in the common usage of rust via cargo with build scripts, or nightly rust using plugins, we already have potentially undefined things occurring at compile time. If there is a goal to avoid particular types of undefined things at compile time, but not all of them, within the rust project there probably should be some explicit note (somewhere, not necessarily this RFC) about what the goals are around undefined things occurring at compile time. Edit: I suppose it might just be "avoid vulnerabilities in play.rust-lang.org" |
@thepowersgang Sorry for the long silence here! I'm working my way through RFC backlog. I personally don't see any problem with this RFC. I will propose it for "final comment period" in the next Lang Team meeting. |
This RFC is entering its final comment period. |
|
struct OptionalInt(u32); | ||
impl OptionalInt { | ||
/// Value must be non-zero | ||
unsafe const fn new(val: u32) -> OptionalInt { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since const
is not a part of function type and unsafe
is, I'd prefer this to be const unsafe fn
and not unsafe const fn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
“unsafe constant function” sounds more “right” to me than “constant unsafe function”, though your point is also valid.
Either way, I think it should be possible to put these in any order. I’ve already had some trouble remembering which goes first in pub extern fn x
and now I’ll have to think what order pub
, const
and unsafe
go in pub unsafe const fn x
. pub
is pretty easy since it “always goes first”, but there’s no such obvious rule for unsafe
and const
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 @petrochenkov's order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer unsafe const fn
because I see const fn
as something different from fn
, while unsafe
is a mere qualifier.
There's no real reason why there aren't const fn()
pointer types, they just weren't implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for @nagisa: allow both orders
There's no good reason to force users to learn a particular order.
If we decide on a preferred order, that can still be enforced by rustfmt. No need to make rustc overly strict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... both could be allowed, but would complicate the parser (if it is to correctly disallow unsafe const unsafe fn
). I'll yeild to the language team on the final decision, but I'm leaning towards keeping a fixed order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @petrochenkov: unsafe fn
feels like a more fundamental concept/thing than const fn
. (const
on a function doesn't outlaw it from being used as a non-const
function, while unsafe
does outlaw it from being used as a non-unsafe
one.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddyb I see how a const fn ptr could allow for higher order functions at compile-time, I am not sure that is the right means to achieve that.
It's official. The language design subteam has decided to accept this RFC. We did not, however, resolve the burning question of modifier order. We'll have to figure that out next week. |
Amend #911 const-fn to allow unsafe const functions
This RFC has been merged. The lang team met and discussed this RFC again, and decided that:
And, as @nikomatsakis said already, in general we are in favor of the RFC. |
@jmesmon (late response, I've only just gathered some thoughts)
That's the down-to-earth view of it, yeah. But as an example of why this would bother me more deeply, consider that The examples of cargo scripts and especially compiler plugins are similar in a way, but feel qualitatively different to me (perhaps it's the distinction between arbitrary and undefined). |
It would be ideal if this change could be applied to |
@Parakleta That's pretty difficult, as it requires representing values as polysemantic bags of bits (for example, constant references right now are only the value they point to, they have no address associated with them until runtime). Our const evaluation is seriously lacking even without this massive increase in complexity you are proposing. |
I don't understand why dereferencing a pointer created from an integer through |
@Parakleta How would you implement it? Memory doesn't exist at compile-time. |
Managed memory doesn't, since you expect the runtime to make it for you when the program is launched, but unmanaged memory does. Specifically look at the memory mapped registers of any MCU. I want something like |
I just realised we're talking about slightly different things. In your example taking the address of a constant integer wouldn't work, it would need to force the integer to be static, and then taking the address is fine. So |
You already have And no, the concept of memory does not exist at compile-time. Managed or unmanaged. At compile-time you can only deal with safe symbolic references, mutable variables at most (as long as you preserve "execution order"). Once you introduce transmutes, you have to track every bit and where it comes from, and somehow allow reconstructing symbolic values from the shattered bits of a different symbolic value (in this context, a safe reference). Constructing symbolic references from constant integers would be impossible, as there is no symbolic information associated to any constant integer address. |
You're right, I'm not really following your argument too well, the point I'm stuck at is just that I cannot get a pointer to the data within a |
The bits of a reference do not exist at compile-time, as the address is decided at link or load time. Can you dereference arbitrary pointers or perform arithmetic on addresses of statics in C constant expressions (or C++11 constexpr)? |
When using the Python C API, it's normal to cast function pointers within static initializers: static PyMethodDef cc_methods[] = {
{"varargs", function_with_varargs, METH_VARARGS, NULL},
{"keywords", (PyCFunction)function_with_kwargs, METH_KEYWORDS, NULL},
{0}
};
Currently there doesn't seem to be any way to do the same operation in Rust; for rust-cpython I've had to use |
The bits of a reference do not, but the type does and at compile time I can change the type that those bits are intended to represent even if the bits are still unknown. Arithmetic on the addresses of statics is done to some extent at link time to address into arrays and structs, although I don't know how general purpose this is, maybe just offsets. I think I understand now that your concern is that transmute would make |
@dgrunwald That's one of those cases that makes me sad we didn't go with some combination of reference/pointer to Technically, we could support the cast with the current |
See discussion in #1207