[flang-commits] [flang] c1e093a - [flang][parser] Add a feature flag for multiple program units on one line. (#186533)
via flang-commits
flang-commits at lists.llvm.org
Mon Mar 16 09:55:23 PDT 2026
Author: Andre Kuhlenschmidt
Date: 2026-03-16T09:55:18-07:00
New Revision: c1e093a70c0c7601309813ddcdc3d5b6967808b8
URL: https://github.com/llvm/llvm-project/commit/c1e093a70c0c7601309813ddcdc3d5b6967808b8
DIFF: https://github.com/llvm/llvm-project/commit/c1e093a70c0c7601309813ddcdc3d5b6967808b8.diff
LOG: [flang][parser] Add a feature flag for multiple program units on one line. (#186533)
This PR adds a feature flag `MultipleProgramUnitsOnSameLine` that by
default allows program units to be terminated by semicolons, and then
allow the next program unit to follow on the same line.
It also adds some test programs to demonstrate using programming units
and showing the portability warning with "-pedantic".
Added:
flang/test/Parser/shared-line-program-units.f90
flang/test/Parser/shared-line-program-units.reject.0.f90
flang/test/Parser/shared-line-program-units.reject.1.f90
Modified:
flang/include/flang/Support/Fortran-features.h
flang/lib/Parser/program-parsers.cpp
flang/lib/Parser/stmt-parser.h
Removed:
################################################################################
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index cbcb3592f04c3..aa2c4cdc6d10b 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -57,7 +57,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
ForwardRefExplicitTypeDummy, InaccessibleDeferredOverride,
CudaWarpMatchFunction, DoConcurrentOffload, TransferBOZ, Coarray,
PointerPassObject, MultipleIdenticalDATA,
- DefaultStructConstructorNullPointer, AssumedRankIoItem)
+ DefaultStructConstructorNullPointer, AssumedRankIoItem,
+ MultipleProgramUnitsOnSameLine)
// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index 775810f8c3c0f..b26603b5aea45 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -68,9 +68,18 @@ static constexpr auto programUnit{
construct<ProgramUnit>(indirect(functionSubprogram)) ||
construct<ProgramUnit>(indirect(Parser<MainProgram>{}))};
-static constexpr auto normalProgramUnit{!consumedAllInput >>
- StartNewSubprogram{} >>
- programUnit / recovery(endOfStmt, skipToNextLineIfAny)};
+// Note, F'23 6.3.1 states that "A Fortran program unit is a sequence of one or
+// more lines, organized as Fortran statements, comments, and INCLUDE lines."
+// which could be interpreted as implying program units must exist on mutually
+// exclusive lines. Nag interprets it this way. We have an extension to allow
+// multiple program units on the same line.
+static constexpr auto normalProgramUnit{
+ !consumedAllInput >> StartNewSubprogram{} >> programUnit /
+ recovery((maybe(semicolons) >> endOfLine) ||
+ (extension<LanguageFeature::MultipleProgramUnitsOnSameLine>(
+ "nonstandard usage: end of program unit not terminated by new line"_port_en_US,
+ semicolons >> not(endOfLine))),
+ skipToNextLineIfAny)};
static constexpr auto globalCompilerDirective{
construct<ProgramUnit>(indirect(compilerDirective))};
diff --git a/flang/lib/Parser/stmt-parser.h b/flang/lib/Parser/stmt-parser.h
index b2bb8dd843642..a003f6ea99d96 100644
--- a/flang/lib/Parser/stmt-parser.h
+++ b/flang/lib/Parser/stmt-parser.h
@@ -37,10 +37,10 @@ constexpr auto checkEndOfKnownStmt{recovery(atEndOfStmt, SkipTo<'\n'>{})};
constexpr auto endOfLine{consumedAllInput ||
withMessage("expected end of line"_err_en_US, "\n"_ch >> ok)};
-constexpr auto semicolons{";"_ch >> skipMany(";"_tok) / space / maybe("\n"_ch)};
+constexpr auto semicolons{";"_ch >> skipMany(";"_tok) / space};
constexpr auto endOfStmt{
space >> withMessage("expected end of statement"_err_en_US,
- semicolons || endOfLine)};
+ (semicolons / maybe(endOfLine)) || endOfLine)};
constexpr auto skipToNextLineIfAny{consumedAllInput || SkipPast<'\n'>{}};
constexpr auto forceEndOfStmt{recovery(endOfStmt, skipToNextLineIfAny)};
diff --git a/flang/test/Parser/shared-line-program-units.f90 b/flang/test/Parser/shared-line-program-units.f90
new file mode 100644
index 0000000000000..acdf3cc87d789
--- /dev/null
+++ b/flang/test/Parser/shared-line-program-units.f90
@@ -0,0 +1,51 @@
+!RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s
+!RUN: not %flang_fc1 -pedantic -Werror -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s --check-prefix=ERROR
+! CHECK: Program -> ProgramUnit -> SubroutineSubprogram
+! CHECK: ProgramUnit -> FunctionSubprogram
+! CHECK: ProgramUnit -> MainProgram
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+subroutine sub; end; function fn(); end; program p; end;
+! CHECK: ProgramUnit -> SubroutineSubprogram
+! CHECK: ProgramUnit -> MainProgram
+! CHECK: ProgramUnit -> MainProgram
+! CHECK: ProgramUnit -> Module
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+subroutine sub2; end; end program; end program; module m; end
+! CHECK: ProgramUnit -> BlockData
+! CHECK: ProgramUnit -> BlockData
+! CHECK: ProgramUnit -> BlockData
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+block data bd; end; block data bd2; end; block data bd3; end
+! CHECK: ProgramUnit -> Module
+! CHECK: ProgramUnit -> Submodule
+! CHECK: ProgramUnit -> Submodule
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+module sm; end; submodule (sm) sm2; end; submodule (sm:sm2) sm3; end
+! CHECK: ProgramUnit -> MainProgram
+! CHECK: ProgramUnit -> MainProgram
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+program p; end; use sm; print *, "Hello, World!"; end
+! CHECK: ProgramUnit -> MainProgram
+! CHECK: ProgramUnit -> MainProgram
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+program p; end; use sm;
+ print *, "Hello, World!"; end
+! CHECK: ProgramUnit -> MainProgram
+! CHECK: ProgramUnit -> MainProgram
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+program p; end; use sm; print *, "Hello, World!";
+end
+! CHECK: ProgramUnit -> FunctionSubprogram
+! CHECK: ProgramUnit -> MainProgram
+function fn(); end
+10 print *, "1"; 20 print *, "2";
+end program;
+! CHECK: ProgramUnit -> FunctionSubprogram
+! CHECK: ProgramUnit -> MainProgram
+! ERROR: portability: nonstandard usage: end of program unit not terminated by new line
+function fn(); end; 10 print *, "1"; 20 print *, "2"; end program;
diff --git a/flang/test/Parser/shared-line-program-units.reject.0.f90 b/flang/test/Parser/shared-line-program-units.reject.0.f90
new file mode 100644
index 0000000000000..15e11455c372d
--- /dev/null
+++ b/flang/test/Parser/shared-line-program-units.reject.0.f90
@@ -0,0 +1,4 @@
+!RUN: not %flang_fc1 -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s
+! CHECK: error: Could not parse
+! CHECK: 4:21: error: expected '('
+program p; function fn(); end; end;
diff --git a/flang/test/Parser/shared-line-program-units.reject.1.f90 b/flang/test/Parser/shared-line-program-units.reject.1.f90
new file mode 100644
index 0000000000000..df471c815f2e3
--- /dev/null
+++ b/flang/test/Parser/shared-line-program-units.reject.1.f90
@@ -0,0 +1,4 @@
+!RUN: not %flang_fc1 -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s
+! CHECK: error: Could not parse
+! CHECK: 4:36: error: end of file
+function fn(); end; function fn2();
More information about the flang-commits
mailing list