[flang-commits] [flang] [flang] Accept C-style comments in label fields (PR #207012)
Leandro Lupori via flang-commits
flang-commits at lists.llvm.org
Tue Sep 15 12:58:48 PDT 2026
https://github.com/luporl updated https://github.com/llvm/llvm-project/pull/207012
>From 08ecad840aea161892c6b22ebf9abda0453eb209 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Mon, 29 Jun 2026 19:35:59 -0300
Subject: [PATCH 01/12] [flang] Accept C-style comments in label fields
The main goal of this patch is to make multi-language header files
easier to write and use in fixed format sources. For this reason, and
for simplicity, C-style comments after labels, directives and OpenMP
conditional compilation sentinels are not supported.
Fixes #127426
---
flang/lib/Parser/prescan.cpp | 117 ++++++++++++++-------
flang/test/Preprocessing/fixed-c-comment.F | 62 +++++++++++
2 files changed, 141 insertions(+), 38 deletions(-)
create mode 100644 flang/test/Preprocessing/fixed-c-comment.F
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index db4b50a492002..24a0f72df5a12 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -70,6 +70,15 @@ static inline constexpr bool IsFixedFormCommentChar(char ch) {
return ch == '!' || ch == '*' || ch == 'C' || ch == 'c';
}
+static bool HasTabInLabelField(const char *col1) {
+ for (int i{0}; i < 6; ++i) {
+ if (col1[i] == '\t') {
+ return true;
+ }
+ }
+ return false;
+}
+
static void NormalizeCompilerDirectiveCommentMarker(TokenSequence &dir) {
char *p{dir.GetMutableCharData()};
char *limit{p + dir.SizeInChars()};
@@ -436,6 +445,30 @@ void Prescanner::LabelField(TokenSequence &token) {
int colOffset{column_ - 1};
const char *start{at_};
std::optional<int> badColumn;
+
+ // Skip C-style comments.
+ const char *p{SkipWhiteSpace(start)};
+ long spaces{HasTabInLabelField(start - colOffset) ? 6 : p - start};
+ if (spaces < 6 && IsCComment(p)) {
+ at_ += spaces;
+ column_ += spaces;
+ if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
+ Say(LanguageFeature::ClassicCComments, GetCurrentProvenance(),
+ "nonstandard usage: C-style comment"_port_en_US);
+ }
+ SkipCComments();
+ // Fix `column_`, which may be incorrect after multi-line comments.
+ p = at_ - 1;
+ while (p > start && *p != '\n') {
+ --p;
+ }
+ if (*p == '\n') {
+ column_ = at_ - p;
+ }
+ colOffset = column_ - 1;
+ start = at_;
+ }
+
for (; *at_ != '\n' && column_ <= 6; ++at_) {
if (*at_ == '\t') {
++at_;
@@ -766,39 +799,39 @@ void Prescanner::UpdateSourcePositionAfterSkip(const char *after) {
bool Prescanner::NextToken(TokenSequence &tokens) {
CHECK(at_ >= start_ && at_ < limit_);
- if (InFixedFormSource() && !preprocessingOnly_) {
+ bool compilingFixedForm{InFixedFormSource() && !preprocessingOnly_};
+ if (compilingFixedForm) {
SkipSpaces();
- } else {
- if (*at_ == '/' && IsCComment(at_)) {
- // Recognize and skip over classic C style /*comments*/ when
- // outside a character literal.
- WarnCComment(at_);
- SkipCComments();
- }
- if (IsSpaceOrTab(at_)) {
- // Compress free-form white space into a single space character.
- const auto theSpace{at_};
- char previous{at_ <= start_ ? ' ' : at_[-1]};
- NextChar();
- SkipSpaces();
- if (*at_ == '\n' && !omitNewline_) {
- // Discard white space at the end of a line.
- } else if (!inPreprocessorDirective_ &&
- (previous == '(' || *at_ == '(' || *at_ == ')')) {
- // Discard white space before/after '(' and before ')', unless in a
- // preprocessor directive. This helps yield space-free contiguous
- // names for generic interfaces like OPERATOR( + ) and
- // READ ( UNFORMATTED ), without misinterpreting #define f (notAnArg).
- // This has the effect of silently ignoring the illegal spaces in
- // the array constructor ( /1,2/ ) but that seems benign; it's
- // hard to avoid that while still removing spaces from OPERATOR( / )
- // and OPERATOR( // ).
- } else {
- // Preserve the squashed white space as a single space character.
- tokens.PutNextTokenChar(' ', GetProvenance(theSpace));
- tokens.CloseToken();
- return true;
- }
+ }
+ if (*at_ == '/' && IsCComment(at_)) {
+ // Recognize and skip over classic C style /*comments*/ when
+ // outside a character literal.
+ WarnCComment(at_);
+ SkipCComments();
+ }
+ if (!compilingFixedForm && IsSpaceOrTab(at_)) {
+ // Compress free-form white space into a single space character.
+ const auto theSpace{at_};
+ char previous{at_ <= start_ ? ' ' : at_[-1]};
+ NextChar();
+ SkipSpaces();
+ if (*at_ == '\n' && !omitNewline_) {
+ // Discard white space at the end of a line.
+ } else if (!inPreprocessorDirective_ &&
+ (previous == '(' || *at_ == '(' || *at_ == ')')) {
+ // Discard white space before/after '(' and before ')', unless in a
+ // preprocessor directive. This helps yield space-free contiguous
+ // names for generic interfaces like OPERATOR( + ) and
+ // READ ( UNFORMATTED ), without misinterpreting #define f (notAnArg).
+ // This has the effect of silently ignoring the illegal spaces in
+ // the array constructor ( /1,2/ ) but that seems benign; it's
+ // hard to avoid that while still removing spaces from OPERATOR( / )
+ // and OPERATOR( // ).
+ } else {
+ // Preserve the squashed white space as a single space character.
+ tokens.PutNextTokenChar(' ', GetProvenance(theSpace));
+ tokens.CloseToken();
+ return true;
}
}
brokenToken_ = false;
@@ -1430,12 +1463,19 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
}
tabInCurrentLine_ = false;
char col1{*nextLine_};
+ int trailingSpaces{0};
+ for (int i{4}; i > 0 && nextLine_[i] == ' '; --i) {
+ ++trailingSpaces;
+ }
+ bool CCommentAndSpaces{!HasTabInLabelField(nextLine_) &&
+ SkipCComment(SkipWhiteSpace(nextLine_)) - nextLine_ + trailingSpaces ==
+ 5};
bool canBeNonDirectiveContinuation{
- (col1 == ' ' ||
- ((col1 == 'D' || col1 == 'd') &&
- features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
- nextLine_[1] == ' ' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
- nextLine_[4] == ' '};
+ ((col1 == ' ' ||
+ ((col1 == 'D' || col1 == 'd') &&
+ features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
+ trailingSpaces == 4) ||
+ CCommentAndSpaces};
if (InCompilerDirective() && !(InConditionalLine() && !preprocessingOnly_)) {
// !$ under -E is not continued, but deferred to later compilation
if (IsFixedFormCommentChar(col1) &&
@@ -1499,7 +1539,8 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
}
if (canBeNonDirectiveContinuation) {
const char *col6{nextLine_ + 5};
- if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
+ if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6) &&
+ !IsCComment(col6)) {
if ((*col6 == 'i' || *col6 == 'I') && IsIncludeLine(nextLine_)) {
// It's an INCLUDE line, not a continuation
} else {
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment.F
new file mode 100644
index 0000000000000..82db6f7b43fa0
--- /dev/null
+++ b/flang/test/Preprocessing/fixed-c-comment.F
@@ -0,0 +1,62 @@
+! RUN: %flang_fc1 -fsyntax-only %s 2>&1
+! RUN: %flang -E %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
+
+ integer :: i
+
+! CHECK-NOT: C comment
+! CHECK: i = 1
+! ERROR: portability: nonstandard usage: C-style comment
+/* Old style C comments
+ *comments
+ */
+#define VAL 1
+
+! ERROR: portability: nonstandard usage: C-style comment
+/* Single-line C comment */
+ /* Single-line C comment */
+ /* Single-line C comment */
+ /* Single-line C comment */
+ /* Single-line C comment */
+ /* Single-line C comment */
+ /* Single-line C comment */
+ /* Single-line C comment */
+ i = VAL
+
+! CHECK-NOT: /*
+! CHECK-NOT: Multi
+! CHECK-NOT: C comment
+! CHECK-NOT: */
+! CHECK: i = 2
+/*
+ * Multi-line C comment
+ * comment
+ */
+ /* Multi-line
+C comment */
+ i = 2
+
+! CHECK: i = 3
+! CHECK: i = 4
+! CHECK: 9 i = 5+ 6
+/* C comment + statement */ i = 3
+ /* C comment + statement */ i = 4
+/**/90i = 5
+/**/ + + 6
+
+! CHECK-NOT: /*
+! CHECK-NOT: C comment
+! CHECK-NOT: */
+! CHECK: 100 i = 7
+/* Multi-line C comment + statement
+*/100 i = 7
+
+! CHECK: i = 8
+! CHECK-NOT: C comment
+ i = 8 /* C comment after statement */
+
+! CHECK: print
+! CHECK-NOT: C comment
+ print *, "TAB"
+ /* C comment after tab */
+ end
>From 02c6085727ae4cc51828628b54363edda9e79f5d Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 1 Jul 2026 17:05:34 +0000
Subject: [PATCH 02/12] Fix Windows build
---
flang/lib/Parser/prescan.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 24a0f72df5a12..ed314acef43a3 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -448,7 +448,8 @@ void Prescanner::LabelField(TokenSequence &token) {
// Skip C-style comments.
const char *p{SkipWhiteSpace(start)};
- long spaces{HasTabInLabelField(start - colOffset) ? 6 : p - start};
+ int spaces{
+ HasTabInLabelField(start - colOffset) ? 6 : static_cast<int>(p - start)};
if (spaces < 6 && IsCComment(p)) {
at_ += spaces;
column_ += spaces;
>From 03062a666ff7e676be559665cdfe0d66612cae45 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Thu, 2 Jul 2026 17:40:31 -0300
Subject: [PATCH 03/12] Address review's comments
---
flang/lib/Parser/prescan.cpp | 8 ++++----
flang/test/Preprocessing/fixed-c-comment.F | 8 +++++++-
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index ed314acef43a3..4814071f4d9f9 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -71,7 +71,7 @@ static inline constexpr bool IsFixedFormCommentChar(char ch) {
}
static bool HasTabInLabelField(const char *col1) {
- for (int i{0}; i < 6; ++i) {
+ for (int i{0}; i < 6 && col1[i] != '\n'; ++i) {
if (col1[i] == '\t') {
return true;
}
@@ -1468,9 +1468,9 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
for (int i{4}; i > 0 && nextLine_[i] == ' '; --i) {
++trailingSpaces;
}
- bool CCommentAndSpaces{!HasTabInLabelField(nextLine_) &&
- SkipCComment(SkipWhiteSpace(nextLine_)) - nextLine_ + trailingSpaces ==
- 5};
+ const char *afterCComment{SkipCComment(SkipWhiteSpace(nextLine_))};
+ bool CCommentAndSpaces{!HasTabInLabelField(nextLine_) && afterCComment &&
+ afterCComment - nextLine_ + trailingSpaces == 5};
bool canBeNonDirectiveContinuation{
((col1 == ' ' ||
((col1 == 'D' || col1 == 'd') &&
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment.F
index 82db6f7b43fa0..1d00528804e7e 100644
--- a/flang/test/Preprocessing/fixed-c-comment.F
+++ b/flang/test/Preprocessing/fixed-c-comment.F
@@ -1,6 +1,7 @@
! RUN: %flang_fc1 -fsyntax-only %s 2>&1
! RUN: %flang -E %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
+! RUN: not %flang_fc1 -pedantic -Werror -fdebug-dump-parse-tree-no-sema \
+! RUN: -DTEST_ERRORS=1 %s 2>&1 | FileCheck %s --check-prefix=ERROR
integer :: i
@@ -59,4 +60,9 @@
! CHECK-NOT: C comment
print *, "TAB"
/* C comment after tab */
+
+! ERROR: error: Character in fixed-form label field must be a digit
+#if TEST_ERRORS
+/* Not-terminated C comment
+#endif
end
>From 67063aa210545e30628155de1149589ed341839d Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Fri, 3 Jul 2026 10:52:18 -0300
Subject: [PATCH 04/12] Fix regression and improve efficiency
---
flang/lib/Parser/prescan.cpp | 8 +++++---
flang/test/Preprocessing/fixed-c-comment.F | 5 +++++
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 4814071f4d9f9..966f91a8ea54a 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -1468,15 +1468,17 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
for (int i{4}; i > 0 && nextLine_[i] == ' '; --i) {
++trailingSpaces;
}
- const char *afterCComment{SkipCComment(SkipWhiteSpace(nextLine_))};
- bool CCommentAndSpaces{!HasTabInLabelField(nextLine_) && afterCComment &&
+ const char *afterWhiteSpace{SkipWhiteSpace(nextLine_)};
+ const char *afterCComment{
+ IsCComment(afterWhiteSpace) ? SkipCComment(afterWhiteSpace) : nullptr};
+ bool cCommentAndSpaces{afterCComment && !HasTabInLabelField(nextLine_) &&
afterCComment - nextLine_ + trailingSpaces == 5};
bool canBeNonDirectiveContinuation{
((col1 == ' ' ||
((col1 == 'D' || col1 == 'd') &&
features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
trailingSpaces == 4) ||
- CCommentAndSpaces};
+ cCommentAndSpaces};
if (InCompilerDirective() && !(InConditionalLine() && !preprocessingOnly_)) {
// !$ under -E is not continued, but deferred to later compilation
if (IsFixedFormCommentChar(col1) &&
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment.F
index 1d00528804e7e..97ad59dd54546 100644
--- a/flang/test/Preprocessing/fixed-c-comment.F
+++ b/flang/test/Preprocessing/fixed-c-comment.F
@@ -56,6 +56,11 @@
! CHECK-NOT: C comment
i = 8 /* C comment after statement */
+! CHECK: i = 9
+! CHECK-NOT: 8
+ i = 9
+* */ 88
+
! CHECK: print
! CHECK-NOT: C comment
print *, "TAB"
>From 426699b410f25b47995e2cb0c8d915b3075f804f Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 8 Jul 2026 14:29:10 -0300
Subject: [PATCH 05/12] Fix out of bounds read
---
flang/lib/Parser/prescan.cpp | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 966f91a8ea54a..f4664bf70466c 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -70,8 +70,10 @@ static inline constexpr bool IsFixedFormCommentChar(char ch) {
return ch == '!' || ch == '*' || ch == 'C' || ch == 'c';
}
-static bool HasTabInLabelField(const char *col1) {
- for (int i{0}; i < 6 && col1[i] != '\n'; ++i) {
+static bool HasTabInLabelField(const char *col1, const char *limit) {
+ std::uint64_t len{static_cast<std::uint64_t>(limit - col1)};
+ int n{len < 6 ? static_cast<int>(len) : 6};
+ for (int i{0}; i < n && col1[i] != '\n'; ++i) {
if (col1[i] == '\t') {
return true;
}
@@ -448,8 +450,9 @@ void Prescanner::LabelField(TokenSequence &token) {
// Skip C-style comments.
const char *p{SkipWhiteSpace(start)};
- int spaces{
- HasTabInLabelField(start - colOffset) ? 6 : static_cast<int>(p - start)};
+ std::uint64_t spaces{HasTabInLabelField(start - colOffset, limit_)
+ ? 6
+ : static_cast<std::uint64_t>(p - start)};
if (spaces < 6 && IsCComment(p)) {
at_ += spaces;
column_ += spaces;
@@ -1464,15 +1467,18 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
}
tabInCurrentLine_ = false;
char col1{*nextLine_};
- int trailingSpaces{0};
- for (int i{4}; i > 0 && nextLine_[i] == ' '; --i) {
- ++trailingSpaces;
- }
const char *afterWhiteSpace{SkipWhiteSpace(nextLine_)};
const char *afterCComment{
IsCComment(afterWhiteSpace) ? SkipCComment(afterWhiteSpace) : nullptr};
- bool cCommentAndSpaces{afterCComment && !HasTabInLabelField(nextLine_) &&
- afterCComment - nextLine_ + trailingSpaces == 5};
+ int trailingSpaces{0};
+ for (std::uint64_t i{afterCComment
+ ? static_cast<std::uint64_t>(afterCComment - nextLine_)
+ : 1};
+ i <= 4 && nextLine_[i] == ' '; ++i) {
+ ++trailingSpaces;
+ }
+ bool cCommentAndSpaces{
+ afterCComment && afterCComment - nextLine_ + trailingSpaces == 5};
bool canBeNonDirectiveContinuation{
((col1 == ' ' ||
((col1 == 'D' || col1 == 'd') &&
>From 900f4326dee860706847a1a5b4b871f785238c4a Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 8 Jul 2026 18:01:05 -0300
Subject: [PATCH 06/12] Avoid out of bounds reads when determining
trailingSpaces
---
flang/lib/Parser/prescan.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index f4664bf70466c..bc93292e9dce2 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -1470,11 +1470,13 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
const char *afterWhiteSpace{SkipWhiteSpace(nextLine_)};
const char *afterCComment{
IsCComment(afterWhiteSpace) ? SkipCComment(afterWhiteSpace) : nullptr};
+ std::uint64_t maxLineLength{static_cast<std::uint64_t>(limit_ - nextLine_)};
+ std::uint64_t n{maxLineLength < 5 ? maxLineLength - 1 : 4};
int trailingSpaces{0};
for (std::uint64_t i{afterCComment
? static_cast<std::uint64_t>(afterCComment - nextLine_)
: 1};
- i <= 4 && nextLine_[i] == ' '; ++i) {
+ i <= n && nextLine_[i] == ' '; ++i) {
++trailingSpaces;
}
bool cCommentAndSpaces{
>From f9937c28891a48763156dff2bfd821ebd0406af8 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Tue, 14 Jul 2026 16:25:18 -0300
Subject: [PATCH 07/12] Fix issues from last review
---
flang/lib/Parser/prescan.cpp | 36 +++++++++++++---------
flang/test/Preprocessing/fixed-c-comment.F | 13 ++++++--
2 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index bc93292e9dce2..b4d6e9bfb313a 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -456,21 +456,23 @@ void Prescanner::LabelField(TokenSequence &token) {
if (spaces < 6 && IsCComment(p)) {
at_ += spaces;
column_ += spaces;
- if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
- Say(LanguageFeature::ClassicCComments, GetCurrentProvenance(),
- "nonstandard usage: C-style comment"_port_en_US);
- }
SkipCComments();
- // Fix `column_`, which may be incorrect after multi-line comments.
- p = at_ - 1;
- while (p > start && *p != '\n') {
- --p;
- }
- if (*p == '\n') {
- column_ = at_ - p;
+ if (at_ > start + spaces) {
+ if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
+ Say(LanguageFeature::ClassicCComments, GetCurrentProvenance(),
+ "nonstandard usage: C-style comment"_port_en_US);
+ }
+ // Fix `column_`, which may be incorrect after multi-line comments.
+ p = at_ - 1;
+ while (p > start && *p != '\n') {
+ --p;
+ }
+ if (*p == '\n') {
+ column_ = at_ - p;
+ }
+ colOffset = column_ - 1;
+ start = at_;
}
- colOffset = column_ - 1;
- start = at_;
}
for (; *at_ != '\n' && column_ <= 6; ++at_) {
@@ -812,6 +814,9 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
// outside a character literal.
WarnCComment(at_);
SkipCComments();
+ if (compilingFixedForm) {
+ SkipSpaces();
+ }
}
if (!compilingFixedForm && IsSpaceOrTab(at_)) {
// Compress free-form white space into a single space character.
@@ -1479,8 +1484,9 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
i <= n && nextLine_[i] == ' '; ++i) {
++trailingSpaces;
}
- bool cCommentAndSpaces{
- afterCComment && afterCComment - nextLine_ + trailingSpaces == 5};
+ bool cCommentAndSpaces{afterCComment &&
+ afterCComment - nextLine_ + trailingSpaces == 5 &&
+ std::memchr(nextLine_, '\n', n + 1) == nullptr};
bool canBeNonDirectiveContinuation{
((col1 == ' ' ||
((col1 == 'D' || col1 == 'd') &&
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment.F
index 97ad59dd54546..f4bb91fe92fb6 100644
--- a/flang/test/Preprocessing/fixed-c-comment.F
+++ b/flang/test/Preprocessing/fixed-c-comment.F
@@ -3,7 +3,8 @@
! RUN: not %flang_fc1 -pedantic -Werror -fdebug-dump-parse-tree-no-sema \
! RUN: -DTEST_ERRORS=1 %s 2>&1 | FileCheck %s --check-prefix=ERROR
- integer :: i
+ implicit none
+ integer :: i, foobar
! CHECK-NOT: C comment
! CHECK: i = 1
@@ -61,13 +62,21 @@
i = 9
* */ 88
+! When compiling, the line below should become: foobar = 123
+ foo/* c */ bar = 123
+
! CHECK: print
! CHECK-NOT: C comment
print *, "TAB"
/* C comment after tab */
-! ERROR: error: Character in fixed-form label field must be a digit
#if TEST_ERRORS
+! ERROR: error: Character in fixed-form label field must be a digit
+ i = 90
+/*
+*/+1
+
+! ERROR: error: Character in fixed-form label field must be a digit
/* Not-terminated C comment
#endif
end
>From 8d1af78dcccf99d2d164109fd2e92eef9b6a14d6 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Tue, 21 Jul 2026 18:11:58 +0000
Subject: [PATCH 08/12] Check for not-terminated C comments in continuation
lines
---
flang/lib/Parser/prescan.cpp | 2 +-
flang/test/Preprocessing/fixed-c-comment.F | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index b4d6e9bfb313a..dd0706fba4bee 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -1557,7 +1557,7 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
if (canBeNonDirectiveContinuation) {
const char *col6{nextLine_ + 5};
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6) &&
- !IsCComment(col6)) {
+ !(IsCComment(col6) && afterCComment > afterWhiteSpace)) {
if ((*col6 == 'i' || *col6 == 'I') && IsIncludeLine(nextLine_)) {
// It's an INCLUDE line, not a continuation
} else {
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment.F
index f4bb91fe92fb6..2c0c35dad718c 100644
--- a/flang/test/Preprocessing/fixed-c-comment.F
+++ b/flang/test/Preprocessing/fixed-c-comment.F
@@ -79,4 +79,8 @@
! ERROR: error: Character in fixed-form label field must be a digit
/* Not-terminated C comment
#endif
+
+! CHECK: i = 10* 2
+ i = 10
+ /* 2
end
>From d32c12f35943d43890dca19bf3f0a84c8cc146af Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 22 Jul 2026 20:37:24 +0000
Subject: [PATCH 09/12] Fix check for not-terminated C comments in continuation
lines
---
flang/lib/Parser/prescan.cpp | 2 +-
flang/test/Preprocessing/fixed-c-comment.F | 11 ++++++++---
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index dd0706fba4bee..7247ad72751da 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -1557,7 +1557,7 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
if (canBeNonDirectiveContinuation) {
const char *col6{nextLine_ + 5};
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6) &&
- !(IsCComment(col6) && afterCComment > afterWhiteSpace)) {
+ !(IsCComment(col6) && SkipCComment(col6) > col6)) {
if ((*col6 == 'i' || *col6 == 'I') && IsIncludeLine(nextLine_)) {
// It's an INCLUDE line, not a continuation
} else {
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment.F
index 2c0c35dad718c..4ba307dd707e5 100644
--- a/flang/test/Preprocessing/fixed-c-comment.F
+++ b/flang/test/Preprocessing/fixed-c-comment.F
@@ -75,12 +75,17 @@
i = 90
/*
*/+1
-
-! ERROR: error: Character in fixed-form label field must be a digit
-/* Not-terminated C comment
#endif
+! CHECK: i = 10* 2
+ i = 10
+/**/ /* 2
! CHECK: i = 10* 2
i = 10
/* 2
+
+#if TEST_ERRORS
+! ERROR: error: Character in fixed-form label field must be a digit
+/* Not-terminated C comment
+#endif
end
>From 45982d0587c12372d8fe0c27b80c18af3a9f2e66 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 22 Jul 2026 22:04:29 +0000
Subject: [PATCH 10/12] Document possible issues with the C-style comments
extension
---
flang/docs/Extensions.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 2a0afbb0cd3c0..b1f7cc2faa27f 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -277,6 +277,20 @@ end
need not begin with a comment marker (!).
* Classic C-style `/*comments*/` are skipped, so multi-language header
files are easier to write and use.
+* Classic C-style `/*comments*/` can cause an otherwise valid Fortran program
+ to be rejected. For example:
+```fortran
+ write(*,10) n, n+1, n+2
+ 10 format(1x,i2/*(i3))
+ print *, 'tail */'
+```
+ The last two lines become `10 format(1x,i2'` after prescan. This issue can
+ be avoided by not omitting the commas around the first slash, as in:
+```fortran
+ write(*,10) n, n+1, n+2
+ 10 format(1x,i2,/,*(i3))
+ print *, 'tail */'
+```
* $ and \ edit descriptors are supported in FORMAT to suppress newline
output on user prompts.
* Tabs in format strings (not `FORMAT` statements) are allowed on output.
>From 3d1535d99ee9138ed636927b61e21c3e1e9b286e Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Fri, 4 Sep 2026 15:34:52 -0300
Subject: [PATCH 11/12] Parse C-style comments for label fields only when
preprocessing is enabled
TODO:
- Add more tests
- Update flang/docs/Extensions.md
Assisted-by: Claude Opus 5
---
flang/include/flang/Parser/options.h | 1 +
flang/lib/Frontend/FrontendAction.cpp | 7 +-
flang/lib/Parser/parsing.cpp | 1 +
flang/lib/Parser/prescan.cpp | 114 ++++++++++++------
flang/lib/Parser/prescan.h | 10 +-
...{fixed-c-comment.F => fixed-c-comment01.F} | 23 ----
flang/test/Preprocessing/fixed-c-comment02.F | 29 +++++
flang/tools/bbc/bbc.cpp | 1 +
8 files changed, 121 insertions(+), 65 deletions(-)
rename flang/test/Preprocessing/{fixed-c-comment.F => fixed-c-comment01.F} (68%)
create mode 100644 flang/test/Preprocessing/fixed-c-comment02.F
diff --git a/flang/include/flang/Parser/options.h b/flang/include/flang/Parser/options.h
index e65f253748d26..e5bb515419c3b 100644
--- a/flang/include/flang/Parser/options.h
+++ b/flang/include/flang/Parser/options.h
@@ -34,6 +34,7 @@ struct Options {
bool needProvenanceRangeToCharBlockMappings{false};
Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
bool prescanAndReformat{false}; // -E
+ bool preprocessingEnabled{false};
bool expandIncludeLinesInPreprocessedOutput{true};
bool showColors{false};
std::vector<std::string> compilerDirectiveSentinels;
diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp
index a385e639a6d67..f1e5eb2786704 100644
--- a/flang/lib/Frontend/FrontendAction.cpp
+++ b/flang/lib/Frontend/FrontendAction.cpp
@@ -83,13 +83,16 @@ bool FrontendAction::beginSourceFile(CompilerInstance &ci,
// * `-cpp/-nocpp`, or
// * the file extension (if the user didn't express any preference)
// to decide whether to include them or not.
- if ((invoc.getPreprocessorOpts().macrosFlag == PPMacrosFlag::Include) ||
+ bool preprocessingEnabled =
+ (invoc.getPreprocessorOpts().macrosFlag == PPMacrosFlag::Include) ||
(invoc.getPreprocessorOpts().showMacros) ||
(invoc.getPreprocessorOpts().macrosFlag == PPMacrosFlag::Unknown &&
- getCurrentInput().getMustBePreprocessed())) {
+ getCurrentInput().getMustBePreprocessed());
+ if (preprocessingEnabled) {
invoc.setDefaultPredefinitions();
invoc.collectMacroDefinitions();
}
+ invoc.getFortranOpts().preprocessingEnabled = preprocessingEnabled;
if (!invoc.getFortranOpts().features.IsEnabled(
Fortran::common::LanguageFeature::CUDA)) {
diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp
index 6dc38dc8cfd8d..391416c8ba25b 100644
--- a/flang/lib/Parser/parsing.cpp
+++ b/flang/lib/Parser/parsing.cpp
@@ -75,6 +75,7 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
messages_, *currentCooked_, preprocessor_, options.features};
prescanner.set_fixedForm(options.isFixedForm)
.set_fixedFormColumnLimit(options.fixedFormColumns)
+ .set_preprocessingEnabled(options.preprocessingEnabled)
.set_preprocessingOnly(options.prescanAndReformat)
.set_expandIncludeLines(!options.prescanAndReformat ||
options.expandIncludeLinesInPreprocessedOutput)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 7247ad72751da..ade5979f34a90 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -35,6 +35,7 @@ Prescanner::Prescanner(const Prescanner &that, Preprocessor &prepro,
bool isNestedInIncludeDirective)
: messages_{that.messages_}, cooked_{that.cooked_}, preprocessor_{prepro},
allSources_{that.allSources_}, features_{that.features_},
+ preprocessingEnabled_{that.preprocessingEnabled_},
preprocessingOnly_{that.preprocessingOnly_},
expandIncludeLines_{that.expandIncludeLines_},
isNestedInIncludeDirective_{isNestedInIncludeDirective},
@@ -449,29 +450,28 @@ void Prescanner::LabelField(TokenSequence &token) {
std::optional<int> badColumn;
// Skip C-style comments.
- const char *p{SkipWhiteSpace(start)};
- std::uint64_t spaces{HasTabInLabelField(start - colOffset, limit_)
- ? 6
- : static_cast<std::uint64_t>(p - start)};
- if (spaces < 6 && IsCComment(p)) {
- at_ += spaces;
- column_ += spaces;
- SkipCComments();
- if (at_ > start + spaces) {
- if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
- Say(LanguageFeature::ClassicCComments, GetCurrentProvenance(),
- "nonstandard usage: C-style comment"_port_en_US);
- }
- // Fix `column_`, which may be incorrect after multi-line comments.
- p = at_ - 1;
- while (p > start && *p != '\n') {
- --p;
- }
- if (*p == '\n') {
- column_ = at_ - p;
+ if (preprocessingEnabled_) {
+ const char *p{SkipWhiteSpace(start)};
+ std::uint64_t spaces{HasTabInLabelField(start - colOffset, limit_)
+ ? 6
+ : static_cast<std::uint64_t>(p - start)};
+ if (spaces < 6 && IsCComment(p)) {
+ at_ += spaces;
+ column_ += spaces;
+ SkipCComments(/*noError=*/false);
+ if (at_ > start + spaces) {
+ WarnCComment(p);
+ // Fix `column_`, which may be incorrect after multi-line comments.
+ p = at_ - 1;
+ while (p > start && *p != '\n') {
+ --p;
+ }
+ if (*p == '\n') {
+ column_ = at_ - p;
+ }
+ colOffset = column_ - 1;
+ start = at_;
}
- colOffset = column_ - 1;
- start = at_;
}
}
@@ -641,7 +641,7 @@ void Prescanner::NextChar() {
// fixed form, and all forms of line continuation.
bool Prescanner::SkipToNextSignificantCharacter() {
if (inPreprocessorDirective_) {
- SkipCComments();
+ SkipCComments(/*noError=*/true);
return false;
} else {
auto anyContinuationLine{false};
@@ -665,15 +665,22 @@ bool Prescanner::SkipToNextSignificantCharacter() {
}
}
-void Prescanner::SkipCComments() {
+void Prescanner::SkipCComments(bool noError) {
while (true) {
if (IsCComment(at_)) {
if (const char *after{SkipCComment(at_)}) {
UpdateSourcePositionAfterSkip(after);
} else {
- // Don't emit any messages about unclosed C-style comments, because
- // the sequence /* can appear legally in a FORMAT statement. There's
- // no ambiguity, since the sequence */ cannot appear legally.
+ // Error messages for unterminated C-style comments should be emitted
+ // only when preprocessing is enabled, since the sequence /* can
+ // appear legally in a FORMAT statement.
+ // At the moment, errors are emitted only for some code paths, such as
+ // when processing label fields, while others keep the old behavior of
+ // ignoring unterminated C-style comments.
+ // TODO Always emit an error when preprocessing is enabled.
+ if (preprocessingEnabled_ && !noError) {
+ Say(GetProvenance(at_), "unterminated C-style comment"_err_en_US);
+ }
break;
}
} else if (inPreprocessorDirective_ && at_[0] == '\\' && at_ + 2 < limit_ &&
@@ -813,7 +820,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
// Recognize and skip over classic C style /*comments*/ when
// outside a character literal.
WarnCComment(at_);
- SkipCComments();
+ SkipCComments(/*noError=*/true);
if (compilingFixedForm) {
SkipSpaces();
}
@@ -1466,15 +1473,25 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
return false;
}
-const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
+const char *Prescanner::FixedFormContinuationLine(
+ bool atNewline, const char *&cComment, const char *&unterminatedCComment) {
+ cComment = nullptr;
+ unterminatedCComment = nullptr;
if (IsAtEnd()) {
return nullptr;
}
tabInCurrentLine_ = false;
char col1{*nextLine_};
const char *afterWhiteSpace{SkipWhiteSpace(nextLine_)};
- const char *afterCComment{
- IsCComment(afterWhiteSpace) ? SkipCComment(afterWhiteSpace) : nullptr};
+ const char *afterCComment{nullptr};
+ if (preprocessingEnabled_ && IsCComment(afterWhiteSpace)) {
+ afterCComment = SkipCComment(afterWhiteSpace);
+ if (afterCComment == nullptr) {
+ unterminatedCComment = afterWhiteSpace;
+ } else {
+ cComment = afterWhiteSpace;
+ }
+ }
std::uint64_t maxLineLength{static_cast<std::uint64_t>(limit_ - nextLine_)};
std::uint64_t n{maxLineLength < 5 ? maxLineLength - 1 : 4};
int trailingSpaces{0};
@@ -1556,12 +1573,23 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
}
if (canBeNonDirectiveContinuation) {
const char *col6{nextLine_ + 5};
- if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6) &&
- !(IsCComment(col6) && SkipCComment(col6) > col6)) {
- if ((*col6 == 'i' || *col6 == 'I') && IsIncludeLine(nextLine_)) {
- // It's an INCLUDE line, not a continuation
- } else {
- return nextLine_ + 6;
+ if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
+ const char *afterCol6CComment{nullptr};
+ if (preprocessingEnabled_ && IsCComment(col6) &&
+ !unterminatedCComment) {
+ afterCol6CComment = SkipCComment(col6);
+ if (afterCol6CComment == nullptr) {
+ unterminatedCComment = col6;
+ } else if (!cComment) {
+ cComment = col6;
+ }
+ }
+ if (afterCol6CComment == nullptr) {
+ if ((*col6 == 'i' || *col6 == 'I') && IsIncludeLine(nextLine_)) {
+ // It's an INCLUDE line, not a continuation
+ } else {
+ return nextLine_ + 6;
+ }
}
}
}
@@ -1691,7 +1719,17 @@ bool Prescanner::FixedFormContinuation(bool atNewline) {
return false;
}
do {
- if (const char *cont{FixedFormContinuationLine(atNewline)}) {
+ const char *cComment;
+ const char *unterminatedCComment;
+ if (const char *cont{FixedFormContinuationLine(
+ atNewline, cComment, unterminatedCComment)}) {
+ if (cComment) {
+ WarnCComment(cComment);
+ }
+ if (unterminatedCComment) {
+ Say(GetProvenance(unterminatedCComment),
+ "unterminated C-style comment"_err_en_US);
+ }
BeginSourceLine(cont);
column_ = 7;
NextLine();
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 656b3c98b6c73..63b1f32d13081 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -48,6 +48,10 @@ class Prescanner {
Preprocessor &preprocessor() { return preprocessor_; }
common::LanguageFeatureControl &features() { return features_; }
+ Prescanner &set_preprocessingEnabled(bool yes) {
+ preprocessingEnabled_ = yes;
+ return *this;
+ }
Prescanner &set_preprocessingOnly(bool yes) {
preprocessingOnly_ = yes;
return *this;
@@ -228,7 +232,7 @@ class Prescanner {
void NextChar();
// True when input flowed to a continuation line
bool SkipToNextSignificantCharacter();
- void SkipCComments();
+ void SkipCComments(bool noError);
void WarnCComment(const char *at);
void SkipSpaces();
static const char *SkipWhiteSpace(const char *);
@@ -250,7 +254,8 @@ class Prescanner {
std::optional<std::size_t> IsIncludeLine(const char *) const;
void FortranInclude(const char *quote);
const char *IsPreprocessorDirectiveLine(const char *) const;
- const char *FixedFormContinuationLine(bool atNewline);
+ const char *FixedFormContinuationLine(
+ bool atNewline, const char *&cComment, const char *&unterminatedCComment);
const char *GetFreeFormContinuationLine(bool ampersand, const char *p);
const char *FreeFormContinuationLine(bool ampersand);
bool IsImplicitContinuation() const;
@@ -275,6 +280,7 @@ class Prescanner {
Preprocessor &preprocessor_;
AllSources &allSources_;
common::LanguageFeatureControl features_;
+ bool preprocessingEnabled_{false};
bool preprocessingOnly_{false};
bool expandIncludeLines_{true};
bool isNestedInIncludeDirective_{false};
diff --git a/flang/test/Preprocessing/fixed-c-comment.F b/flang/test/Preprocessing/fixed-c-comment01.F
similarity index 68%
rename from flang/test/Preprocessing/fixed-c-comment.F
rename to flang/test/Preprocessing/fixed-c-comment01.F
index 4ba307dd707e5..947d3a5fda42d 100644
--- a/flang/test/Preprocessing/fixed-c-comment.F
+++ b/flang/test/Preprocessing/fixed-c-comment01.F
@@ -1,20 +1,16 @@
! RUN: %flang_fc1 -fsyntax-only %s 2>&1
! RUN: %flang -E %s 2>&1 | FileCheck %s
-! RUN: not %flang_fc1 -pedantic -Werror -fdebug-dump-parse-tree-no-sema \
-! RUN: -DTEST_ERRORS=1 %s 2>&1 | FileCheck %s --check-prefix=ERROR
implicit none
integer :: i, foobar
! CHECK-NOT: C comment
! CHECK: i = 1
-! ERROR: portability: nonstandard usage: C-style comment
/* Old style C comments
*comments
*/
#define VAL 1
-! ERROR: portability: nonstandard usage: C-style comment
/* Single-line C comment */
/* Single-line C comment */
/* Single-line C comment */
@@ -69,23 +65,4 @@
! CHECK-NOT: C comment
print *, "TAB"
/* C comment after tab */
-
-#if TEST_ERRORS
-! ERROR: error: Character in fixed-form label field must be a digit
- i = 90
-/*
-*/+1
-#endif
-
-! CHECK: i = 10* 2
- i = 10
-/**/ /* 2
-! CHECK: i = 10* 2
- i = 10
- /* 2
-
-#if TEST_ERRORS
-! ERROR: error: Character in fixed-form label field must be a digit
-/* Not-terminated C comment
-#endif
end
diff --git a/flang/test/Preprocessing/fixed-c-comment02.F b/flang/test/Preprocessing/fixed-c-comment02.F
new file mode 100644
index 0000000000000..520a39bf66e64
--- /dev/null
+++ b/flang/test/Preprocessing/fixed-c-comment02.F
@@ -0,0 +1,29 @@
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Werror %s 2>&1 | FileCheck %s --check-prefix=ERROR
+
+ implicit none
+ integer :: i
+
+! ERROR: fixed-c-comment02.F:9:1: portability: nonstandard usage: C-style comment
+! ERROR: fixed-c-comment02.F:10:3: error: Character in fixed-form label field must be a digit
+ i = 11
+/*
+*/+1
+
+! ERROR: fixed-c-comment02.F:13:1: portability: nonstandard usage: C-style comment
+/* Single-line C comment */
+! ERROR: fixed-c-comment02.F:15:1: portability: nonstandard usage: C-style comment
+/* Multi-line
+ * C comment
+ */
+
+! ERROR: fixed-c-comment02.F:22:1: portability: nonstandard usage: C-style comment
+! ERROR: fixed-c-comment02.F:22:6: error: unterminated C-style comment
+ i = 21
+/**/ /* 2
+! ERROR: fixed-c-comment02.F:25:6: error: unterminated C-style comment
+ i = 22
+ /* 2
+! ERROR: fixed-c-comment02.F:29:1: error: unterminated C-style comment
+! ERROR: fixed-c-comment02.F:29:1: error: Character in fixed-form label field must be a digit
+! ERROR: fixed-c-comment02.F:29:1: portability: nonstandard usage: C-style comment
+/* Not-terminated C comment
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 50742eb106421..7d0c0f6644a0d 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -658,6 +658,7 @@ int main(int argc, char **argv) {
}
Fortran::parser::Options options;
+ options.preprocessingEnabled = true;
options.predefinitions.emplace_back("__flang__"s, "1"s);
options.predefinitions.emplace_back("__flang_major__"s,
std::string{FLANG_VERSION_MAJOR_STRING});
>From 16dd953dccdf7f7d4749d89fc53cbb1c55002a31 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Tue, 15 Sep 2026 16:43:37 -0300
Subject: [PATCH 12/12] Add more tests and update flang/docs/Extensions.md
---
flang/docs/Extensions.md | 18 +++++----------
flang/test/Preprocessing/fixed-c-comment02.F | 23 ++++++++++++++------
flang/test/Preprocessing/fixed-c-comment03.f | 10 +++++++++
3 files changed, 32 insertions(+), 19 deletions(-)
create mode 100644 flang/test/Preprocessing/fixed-c-comment03.f
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index b1f7cc2faa27f..c1b088dca7c7d 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -277,19 +277,13 @@ end
need not begin with a comment marker (!).
* Classic C-style `/*comments*/` are skipped, so multi-language header
files are easier to write and use.
-* Classic C-style `/*comments*/` can cause an otherwise valid Fortran program
- to be rejected. For example:
+* Classic C-style `/*comments*/` in fixed source form label fields are
+ skipped only when preprocessing is enabled. Otherwise, valid Fortran
+ programs could be rejected. For example:
```fortran
- write(*,10) n, n+1, n+2
- 10 format(1x,i2/*(i3))
- print *, 'tail */'
-```
- The last two lines become `10 format(1x,i2'` after prescan. This issue can
- be avoided by not omitting the commas around the first slash, as in:
-```fortran
- write(*,10) n, n+1, n+2
- 10 format(1x,i2,/,*(i3))
- print *, 'tail */'
+ x = x
+ /* 2
+ print *, x, 'tail */ text'
```
* $ and \ edit descriptors are supported in FORMAT to suppress newline
output on user prompts.
diff --git a/flang/test/Preprocessing/fixed-c-comment02.F b/flang/test/Preprocessing/fixed-c-comment02.F
index 520a39bf66e64..5805e767f3fb6 100644
--- a/flang/test/Preprocessing/fixed-c-comment02.F
+++ b/flang/test/Preprocessing/fixed-c-comment02.F
@@ -16,14 +16,23 @@
* C comment
*/
-! ERROR: fixed-c-comment02.F:22:1: portability: nonstandard usage: C-style comment
-! ERROR: fixed-c-comment02.F:22:6: error: unterminated C-style comment
+! ERROR: fixed-c-comment02.F:23:6: portability: nonstandard usage: C-style comment
+! ERROR: fixed-c-comment02.F:25:29: error: Incomplete character literal
i = 21
+ i = i
+ /* 2
+ print *, i
+ print *, 'tail */ text'
+
+! ERROR: fixed-c-comment02.F:30:1: portability: nonstandard usage: C-style comment
+! ERROR: fixed-c-comment02.F:30:6: error: unterminated C-style comment
+ i = 31
/**/ /* 2
-! ERROR: fixed-c-comment02.F:25:6: error: unterminated C-style comment
- i = 22
+! ERROR: fixed-c-comment02.F:33:6: error: unterminated C-style comment
+ i = 32
/* 2
-! ERROR: fixed-c-comment02.F:29:1: error: unterminated C-style comment
-! ERROR: fixed-c-comment02.F:29:1: error: Character in fixed-form label field must be a digit
-! ERROR: fixed-c-comment02.F:29:1: portability: nonstandard usage: C-style comment
+! ERROR: fixed-c-comment02.F:37:1: error: unterminated C-style comment
+! ERROR: fixed-c-comment02.F:37:1: error: Character in fixed-form label field must be a digit
+! ERROR: fixed-c-comment02.F:37:1: portability: nonstandard usage: C-style comment
/* Not-terminated C comment
+ end
diff --git a/flang/test/Preprocessing/fixed-c-comment03.f b/flang/test/Preprocessing/fixed-c-comment03.f
new file mode 100644
index 0000000000000..80d0c19ec264d
--- /dev/null
+++ b/flang/test/Preprocessing/fixed-c-comment03.f
@@ -0,0 +1,10 @@
+! RUN: %flang_fc1 -fsyntax-only %s 2>&1
+
+ program p
+ integer :: y, x
+ y = 3
+ x = y
+ /* 2
+ print *, x
+ print *, 'tail */ text'
+ end
More information about the flang-commits
mailing list