-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: spec: disallow taking the addresses of loop variables #20725
Comments
This looks like a dup of #16520. The examples are slightly different ( |
@mvdan I actually wrote this as a comment to that issue before submitting this one instead :) While the problems do overlap, #16520 is about capturing, which is not the issue here. I think the main difference is that there are many legitimate reasons to capture a loop variable inside a function literal (at least with the As I try to argue here, taking a range variable address is much more unlikely to be useful - in part because you can capture the original variable. Also, fixing "false positive" cases is trivial using the mentioned replacements. This will not be the case if you generalize the problem. |
Ah, I think I see what you're after then. I take it that when you say "taking an address" you mean whenever the compiler takes a variable's address, even if it wasn't explicit in the code via |
As in the examples, I do mean it to be explicit in the code with |
There are no warnings but we could think about disallowing this entirely in Go 2. Leaving for that. |
@rsc I used the word "warn" because it seemed to me to be conventionally used by other issues on go vet. I did mean "rejected" by go vet. I have a simple patch that I wanted to try and submit tonight (UTC+1 time) :) |
It's too invasive to reject in vet. It fails the "precision" test in cmd/vet/README. |
Not being able to take the address of an addressable thing turns the "addressable" concept into something very weird. Also: for _, bigValue := range bigValues {
foo(&bigValue)
} is completely reasonable code avoiding making another copy of bigValue when foo just reads its argument. |
@rsc How is it determined if it fails the test? I've tried to run my patched tool on a bunch of random projects and found mostly cases which are definitely "worth examining" as the precision test states. Maybe the test could be disabled by default if it becomes too noisy in an existing project? @cznic As
Alternatively, you would just have to define |
There is plenty of correct code it would disallow. That's not OK. See @cznic's comment for one example. I am sure there are more, even if not in your own code base. That's why it's really a spec change. |
Iff bigValues is a slice/array. |
The most common false positive I found so far is |
There is nothing wrong with taking the address of a range variable if you don't save the pointer across loop iterations. And, this restriction doesn't fix the problem of referring to a range variable in a closure, which is if anything more likely to be problematic. Closing. |
Consider a range loop:
Since the variables
k
andv
are not redefined for each iteration of the loop, their addresses are the same in each iteration. These addresses are therefore very unlikely to be useful, and the following more explicit alternatives are IMO clearer and more robust to refactorings anyway:Instead of overwriting the value by passing its address to a helper function, define a new variable instead:
In order to reference the object in the current iteration of the loop, copy it or access the iterated slice directly:
I would argue that taking the addresses of range variables is so rarely useful that it would be good to require the intent to be made explicit as follows:
The text was updated successfully, but these errors were encountered: