Skip to content

Commit be6bc6a

Browse files
authored
[flang] Better recovery from errors in a loop control (#117025)
When there's an error in a DO statement loop control, error recovery isn't great. A bare "DO" is a valid statement, so a failure to parse its loop control doesn't fail on the whole statement. Its partial parse ends after the keyword, and as some other statement parsers can get further into the input before failing, errors in the loop control can lead to confusing error messages about bad pointer assignment statements and others. So just check that a bare "DO" is followed by the end of the statement.
1 parent 3f59474 commit be6bc6a

File tree

4 files changed

+30
-5
lines changed

4 files changed

+30
-5
lines changed

flang/docs/ParserCombinators.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,16 @@ is built. All of the following parsers consume characters acquired from
178178
Last, a string literal `"..."_debug` denotes a parser that emits the string to
179179
`llvm::errs` and succeeds. It is useful for tracing while debugging a parser but should
180180
obviously not be committed for production code.
181+
182+
### Messages
183+
A list of generated error and warning messages is maintained in the `ParseState`.
184+
The parser combinator that handles alternatives (`||` and `first()`) will
185+
discard the messages from alternatives that fail when there is an alternative
186+
that succeeds.
187+
But when no alternative succeeds, and the alternative parser as a whole is
188+
failing, the messages that survive are chosen from the alternative that
189+
recognized any input tokens, if only one alternative did so;
190+
and when multiple alternatives recognized tokens, the messages from the
191+
alternative that proceeded the furthest into the input are retained.
192+
This strategy tends to show the most useful error messages to the user
193+
in situations where a statement fails to parse.

flang/lib/Parser/executable-parsers.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// Per-type parsers for executable statements
1010

1111
#include "basic-parsers.h"
12-
#include "debug-parser.h"
1312
#include "expr-parsers.h"
1413
#include "misc-parsers.h"
1514
#include "stmt-parser.h"
@@ -282,18 +281,26 @@ TYPE_CONTEXT_PARSER("loop control"_en_US,
282281
"CONCURRENT" >> concurrentHeader,
283282
many(Parser<LocalitySpec>{})))))
284283

284+
// "DO" is a valid statement, so the loop control is optional; but for
285+
// better recovery from errors in the loop control, don't parse a
286+
// DO statement with a bad loop control as a DO statement that has
287+
// no loop control and is followed by garbage.
288+
static constexpr auto loopControlOrEndOfStmt{
289+
construct<std::optional<LoopControl>>(Parser<LoopControl>{}) ||
290+
lookAhead(";\n"_ch) >> construct<std::optional<LoopControl>>()};
291+
285292
// R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control]
286293
// A label-do-stmt with a do-construct-name is parsed as a nonlabel-do-stmt
287294
// with an optional label.
288295
TYPE_CONTEXT_PARSER("label DO statement"_en_US,
289-
construct<LabelDoStmt>("DO" >> label, maybe(loopControl)))
296+
construct<LabelDoStmt>("DO" >> label, loopControlOrEndOfStmt))
290297

291298
// R1122 nonlabel-do-stmt -> [do-construct-name :] DO [loop-control]
292299
TYPE_CONTEXT_PARSER("nonlabel DO statement"_en_US,
293300
construct<NonLabelDoStmt>(
294-
name / ":", "DO" >> maybe(label), maybe(loopControl)) ||
301+
name / ":", "DO" >> maybe(label), loopControlOrEndOfStmt) ||
295302
construct<NonLabelDoStmt>(construct<std::optional<Name>>(),
296-
construct<std::optional<Label>>(), "DO" >> maybe(loopControl)))
303+
construct<std::optional<Label>>(), "DO" >> loopControlOrEndOfStmt))
297304

298305
// R1132 end-do-stmt -> END DO [do-construct-name]
299306
TYPE_CONTEXT_PARSER("END DO statement"_en_US,

flang/lib/Parser/type-parsers.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ constexpr Parser<ForallAssignmentStmt> forallAssignmentStmt; // R1053
102102
constexpr Parser<ForallStmt> forallStmt; // R1055
103103
constexpr Parser<Selector> selector; // R1105
104104
constexpr Parser<EndSelectStmt> endSelectStmt; // R1143 & R1151 & R1155
105-
constexpr Parser<LoopControl> loopControl; // R1123
106105
constexpr Parser<ConcurrentHeader> concurrentHeader; // R1125
107106
constexpr Parser<IoUnit> ioUnit; // R1201, R1203
108107
constexpr Parser<FileUnitNumber> fileUnitNumber; // R1202

flang/test/Parser/recovery07.f90

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
2+
! CHECK: error: expected ':'
3+
! CHECK: in the context: loop control
4+
do concurrent(I = 1, N)
5+
end do
6+
end

0 commit comments

Comments
 (0)