This is an archive of the discontinued LLVM Phabricator instance.

[clang] better error message for while loops outside of control flow
ClosedPublic

Authored by inclyc on Jul 12 2022, 9:20 AM.

Details

Summary

report an error when encountering 'while' token parsing declarator

clang/test/Parser/while-loop-outside-function.c:3:1: error: while loop outside of a function
while // expected-error {{while loop outside of a function}}
^
clang/test/Parser/while-loop-outside-function.c:7:1: error: while loop outside of a function
while // expected-error {{while loop outside of a function}}
^

Fixes https://github.com/llvm/llvm-project/issues/34462

Diff Detail

Event Timeline

inclyc created this revision.Jul 12 2022, 9:20 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 12 2022, 9:20 AM
inclyc requested review of this revision.Jul 12 2022, 9:20 AM
inclyc added a reviewer: Restricted Project.Jul 12 2022, 11:28 AM
inclyc set the repository for this revision to rG LLVM Github Monorepo.
Herald added a project: Restricted Project. · View Herald TranscriptJul 12 2022, 11:28 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
mizvekov added inline comments.
clang/test/Parser/while-loop-outside-function.c
4–5

How about just making the error be the same thing the note would say?

clang/test/Parser/while-loop-outside-function.cpp
28

Missing newline

inclyc added inline comments.Jul 17 2022, 5:51 PM
clang/test/Parser/while-loop-outside-function.c
4–5

OK, so just create a new error directly, and then report the error when encountering the while token?

mizvekov added inline comments.Jul 17 2022, 6:06 PM
clang/test/Parser/while-loop-outside-function.c
4–5

Well the end result should be that there is only one error, while outside of function, because that explains everything the user needs to know.

It would be strange to report the expected identifier or ... error in addition to this one, it would be just noise.

How to go about implementing that I leave it up to you :P
Unless you need some specific help of course.

inclyc updated this revision to Diff 445455.Jul 18 2022, 4:43 AM
inclyc edited the summary of this revision. (Show Details)

Now it only generates 1 error encountering token "while"

