Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAmend #1440: allow `const` items to contain drop types. #1817
Conversation
SergioBenitez
referenced this pull request
Dec 13, 2016
Merged
RFC - Allow Drop types in statics/const functions #1440
nrc
added
the
T-lang
label
Dec 19, 2016
This comment has been minimized.
This comment has been minimized.
pnkfelix
reviewed
Dec 19, 2016
| - Allow `const fn` to return types with destructors. | ||
| - Disallow constant expressions which would result in the destructor being called (if the code were run at runtime). | ||
| - Disallow constant expressions resulting in destructors being called at runtime (i.e: a `drop(foo)` in a `const fn`). |
This comment has been minimized.
This comment has been minimized.
pnkfelix
Dec 19, 2016
Member
Doesn't the change proposed here explicitly allow for constant expressions that result in destructors being called at runtime?
Or do I misunderstand how the term "constant expression" or "runtime" is being used in this context?
This comment has been minimized.
This comment has been minimized.
eddyb
Dec 19, 2016
Member
Oh, right, I prefer the original phrasing because it emphasizes that this is not about code ran at runtime, but rather some compile-time constant evaluation context. I'm not even sure we check this correctly with the feature flag enabled, it's a bit tricky if you can't rely on a full ban of drop types.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
assigned
pnkfelix
Dec 22, 2016
This comment has been minimized.
This comment has been minimized.
|
Any further thoughts on this? Would love to get this in and implemented soon! |
This comment has been minimized.
This comment has been minimized.
|
Does anyone recall why precisely we prohibited them in the first place? I'm trying to bring that conversation back into cache. |
nikomatsakis
reviewed
Jan 5, 2017
| @@ -55,6 +57,8 @@ const fn sample(_v: Vec<u8>) -> usize { | |||
|
|
|||
| Destructors do not run on `static` items (by design), so this can lead to unexpected behavior when a type's destructor has effects outside the program (e.g. a RAII temporary folder handle, which deletes the folder on drop). However, this can already happen using the `lazy_static` crate. | |||
|
|
|||
| Destructors _will_ run on `const` items at runtime, which can lead to unexpected behavior when a type's destructor has effects outside the program. | |||
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Jan 5, 2017
Contributor
I'm not sure what this means. My mental model for a constant is that it is an "rvalue" -- in other words, each point where it is used, it is (roughly) "as if" you typed the expression in that place. Therefore, if we permit drop types there, I'd expect that Drop will run at each point where the constant is referenced (and if it is never referenced, it will not run). I think we should expand this text to be much clearer about this point.
This comment has been minimized.
This comment has been minimized.
SergioBenitez
Jan 9, 2017
Author
Contributor
You've precisely identified the intent of the comment. I'll reword it.
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis It was trying to side-step the "drop runs on every copy which may be unexpected" fact, I believe, and it was quite narrow-scoped, focusing on |
This comment has been minimized.
This comment has been minimized.
|
Sorry for the delay. I've reworded to sketchy statement. |
This comment has been minimized.
This comment has been minimized.
|
Checking in on this. How's this looking in terms of getting accepted? |
nikomatsakis
reviewed
Feb 16, 2017
| - `static`s containing Drop-types will not run the destructor upon program/thread exit. | ||
| - `const`s containing Drop-types _will_ run the destructor at the appropriate point in the program. |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Feb 16, 2017
Contributor
I think that we should be more specific about what "the appropriate point" is. Probably by adding a subsection to allow us to elaborate. But when I started thinking about what to write I encountered a question. I'll post it on the main thread though.
This comment has been minimized.
This comment has been minimized.
|
OK, so, I was thinking more about this RFC. I just wanted to talk through what happens when we have a non-trivial constant. I'm not sure that there's a problem here, but I think the semantics are actually kind of subtle. Imagine I have this: const EMPTY_VEC: Vec<i32> = Vec::new();Here I am assuming Now, if this were a static, when I reference But for a constant, we essentially get a new copy each time we access it. The way I imagine this really working is that we execute Now maybe by declaring |
This comment has been minimized.
This comment has been minimized.
|
@nagisa raises the question of what happens when you use such a constant in a pattern -- though I think the answer there is that we wouldn't really be instantiating the constant in that case, but rather doing a kind of comparison... so maybe drop doesn't have to run? But I'm not sure the best way to think about this. It seems tied in to the annoyance around |
This comment has been minimized.
This comment has been minimized.
Yes, this is also the case where I’ve wanted this: Regarding patterns, if fact that was the motivation for using Taking another step back, this whole thing would be a work around for privacy hygiene in |
This comment has been minimized.
This comment has been minimized.
|
@eddyb had a nice example of how you could easily misuse this capability: pub struct FileHandle { x: i32 }
impl Drop for FileHandle { /* closes the handle */ }
const STDIN: FileHandle = FileHandle { x: 0 }; // BADNow any reference to STDIN will close file description 0. If you used a static, everything would be fine. This is not to say we should not permit drop in constants, but there is a kind of subtle "opt in" happening here. It'd be nice if we could do a bit better. @eddyb suggested perhaps a lint of some kind, but we'd have to tailor it properly. |
This comment has been minimized.
This comment has been minimized.
|
I feel that adding something that would then be limited against by default
is meaningless. Also nice example.
…On Feb 22, 2017 13:54, "Niko Matsakis" ***@***.***> wrote:
@eddyb <https://github.com/eddyb> had a nice example of how you could
easily misuse this capability:
pub struct FileHandle { x: i32 }impl Drop for FileHandle { /* closes the handle */ }const STDIN: FileHandle = FileHandle { x: 0 }; // BAD
Now any reference to STDIN will close file description 0. If you used a
static, everything would be fine.
This is not to say we should not permit drop in constants, but there is a
kind of subtle "opt in" happening here. It'd be nice if we could do a bit
better.
@eddyb <https://github.com/eddyb> suggested perhaps a lint of some kind,
but we'd have to tailor it properly.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1817 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AApc0mFxPTG275Cazxpqwb117FTL29siks5rfCHYgaJpZM4LLp-p>
.
|
eddyb
referenced this pull request
Feb 22, 2017
Open
Track the "static"-ness of slots in MIR and detect drops in constant initializers. #40036
pnkfelix
reviewed
Feb 22, 2017
| - Allow `const fn` to return types with destructors. | ||
| - Disallow constant expressions which would result in the destructor being called (if the code were run at runtime). | ||
| - Disallow constant expressions that require destructors to run during compile-time constant evaluation (i.e: a `drop(foo)` in a `const fn`). |
This comment has been minimized.
This comment has been minimized.
pnkfelix
Feb 22, 2017
Member
doesn't this need further amending to be consistent with the other changes in the RFC?
(This probably ties into @nikomatsakis's earlier point that we need more specifics about what "the appropriate point in the program" is...)
This comment has been minimized.
This comment has been minimized.
pnkfelix
Feb 22, 2017
Member
hmm well on further reflection I guess this text may be consistent as written. (Just need to get my head around when the destructors that are now allowed are actually getting invoked.)
This comment has been minimized.
This comment has been minimized.
|
@SergioBenitez @pnkfelix You might want to take a look at rust-lang/rust#40036 where I used a potential problem with this addition as an example. That is, we have to specify in what conditions drops wouldn't run in constant initializers (and thus when values of types with |
This comment has been minimized.
This comment has been minimized.
|
If we were going to lint against this, I think the right way would be to say that if a type implements @nagisa (I feel like this isn't quite the same as saying we "lint against it by default".) One could imagine calling the struct body "unsafe" as well. |
nikomatsakis
referenced this pull request
Mar 2, 2017
Closed
permit `Drop` types in constants (tracking issue for RFC #1440) #33156
This comment has been minimized.
This comment has been minimized.
Summary of status and of comment thread(Note that this summary includes some discussion of const-evaluation semantics; in particular it includes my personal mental model for the semantics, which probably does not match the rest of the lang/compiler team...) The RFC proposes to loosen const-expressions so that they can have (sub)expressions of type T where T carries a destructor. (Destructor invocation continues to be disallowed at compile-time.) The comment thread has raised the question: "Why did const-expressions forbid destructors anyway?" One answer is that people may not expect the resulting semantics with multiple destructor invocations from a single const definition (more details in bulleted summary below). Niko notes in particular the distinction between As I understand it:
Given the caveats above, does the lang team want to take action now on this RFC? Or should we postpone until after resolving Issue 40036? |
This comment has been minimized.
This comment has been minimized.
This interacts poorly with associated constants and the future possibility of generic top-level constants. EDIT: As discussed on IRC, "MIR inlining" is a bit better than "macro-expansion" at describing this. |
This comment has been minimized.
This comment has been minimized.
|
After reflecting on this RFC, I figure that the capability for abuse is something that the designer of a type can readily defend against. My basis for this reasoning is: if you don't allow literals to be publicly constructed, and you don't provide a (It might be the case that we will want a lint for any |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot fcp merge (see reasoning from my previous comment) |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Mar 21, 2017
•
|
Team member @pnkfelix has proposed to merge this. The next step is review by the rest of the tagged teams: Concerns:
Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot concern unresolved-question-for-lint
I agree, but my concern is mostly -- will they think to defend against it? This is why I am somewhat reluctant to go forward without a lint of the kind I described (specifically, one the struct literals). But I've also learned from experience that people hate "allowing" lints -- and this would be a lint that you basically have to allow, to declare that you know what you are doing, if you intend to have types (like Still, I'd like to ensure we revisit this question before stabilization, so I'm noting a formal concern that we should add an unresolved question about whether to add such a lint. |
carols10cents
added this to Merge proposed
in Tracker
Apr 26, 2017
This comment has been minimized.
This comment has been minimized.
|
I've spent some time mulling over this, and want to sketch my mental model of what's going on. There are types which are not, in general, However, I think there are several mitigating factors that make this perfectly OK:
Finally, if there does turn out to be a footgun here, we always have the option of linting our way out of it. @rfcbot reviewed |
This comment has been minimized.
This comment has been minimized.
|
@SergioBenitez, can you add the unresolved question @nikomatsakis mentioned above? I think that's effectively the only remaining blocker here. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot resolve unresolved-question-for-lint I've decided that this lint doesn't have to be a "formal unresolved question". We can just remember that it is an option if we feel like there is a real footgun evolving here. I tend to agree with @aturon that this probably won't arise in practice all that often. |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis You have to write |
withoutboats
added
the
proposed-final-comment-period
label
Jun 21, 2017
This comment has been minimized.
This comment has been minimized.
|
Ping @nikomatsakis -- I think your |
aturon
added
final-comment-period
and removed
proposed-final-comment-period
labels
Jul 3, 2017
This comment has been minimized.
This comment has been minimized.
|
In the interest in making progress, I've manually applied the FCP tag. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot resolved unresolved-question-for-lint |
rfcbot
added
the
final-comment-period
label
Jul 6, 2017
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Jul 6, 2017
|
|
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Jul 16, 2017
|
The final comment period is now complete. |
This comment has been minimized.
This comment has been minimized.
|
Huzzah! This RFC amendment has been merged! The tracking issue is the one for the original RFC. |
SergioBenitez commentedDec 13, 2016
•
edited
At present, #1440 does not allow
constitems to contain drop types. This leads to somewhat surprising behavior, as illustrated in the following example:In the code above,
WORKStypechecks whileFAILSdoes not, even though they may appear to be identical to the user. The check fails because the compiler treatsTestas an opaque type returned fromTest::new(); becauseTestcontains aVec, the type maydrop, and so theconstitem is rejected under the current RFC. This PR changes the semantics to allow thedroptype in theconstitem, thus typecheckingFAILS.