- Give I[1] and I[-1] a name:
- Easier to understand
- Easier to debug (since you don't go through operator[] everytime)
- TheLine->First != TheLine->Last follows since last is a l brace and first isn't.
- Factor the check for is(tok::l_brace) out.
- Drop else after return.
Details
Diff Detail
Unit Tests
Time | Test | |
---|---|---|
50 ms | x64 debian > LLVM.Bindings/Go::go.test |
Event Timeline
Fixed formatting and added a name for I[-1].
I[i + 1] is used in the loop condition, which also checks if i + 1 is valid, so do not give a name here.
@HazardyKnusperkeks, it *seems* as if this commit (or one of others indicated on Changes tab of the link below) provoked failures in ASan. But it could be something else.
https://lab.llvm.org/buildbot/#/builders/5/builds/16734
Could you have a look?
Okay, I don't have access to ASAN or so, I'm using MinGW on Windows. But I suspect it is the Assignment of the PreviousLine since this is not existent every time. So I see the following solutions:
- Only name NextLine, and use I[-1].
- const auto HasPreviousLine = I != AnnotatedLines.begin(); const auto &PreviousLine = HasPreviousLine ? *I[-1] : *I; which is safe, since PreviousLine is only used if HasPreviousLine is true, but is a bit confusing. It would get an explaining comment.
- Rearrange the statements so that we can have only one check if there is a previous line and define PreviousLine inside that if. It remains to be seen if that's NFC.
I would prefer option 3, but if that would change the behavior would go for option 2.
That's look good. And it's a nice clean up with all those repeated checks removed. Don't forget to reformat before landing.
But I suspect it is the Assignment of the PreviousLine since this is not existent every time.
Yep!
So I see the following solutions:
- Only name NextLine, and use I[-1].
- const auto HasPreviousLine = I != AnnotatedLines.begin(); const auto &PreviousLine = HasPreviousLine ? *I[-1] : *I; which is safe, since PreviousLine is only used if HasPreviousLine is true, but is a bit confusing. It would get an explaining comment.
- Rearrange the statements so that we can have only one check if there is a previous line and define PreviousLine inside that if. It remains to be seen if that's NFC.
I would prefer option 3, but if that would change the behavior would go for option 2.
There is option 4: change the type of PreviousLine to a pointer, and replace PreviousLine. with PreviousLine->. (You can rename PreviousLine if you think the naming is inconsistent with NextLine.) This would keep the patch being NFC.
I'm open for that, but I think the current diff (plus corrected formatting) is better. And at least according to our tests it is NFC.
Moving the handling of empty record blocks might be non-NFC? Maybe option 4 for now and the refactoring in another patch?
clang/lib/Format/UnwrappedLineFormatter.cpp | ||
---|---|---|
288 | Is TheLine->First != TheLine->Last redundant? | |
310 | I don't think you can drop else here. | |
317 | Ditto. | |
335–360 | Handling empty record blocks here instead of earlier may have unknown side effects? |
clang/lib/Format/UnwrappedLineFormatter.cpp | ||
---|---|---|
288 | This seems to be an error on my side. |
clang/lib/Format/UnwrappedLineFormatter.cpp | ||
---|---|---|
215 | I would move this line to just before handling empty record blocks below. | |
237–238 | I'd either leave this lambda alone or further simplify it as suggested here. | |
238–245 | Drop the I if you decide to further simplify the lambda as suggested above. | |
310 |
I was wrong. For some reason, I didn't see the return statement. | |
317 | I missed the return here as well. | |
332–343 | If you want, you can factor out PreviousLine && TheLine->First->is(tok::l_brace) and even combine the two if statements as they both return 0. |
clang/lib/Format/UnwrappedLineFormatter.cpp | ||
---|---|---|
215 | If it were just a simple initialization, it wouldn't matter much. However, it would be a bit wasteful as PreviousLine always gets computed here even if the function may return before the pointer would get chance to be used. If you really want to keep all related definitions together, wouldn't you want to move lines 214-215 up to right after line 211? | |
237–238 | [&] doesn't capture everything. It only captures the variables that are used in the lambda body. That being said, I'm okay with explicitly capturing each one. |
clang/lib/Format/UnwrappedLineFormatter.cpp | ||
---|---|---|
215 |
No compiler will (or should) skip generating code that calculates PreviousLine, which may or may not get used at runtime. I'm not aware of any compiler that is smart enough to move the initialization code to just before where the variable is first used. To illustrate the difference, I compiled the code below with clang++ -Wall -std=c++11 -O3 -S foo.cpp: #include <vector> using namespace std; using Type = vector<int *>; int f(const Type &V, Type::const_iterator I) { const auto *P = I != V.begin() ? I[-1] : nullptr; if (I == V.end()) return 0; return *P; } The generated code in foo.s includes the following: .cfi_startproc ; %bb.0: ldr x8, [x0] cmp x8, x1 b.eq LBB0_3 ; %bb.1: ldur x8, [x1, #-8] ldr x9, [x0, #8] cmp x9, x1 b.eq LBB0_4 LBB0_2: ldr w0, [x8] ret LBB0_3: mov x8, #0 ldr x9, [x0, #8] cmp x9, x1 b.ne LBB0_2 LBB0_4: mov w0, #0 ret .cfi_endproc As you can see, the initialization code was neither optimized away nor moved. When I changed the function body to: if (I == V.end()) return 0; const auto *P = I != V.begin() ? I[-1] : nullptr; return *P; The generated code became much simpler: .cfi_startproc ; %bb.0: ldr x8, [x0, #8] cmp x8, x1 b.eq LBB0_2 ; %bb.1: ldur x8, [x1, #-8] ldr w0, [x8] ret LBB0_2: mov w0, #0 ret .cfi_endproc |
I would move this line to just before handling empty record blocks below.