4 ms·
Actually, in rust I get no warning with the functionally similar (and I think idiomatic) code: let l = [1i, 2, 3]; for i in l.iter() { println
by simias 12y ago
Actually, in rust I get no warning with the functionally similar (and I think idiomatic) code:
let l = [1i, 2, 3];
for i in l.iter() {
println!("{}", i);
break;
}
Obviously there's no explicit update as in the C code but since using iterators is the Rust way to iterate over collections I don't think it's fair to say that the rust compiler would have saved them on that one.
- chrismorgan 12y agoIt’s not a break—it’s a return. So the stuff after the for-loop is unreachable.
- jzwinck 12y agoThe stuff after the for-loop is reachable if the for-loop is never entered. You can consider it to be an if-block instead, with a return at the end.
- chrismorgan 12y agoOhhh, yes. I forgot that.
- simias 12y agoYou're right but in this case it doesn't change anything (you can replace break; with return; and you won't have a warning either). Actually, even if you add code after the for loop and the list is not empty Rust does not warn: fn main() { let l = [1i, 2, 3]; for i in l.iter() { println!("{}", i); return; } println!("unreached"); } Builds without warning and prints a single "1". Judging by the output with "--emit ir" when building with -O the rust compiler doesn't seem clever enough yet to realize that the whole vector and loop could just be factorized in a single "println!("{}", 1); return;" which probably explains why it can't detect that the return is always reached (i.e. the list is never empty). It even generates instructions to create the unused array elements: %1 = getelementptr inbounds [3 x i64]* %l, i64 0, i64 0 store i64 1, i64* %1, align 8 %2 = getelementptr inbounds [3 x i64]* %l, i64 0, i64 1 store i64 2, i64* %2, align 8 %3 = getelementptr inbounds [3 x i64]* %l, i64 0, i64 2 store i64 3, i64* %3, align 8
- eddyb 12y agoThe Rust compiler cannot assume the loop will never iterate, the analysis phases that could determine that are ran before optimizations. And optimizations are performed by LLVM, with no feedback to the compiler. I actually analyzed your example, and what happens there is that `i` is a reference to array elements and we don't pass enough metadata to LLVM to inform it of pointers with a fixed number of usable bytes, so it believes the formatting runtime is capable of accessing more of the array.
- jnbiche 12y agoThe problem is not breaking before an iteration has completed, it's unreachable code. In your example, you have no unreachable code. However, move that print statement to the line below your break, and you'll see that Rust gives an 'unreachable code' warning. let l = [1i, 2, 3]; for i in l.iter() { println!("{}", i); break; } And I'm pretty sure it can be configured to not compile at all on warning. Can someone with the project confirm?
- simias 12y agoYou forgot to update the snippet but I get what you mean, but that's not the problem in the C code in TFA, the return is the last operation in the for loop (no code after it). But you are correct that rust does emit a warning if you put the println! after the break while gcc 4.9.1 builds the following without any warning even with -Wextra: #include <stdio.h> int main() { int i; for (i = 0; i < 10; i++) { break; printf("unreached\n"); } return 0; } Which is pretty surprising to me, especially since the optimizer is clever enough to completely remove the for loop and the static string from the asm output, so unlike rust they actually know it's unused.