./local/while_loop_outside_func.cpp:1:1: error: while loop outside of function
while (true) {
^
1 error generated.
inclyc updated this revision to Diff 445458.Jul 18 2022, 4:48 AM

Now it only generates 1 error encountering token "while"

Yes thank you, that is what I meant!

But now we just gotta make sure this stays true for more complex test cases.

clang/include/clang/Basic/DiagnosticParseKinds.td
542

Looking at other diagnostics which contain the word outside, there are many different ways to spell this.

Other possibilities include:

  • while loop outside function
  • while loop outside of a function
  • while loop outside of a function body

All of these alternates could be justified with some prior art here.
I have no strong opinions either way, this seems fine, just making a note.

clang/test/Parser/while-loop-outside-function.c
4

You could break this down further into more lines to test exactly where the error is placed. Id expect it to be placed at the while keyword.

9

Can you add a few more test cases showing how error recovery is performing here?

Have we parsed this function declaration at all, or were we skipping until the next ';'?

What happens if there are (multiple) statements in the loop's block?

How do we handle a do ... while() loop instead?

Does it make a difference if the loop contains a block or a (possibly empty) single statement?

inclyc added inline comments.Jul 18 2022, 5:42 PM
clang/test/Parser/while-loop-outside-function.c
9

For this occasion,

// RUN: %clang_cc1 -fsyntax-only -verify %s

while(true) {}; // expected-error {{while loop outside of function}}

// without semicolon
while(true) {} // expected-error {{while loop outside of function}}


while(true) {
    // some statements
    int some_var = 3;
    some_var += 2;
}

while(true) 
{
    // some statements
    int some_var = 3;
    some_var += 2;
}

do {
    int some_var = 1;
    some_var += 3;
} 
while(true);

void someFunction() {
    while(true) {};
}

class SomeClass {
public:
    while(true) {}
    void some_fn() {
        while(true) {}
    }
};
./clang/test/Parser/while-loop-outside-function.cpp:3:1: error: while loop outside of function
while(true) {}; // expected-error {{while loop outside of function}}
^
./clang/test/Parser/while-loop-outside-function.cpp:6:1: error: while loop outside of function
while(true) {} // expected-error {{while loop outside of function}}
^
./clang/test/Parser/while-loop-outside-function.cpp:9:1: error: while loop outside of function
while(true) {
^
./clang/test/Parser/while-loop-outside-function.cpp:15:1: error: while loop outside of function
while(true) 
^
./clang/test/Parser/while-loop-outside-function.cpp:22:1: error: expected unqualified-id
do {
^
./clang/test/Parser/while-loop-outside-function.cpp:26:1: error: while loop outside of function
while(true);
^
./clang/test/Parser/while-loop-outside-function.cpp:34:5: error: expected member name or ';' after declaration specifiers
    while(true) {}
    ^
7 errors generated.

The parser generates the newly added error for every "top-level" declarator. For do ... while(...) loops it generates two errors. I think ideally only one error should be reported, only generating an error at the latter while token, without generating a "noise" at the preceding do. And, this patch doesn't seem to produce good results where classes, structs, etc. are also not part of the function body.

At first, when I solved this issue, I thought he only needed to report the appearance of the top-level while loop, without considering do-while, in a class, or in a structure. So the current code is only in Parser, this error is reported when the while token is encountered parsing declarators.

inclyc added inline comments.Jul 18 2022, 5:48 PM
clang/test/Parser/while-loop-outside-function.c
4

Passes this test case, I will submit this in the next patch.

// RUN: %clang_cc1 -fsyntax-only -verify %s

while(1) {}; // expected-error {{while loop outside of function}}


while(1) // expected-error {{while loop outside of function}}
{

}

while(1) { // expected-error {{while loop outside of function}}

}

while(1) { // expected-error {{while loop outside of function}}

};

while(1) // expected-error {{while loop outside of function}}
{

}

while(1) { // expected-error {{while loop outside of function}}

};

// without semicolon
while(1) {} // expected-error {{while loop outside of function}}

void some_fn();

void some_fn() {
    while(1) {};
}
inclyc marked an inline comment as not done.Jul 18 2022, 5:49 PM
mizvekov added inline comments.Jul 18 2022, 5:56 PM
clang/test/Parser/while-loop-outside-function.c
9

I see, thanks for the explanations.

I think this patch is a very simple change that brings some improvement, and apparently it does not regress anything or cause any unfortunate error recovery.

You don't really need to improve these other cases in the same patch, I am just checking that this was all considered :-)

But please do add these test cases to the patch!

inclyc added inline comments.Jul 18 2022, 6:00 PM
clang/test/Parser/while-loop-outside-function.c
9

Do you think we need to change something more to accurately report while / do-while / for loops, and only report errors outside of a reasonable control flow?

inclyc added inline comments.Jul 18 2022, 6:07 PM
clang/test/Parser/while-loop-outside-function.c
9

Right now this patch is far from perfect, ideally it should report various types of loops (as mentioned above) and also in a non-control flow context, such as class members, typedefs, etc. (I don't know how to do this, sorry)

inclyc updated this revision to Diff 445668.Jul 18 2022, 6:27 PM
inclyc retitled this revision from [Clang] add a diagnostic note 'while loop outside functions' at global scope to [clang] add a diagnostic note 'while loop outside functions' at global scope.
mizvekov added inline comments.Jul 18 2022, 7:01 PM
clang/test/Parser/while-loop-outside-function.c
9

Don't worry about it! I think this patch is pretty good bang for the buck, for the cost of basically two lines of code you get much better diagnostic for the bulk of the interesting cases, without regressing anything.

11–20

I think you don't really need to test these two cases separately. They differ by just white space.

The one thing that I did suggest is that, for at least one of your test cases, put the while keyword alone by itself on a line,
so that you can test that the diagnostic points to the location of the keyword.

inclyc updated this revision to Diff 445712.Jul 19 2022, 12:38 AM
inclyc updated this revision to Diff 445771.Jul 19 2022, 3:57 AM

Is the build error related to this patch?

Is the build error related to this patch?

I don't think so, it's not even close to what you are changing.

Could you please review the latest patch ? I have removed some redundant test cases mentioned above

mizvekov added inline comments.Jul 21 2022, 5:14 PM
clang/test/Parser/while-loop-outside-function.c
5

What I meant is something like this, we test that the error caret would be placed on the while keyword.
You have to break it down like this as you can't express in the verifier where an error would occur inside a line.

23

To demonstrate recovery, I think it would make sense to try to use this declaration later, and test that it would work.
Ie you can try to 'overload' on the return type and see that you get the expected error.

inclyc updated this revision to Diff 446690.Jul 21 2022, 7:25 PM
inclyc marked 2 inline comments as not done.Jul 21 2022, 7:36 PM
inclyc added inline comments.
clang/test/Parser/while-loop-outside-function.c
4

Thanks a lot for your suggestion, I replaced this statement with two lines to test if the diagnostics are correctly given at the token while.

The C++ test cases is also changed like this.

11

This test case checks whether the program can correctly diagnose other errors after reporting our newly added error

25

Should not give diagnostic information at these 2 lines of correct statements

mizvekov accepted this revision as: mizvekov.Jul 22 2022, 6:11 PM

Thanks! The patch itself LGTM.

Please update / fix up the commit message before merging. It still mentions note and has some minor English spelling issues.

This revision is now accepted and ready to land.Jul 22 2022, 6:11 PM
inclyc retitled this revision from [clang] add a diagnostic note 'while loop outside functions' at global scope to [clang] better error message for while loops outside of control flow.Jul 22 2022, 7:32 PM
inclyc edited the summary of this revision. (Show Details)
This revision was landed with ongoing or failed builds.Jul 24 2022, 8:49 PM
This revision was automatically updated to reflect the committed changes.