diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index bb9c0ebe84a16..5f82b3f4a5e48 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -285,6 +285,10 @@ end it's an error only if the resolution is ambiguous. * An entity may appear in a `DATA` statement before its explicit type declaration under `IMPLICIT NONE(TYPE)`. +* INCLUDE lines can start in any column, can be preceded in + fixed form source by a '0' in column 6, can contain spaces + between the letters of the word INCLUDE, and can have a + numeric character literal kind prefix on the file name. ### Extensions supported when enabled by options @@ -412,6 +416,9 @@ end This is especially desirable when two generics of the same name are combined due to USE association and the mixture may be inadvertent. +* Since Fortran 90, INCLUDE lines have been allowed to have + a numeric kind parameter prefix on the file name. No other + Fortran compiler supports them that I can find. ## Behavior in cases where the standard is ambiguous or indefinite diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index 6444c8713c722..09b31b1dc7cc9 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -847,12 +847,25 @@ const char *Prescanner::IsFreeFormComment(const char *p) const { std::optional Prescanner::IsIncludeLine(const char *start) const { const char *p{SkipWhiteSpace(start)}; - for (char ch : "include"s) { - if (ToLowerCaseLetter(*p++) != ch) { + if (*p == '0' && inFixedForm_ && p == start + 5) { + // Accept " 0INCLUDE" in fixed form. + p = SkipWhiteSpace(p + 1); + } + for (const char *q{"include"}; *q; ++q) { + if (ToLowerCaseLetter(*p) != *q) { return std::nullopt; } + p = SkipWhiteSpace(p + 1); + } + if (IsDecimalDigit(*p)) { // accept & ignore a numeric kind prefix + for (p = SkipWhiteSpace(p + 1); IsDecimalDigit(*p); + p = SkipWhiteSpace(p + 1)) { + } + if (*p != '_') { + return std::nullopt; + } + p = SkipWhiteSpace(p + 1); } - p = SkipWhiteSpace(p); if (*p == '"' || *p == '\'') { return {p - start}; } @@ -1022,7 +1035,11 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) { nextLine_[3] == ' ' && nextLine_[4] == ' ') { char col6{nextLine_[5]}; if (col6 != '\n' && col6 != '\t' && col6 != ' ' && col6 != '0') { - return nextLine_ + 6; + if ((col6 == 'i' || col6 == 'I') && IsIncludeLine(nextLine_)) { + // It's An INCLUDE line, not a continuation + } else { + return nextLine_ + 6; + } } } if (IsImplicitContinuation()) { diff --git a/flang/test/Parser/Inputs/include-file b/flang/test/Parser/Inputs/include-file new file mode 100644 index 0000000000000..f2cb4f572ce9c --- /dev/null +++ b/flang/test/Parser/Inputs/include-file @@ -0,0 +1 @@ + x = 1 diff --git a/flang/test/Parser/include.f b/flang/test/Parser/include.f new file mode 100644 index 0000000000000..8a7fe3a2ecd9d --- /dev/null +++ b/flang/test/Parser/include.f @@ -0,0 +1,68 @@ +! RUN: %flang_fc1 -E -I %S/Inputs %s 2>&1 | FileCheck %s + include 'include-file' + include "include-file" + include 1_'include-file' + include 1_"include-file" + i n c l u d e 'include-file' + INCLUDE 'include-file' + I N C L U D E 'include-file' +include 'include-file' +include "include-file" +include 1_'include-file' +include 1_"include-file" +i n c l u d e 'include-file' +INCLUDE 'include-file' +I N C L U D E 'include-file' + 0include 'include-file' + x = 2 + include 'include-file' + print *, " + 1include 'not-an-include' + 2" +cinclude 'not-an-include' +*include 'not-an-include' +!include 'not-an-include' +c include 'not-an-include' +* include 'not-an-include' +! include 'not-an-include' + end + +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include.f" 17 +!CHECK: x = 2 +!CHECK:#line "{{.*[/\\]}}include-file" 1 +!CHECK: x = 1 +!CHECK:#line "{{.*[/\\]}}include.f" 19 +!CHECK: print *, " & +!CHECK: &include 'not-an-include' & +!CHECK: &" +!CHECK: end