-
Notifications
You must be signed in to change notification settings - Fork 260
Move from last-use causes problems with RAII types, and types with member functions with side effects #1002
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
Comments
Thanks! Ah, this is similar to #999, except the key thing is that [Updated to add:] It's actually intentional that this is an error. Briefly, the reason is that if a definite last use of a local object modifies that object, then the code is not looking at the object again (because by definition it's a last use) and therefore trying to implicitly discard the new value. For a complete discussion, please see Design note: Explicit discard. Like #999, this is still improved by the recent commit 7041994, but instead of the nicer error message #999 gets, currently this example gets this:
And on MSVC that's followed by this, which gives the right clue never the end:
So that's better than above, but not as nice as for the first argument before |
Based on this feedback, I think the first error message should be:
That's at least a clearer clue to the programmer. Thanks! |
I may be missing something but I don't think the issue is just that the Cppfront error could be clearer? Here's a fuller example: Godbolt See lines 20 and 42. How should this code be changed to fix the error? EDIT - I saw from the suggestion to add the (copy lk: std::unique_lock = (m))
{
cv.wait(lk, :() -> bool = processed);
_ = lk; // <-- New
} Similar to my RAII example in #999, I find this awkward. IMO the code is clear that the |
After thinking about this, I think this is about "guard" objects. Those are the local objects whose values are used "by someone else than this function's remaining body code" after their definite last use because:
... and so I think those are the only cases? I can't think of another case where code could consume the new value of a modified-at-last-use local object. Next, what to do about it? At minimum we could just teach people who use local synchronization variables that this is how to use them in Cpp2. Or... we could add some way to declare guards (possibly even by recognizing the prefix |
Its a tricky one, it seems
This works (please confirm if that's a coincidence 😛) because EDIT: Silly me, you can't grab the pointer of a rvalue... This happens to work because |
Should #999 be merged with this issue? They’re not duplicates but I think both are symptoms of a bigger, parent issue. I think there may be more cases than just guard objects to consider. Here are a few that I’m wondering about (but haven’t tested yet):
|
Yes, I think we should try to merge them both, its not about UFCS per se. It's about not giving up one of the main strengths of RAII (I pass you this value, you do the cleanup for me, regardless of how we exit the scope). |
Intended. See #558 (comment). |
Yes, I agree this isn't about UFCS -- would you like to update the issue titles to reflect that? |
What if we had a way to say this? "The destructor of this type is always the definite last use of an object of this type, no matter what That would take care of one group of issues. Another group of issues is this. "This function has side effects so we need it to not be Is that an accurate statement of the group of issues? Do we need a decoration for |
Yes, I think you nicely summarised the issues. After thinking about this further I prefer the idea of opting-in to the "move from last-use" behaviour, for the reasons I outlined in #1030. One major point, for me, is that I want to use my existing C++ types (e.g. RAII types, or code that I'm slowly migrating to Cpp2) which I can't modify with a metafunction or a new decoration for |
Thanks! See #1030, this should now be fixed in the above commit. The original code example now works. (Unrelatedly, making the code work on MSVC also requires removing the |
Interesting, I just learned that the presence of |
TIL:
🧑🎓 Thanks for sharing that info! |
Brief update: On reviewing these changes in a recent commit discussion, I think I'm going to switch gears and not move from last use for object whose names start with |
I find depending on a naming convention to be inelegant, what about users that use CamelCase such as |
Agreed, I had the same thought. It's okay for a short term test, but I wouldn't want to see it as a long term feature. Also, it seems like this marking should be on the type definition rather than the name of the particular object. This is a property of the type, not of the particular instance of the type. Spitballing here, what if marking the destructor as Another possibility is to use a metafunction tag such as |
Tagging @hsutter just in case you don't get a notification. I see this destructor tagging is basically the same thing I said earlier this year. Glad I was consistent. |
Very good point. The problem with any kind of annotation on Cpp2 end is that it will not pan out to C++-written types. I am starting to think that automatic move from last use is inherently incompatible with scope-guard type of objects, at least named ones. |
That's unfortunately true. :( I tried putting You can actually put the |
I guess Herb went with the name annotation because is the simplest solution to implement at the moment, and an issue that only shows when dealing with very specific Cpp2 code. I think what he did is add a way to mark a specific instance of an object as "never move me implicitly" when its identifier matches the I think a more general solution can be combined with something similar to what is proposed at #1332. In fact, we still need a way to mark certain things like
It means you should not discard the value you get of that type. So its a good idea to put it in types like lock guards which you want to "pin" to a scope. |
Describe the bug
A combination of UFCS and
std::move
introduced by a variable's last-use causes a C++ compiler error.To Reproduce
Run cppfront on this code:
After compiling with clang it results in an error:
One workaround is to add something after the
cv.wait
line that becomes the last use oflk
:Repro on Godbolt
The text was updated successfully, but these errors were encountered: