[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