[flang-commits] [flang] [flang] Improve error recovery for bad statement after CONTAINS (PR #109698)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Sep 23 10:59:26 PDT 2024
https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/109698
>From bbb1d7c2e74007d4ec4865953bb79199522c62c3 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 23 Sep 2024 10:54:12 -0700
Subject: [PATCH] [flang] Improve error recovery for bad statement after
CONTAINS
After a CONTAINS statement in a program unit, a statement that
cannot begin a subprogram will trigger catastrophic error recovery.
But the compiler is presently emitting multiple errors for the
same location about expected variations of END statements.
Emit fewer messages.
Fixes https://github.com/llvm/llvm-project/issues/109609.
---
flang/lib/Parser/program-parsers.cpp | 26 +++++++-----
flang/lib/Parser/stmt-parser.h | 1 -
flang/test/Parser/recovery06.f90 | 62 ++++++++++++++++++++++++++++
3 files changed, 77 insertions(+), 12 deletions(-)
create mode 100644 flang/test/Parser/recovery06.f90
diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index c43696c52c1604..2b7da18a09bb30 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -249,8 +249,9 @@ TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
// R1403 end-program-stmt -> END [PROGRAM [program-name]]
TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
- construct<EndProgramStmt>(recovery(
- "END PROGRAM" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
+ construct<EndProgramStmt>(
+ recovery("END" >> defaulted("PROGRAM" >> maybe(name)) / atEndOfStmt,
+ progUnitEndStmtErrorRecovery)))
// R1404 module ->
// module-stmt [specification-part] [module-subprogram-part]
@@ -266,8 +267,9 @@ TYPE_CONTEXT_PARSER(
// R1406 end-module-stmt -> END [MODULE [module-name]]
TYPE_CONTEXT_PARSER("END MODULE statement"_en_US,
- construct<EndModuleStmt>(recovery(
- "END MODULE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
+ construct<EndModuleStmt>(
+ recovery("END" >> defaulted("MODULE" >> maybe(name)) / atEndOfStmt,
+ progUnitEndStmtErrorRecovery)))
// R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
TYPE_CONTEXT_PARSER("module subprogram part"_en_US,
@@ -334,7 +336,7 @@ TYPE_PARSER(construct<ParentIdentifier>(name, maybe(":" >> name)))
// R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US,
construct<EndSubmoduleStmt>(
- recovery("END SUBMODULE" >> maybe(name) || bareEnd,
+ recovery("END" >> defaulted("SUBMODULE" >> maybe(name)) / atEndOfStmt,
progUnitEndStmtErrorRecovery)))
// R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt
@@ -350,7 +352,7 @@ TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US,
// R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US,
construct<EndBlockDataStmt>(
- recovery("END BLOCK DATA" >> maybe(name) || bareEnd,
+ recovery("END" >> defaulted("BLOCK DATA" >> maybe(name)) / atEndOfStmt,
progUnitEndStmtErrorRecovery)))
// R1501 interface-block ->
@@ -564,8 +566,9 @@ TYPE_PARSER(construct<Suffix>(
"RESULT" >> parenthesized(name), maybe(languageBindingSpec)))
// R1533 end-function-stmt -> END [FUNCTION [function-name]]
-TYPE_PARSER(construct<EndFunctionStmt>(recovery(
- "END FUNCTION" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
+TYPE_PARSER(construct<EndFunctionStmt>(
+ recovery("END" >> defaulted("FUNCTION" >> maybe(name)) / atEndOfStmt,
+ progUnitEndStmtErrorRecovery)))
// R1534 subroutine-subprogram ->
// subroutine-stmt [specification-part] [execution-part]
@@ -591,8 +594,9 @@ TYPE_PARSER(
TYPE_PARSER(construct<DummyArg>(name) || construct<DummyArg>(star))
// R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
-TYPE_PARSER(construct<EndSubroutineStmt>(recovery(
- "END SUBROUTINE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
+TYPE_PARSER(construct<EndSubroutineStmt>(
+ recovery("END" >> defaulted("SUBROUTINE" >> maybe(name)) / atEndOfStmt,
+ progUnitEndStmtErrorRecovery)))
// R1538 separate-module-subprogram ->
// mp-subprogram-stmt [specification-part] [execution-part]
@@ -609,7 +613,7 @@ TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US,
// R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US,
construct<EndMpSubprogramStmt>(
- recovery("END PROCEDURE" >> maybe(name) || bareEnd,
+ recovery("END" >> defaulted("PROCEDURE" >> maybe(name)) / atEndOfStmt,
progUnitEndStmtErrorRecovery)))
// R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]
diff --git a/flang/lib/Parser/stmt-parser.h b/flang/lib/Parser/stmt-parser.h
index 00bae2bf950c85..ee45c6fd5d38c1 100644
--- a/flang/lib/Parser/stmt-parser.h
+++ b/flang/lib/Parser/stmt-parser.h
@@ -90,7 +90,6 @@ constexpr auto executionPartErrorRecovery{stmtErrorRecoveryStart >>
// END statement error recovery
constexpr auto missingOptionalName{pure<std::optional<Name>>()};
constexpr auto noNameEnd{"END" >> missingOptionalName};
-constexpr auto bareEnd{noNameEnd / recovery(atEndOfStmt, SkipTo<'\n'>{})};
// For unrecognizable construct END statements. Be sure to not consume
// a program unit's END statement.
diff --git a/flang/test/Parser/recovery06.f90 b/flang/test/Parser/recovery06.f90
new file mode 100644
index 00000000000000..4c0214180eb0f8
--- /dev/null
+++ b/flang/test/Parser/recovery06.f90
@@ -0,0 +1,62 @@
+! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
+program p
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: END PROGRAM statement
+ continue
+end
+
+subroutine s
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: SUBROUTINE subprogram
+ continue
+end
+
+function f()
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: FUNCTION subprogram
+ continue
+end
+
+module m
+ interface
+ module subroutine ms
+ end
+ end interface
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: END MODULE statement
+ continue
+end
+
+module m2
+ contains
+ subroutine m2s
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: SUBROUTINE subprogram
+ continue
+ end
+end
+
+submodule(m) s1
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: END SUBMODULE statement
+ continue
+end
+
+submodule(m) s2
+ contains
+ module procedure ms
+ contains
+! CHECK: error: expected 'END'
+! CHECK: in the context: END PROCEDURE statement
+ continue
+ end
+end
+
+! Ensure no error cascade
+! CHECK-NOT: error:
More information about the flang-commits
mailing list