[flang-commits] [flang] [flang] Allow C style comments in continuation lines (PR #214336)

Leandro Lupori via flang-commits flang-commits at lists.llvm.org
Tue Aug 18 10:57:46 PDT 2026


https://github.com/luporl updated https://github.com/llvm/llvm-project/pull/214336

>From c6ef42313f4006efb2621b79a118dd62001e17bd Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 5 Aug 2026 17:25:35 -0300
Subject: [PATCH 1/4] [flang] Allow C style comments in continuation lines and
 directives

Fixes #129455
---
 flang/lib/Parser/prescan.cpp                  |  6 +++
 .../Parser/continuation-before-c-comment.f90  | 38 +++++++++++++++++++
 2 files changed, 44 insertions(+)
 create mode 100644 flang/test/Parser/continuation-before-c-comment.f90

diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 262954d32f266..1e0afd82c5f31 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -664,6 +664,12 @@ const char *Prescanner::SkipWhiteSpaceIncludingEmptyMacros(
   while (true) {
     if (int n{IsSpaceOrTab(p)}) {
       p += n;
+    } else if (IsCComment(p)) {
+      if (const char *after{SkipCComment(p)}) {
+        p = after;
+      } else {
+        break;
+      }
     } else if (preprocessor_.AnyDefinitions() && IsLegalIdentifierStart(*p)) {
       // Skip keyword macros with empty definitions
       const char *q{p + 1};
diff --git a/flang/test/Parser/continuation-before-c-comment.f90 b/flang/test/Parser/continuation-before-c-comment.f90
new file mode 100644
index 0000000000000..0049a363350c0
--- /dev/null
+++ b/flang/test/Parser/continuation-before-c-comment.f90
@@ -0,0 +1,38 @@
+! RUN: %flang_fc1 -fopenmp -fdebug-unparse %s 2>&1 | FileCheck %s
+! Continuation before C style comment.
+
+integer :: i
+
+! CHECK: i=1
+/* comment 1 */
+i&
+/* comment 2 */
+=1
+
+! CHECK: i=2
+  /* comment 1 */
+  i&
+  /* comment 2 */
+  =2
+
+! CHECK: i=3
+  /* comment 1 */
+  i&  
+  /* comment 2 */  
+  =3
+
+! CHECK: i=4
+  /* comment 1 */
+  i&  /* inline comment */  
+  /* comment 2 */  
+  =4
+
+! CHECK: !$OMP PARALLEL DO
+  /* comments before directives are allowed now */ !$omp parallel do
+  do i = 1, 10
+  end do
+
+! CHECK: PRINT *, "pass"
+  /* C comment */
+  print *,'pass'
+end

>From 83e2e50a8b3eb8ec93418bfb8f4f62b2719911d3 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Thu, 13 Aug 2026 17:06:23 -0300
Subject: [PATCH 2/4] Fix support for multi-line C style comments

And drop support for comments before compiler directives, to reduce
the amount of changes needed.
---
 flang/lib/Parser/prescan.cpp                  | 48 +++++++++++++------
 flang/lib/Parser/prescan.h                    |  3 +-
 .../Parser/continuation-before-c-comment.f90  | 41 ++++++++++++----
 3 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 1e0afd82c5f31..e75a221f41889 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -625,11 +625,7 @@ void Prescanner::SkipCComments() {
   while (true) {
     if (IsCComment(at_)) {
       if (const char *after{SkipCComment(at_)}) {
-        column_ += after - at_;
-        // May have skipped over one or more newlines; relocate the start of
-        // the next line.
-        nextLine_ = at_ = after;
-        NextLine();
+        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
@@ -660,11 +656,11 @@ const char *Prescanner::SkipWhiteSpace(const char *p) {
 }
 
 const char *Prescanner::SkipWhiteSpaceIncludingEmptyMacros(
-    const char *p) const {
+    const char *p, bool skipCComments) const {
   while (true) {
     if (int n{IsSpaceOrTab(p)}) {
       p += n;
-    } else if (IsCComment(p)) {
+    } else if (skipCComments && IsCComment(p)) {
       if (const char *after{SkipCComment(p)}) {
         p = after;
       } else {
@@ -719,6 +715,27 @@ const char *Prescanner::SkipCComment(const char *p) const {
   return p;
 }
 
+// When skipping over C-style comments, one or more newlines may be skipped.
+// Adjust current position, column, and next line in source.
+void Prescanner::UpdateSourcePositionAfterSkip(const char *after) {
+  if (at_ >= after) {
+    return;
+  }
+  const char *nl{after - 1};
+  while (nl > at_ && *nl != '\n') {
+    --nl;
+  }
+  if (*nl == '\n' && after >= nextLine_) {
+    tabInCurrentLine_ = false;
+    column_ = after - nl;
+    nextLine_ = nl + 1;
+    NextLine();
+  } else {
+    column_ += after - at_;
+  }
+  at_ = after;
+}
+
 bool Prescanner::NextToken(TokenSequence &tokens) {
   CHECK(at_ >= start_ && at_ < limit_);
   if (InFixedFormSource() && !preprocessingOnly_) {
@@ -1340,6 +1357,7 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
   } else {
     auto lineClass{ClassifyLine(nextLine_)};
     if (lineClass.kind == LineClassification::Kind::Comment) {
+      nextLine_ += lineClass.payloadOffset; // advance to '!' or newline
       NextLine();
       return true;
     } else if (lineClass.kind ==
@@ -1470,7 +1488,7 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
   if (p >= limit_) {
     return nullptr;
   }
-  p = SkipWhiteSpaceIncludingEmptyMacros(p);
+  p = SkipWhiteSpaceIncludingEmptyMacros(p, /*skipCComments=*/true);
   if (InCompilerDirective()) {
     if (InConditionalLine()) {
       if (preprocessingOnly_) {
@@ -1594,8 +1612,8 @@ bool Prescanner::FreeFormContinuation() {
   }
   do {
     if (const char *cont{FreeFormContinuationLine(ampersand)}) {
-      BeginSourceLine(cont);
-      NextLine();
+      UpdateSourcePositionAfterSkip(cont);
+      tabInCurrentLine_ = false;
       return true;
     }
   } while (SkipCommentLine(ampersand));
@@ -1701,7 +1719,8 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
 
 std::optional<Prescanner::LineClassification>
 Prescanner::IsFreeFormCompilerDirectiveLine(const char *start) const {
-  if (const char *p{SkipWhiteSpaceIncludingEmptyMacros(start)};
+  if (const char *p{
+          SkipWhiteSpaceIncludingEmptyMacros(start, /*skipCComments=*/false)};
       p && *p == '!') {
     if (auto lnClass{IsCompilerDirectiveSentinelAfterKeywordMacro(p + 1)}) {
       if (lnClass->kind == LineClassification::Kind::CompilerDirective) {
@@ -1934,7 +1953,7 @@ bool Prescanner::CompilerDirectiveContinuation(
   if (nextContinuation) {
     // What follows is !DIR$ & xxx; skip over the & so that it
     // doesn't cause a spurious continuation.
-    at_ = nextContinuation;
+    UpdateSourcePositionAfterSkip(nextContinuation);
   } else {
     // What follows looks like a source line before macro expansion,
     // but might become a directive continuation afterwards.
@@ -1990,10 +2009,9 @@ bool Prescanner::SourceLineContinuation(TokenSequence &tokens) {
       NextLine();
       return true;
     } else if (const char *nextContinuation{FreeFormContinuationLine(true)}) {
-      BeginSourceLine(nextLine_);
-      NextLine();
+      UpdateSourcePositionAfterSkip(nextContinuation);
+      tabInCurrentLine_ = false;
       TokenSequence followingTokens;
-      at_ = nextContinuation;
       while (NextToken(followingTokens)) {
       }
       if (auto followingPrepro{
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 8f4f390d4ea37..30ff8bf7c7811 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -223,9 +223,10 @@ class Prescanner {
   void SkipCComments();
   void SkipSpaces();
   static const char *SkipWhiteSpace(const char *);
-  const char *SkipWhiteSpaceIncludingEmptyMacros(const char *) const;
+  const char *SkipWhiteSpaceIncludingEmptyMacros(const char *, bool) const;
   const char *SkipWhiteSpaceAndCComments(const char *) const;
   const char *SkipCComment(const char *) const;
+  void UpdateSourcePositionAfterSkip(const char *);
   bool NextToken(TokenSequence &);
   bool HandleExponent(TokenSequence &);
   bool HandleKindSuffix(TokenSequence &);
diff --git a/flang/test/Parser/continuation-before-c-comment.f90 b/flang/test/Parser/continuation-before-c-comment.f90
index 0049a363350c0..33b2291c4d280 100644
--- a/flang/test/Parser/continuation-before-c-comment.f90
+++ b/flang/test/Parser/continuation-before-c-comment.f90
@@ -3,36 +3,59 @@
 
 integer :: i
 
+! Single line comment.
 ! CHECK: i=1
 /* comment 1 */
 i&
 /* comment 2 */
 =1
-
 ! CHECK: i=2
   /* comment 1 */
   i&
   /* comment 2 */
   =2
-
 ! CHECK: i=3
   /* comment 1 */
   i&  
   /* comment 2 */  
   =3
-
 ! CHECK: i=4
   /* comment 1 */
   i&  /* inline comment */  
   /* comment 2 */  
   =4
 
-! CHECK: !$OMP PARALLEL DO
-  /* comments before directives are allowed now */ !$omp parallel do
-  do i = 1, 10
-  end do
+! Multi-line comment.
+! CHECK: i=5
+i&
+/* c
+*/ = 5
+
+! Compiler directive.
+! CHECK: !$OMP PARALLEL
+! CHECK: !$OMP END PARALLEL
+!$omp para&
+/* comment */
+!$omp llel
+!$omp end parallel
+! CHECK: !$OMP PARALLEL
+! CHECK: !$OMP END PARALLEL
+!$omp para&
+/* multi
+ * line */
+!$omp llel
+!$omp end parallel
 
+! Source line continuation after macro expansion.
+! CHECK: i=12
+! CHECK: i=14
 ! CHECK: PRINT *, "pass"
-  /* C comment */
-  print *,'pass'
+#define CONT &
+i = 6 CONT
+/* comment */
++ 6
+i = 7 CONT
+/* multi
+ * line */ + 7
+print *,'pass'
 end

>From f2f099ae03d0b8991e305dfdd05e316577008642 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Thu, 13 Aug 2026 18:47:22 -0300
Subject: [PATCH 3/4] Don't clear tabInCurrentLine_ in
 UpdateSourcePositionAfterSkip

---
 flang/lib/Parser/prescan.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index e75a221f41889..edbce401d74fc 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -726,7 +726,6 @@ void Prescanner::UpdateSourcePositionAfterSkip(const char *after) {
     --nl;
   }
   if (*nl == '\n' && after >= nextLine_) {
-    tabInCurrentLine_ = false;
     column_ = after - nl;
     nextLine_ = nl + 1;
     NextLine();

>From 8af242b7fd7d67c02a8dfe62b38be1198f040857 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Mon, 17 Aug 2026 16:15:17 -0300
Subject: [PATCH 4/4] Warn when C-style comments are used in continuation lines

---
 flang/lib/Parser/prescan.cpp                  | 48 ++++++++++++++-----
 flang/lib/Parser/prescan.h                    |  5 +-
 ...90 => continuation-before-c-comment01.f90} |  0
 .../continuation-before-c-comment02.f90       | 15 ++++++
 4 files changed, 54 insertions(+), 14 deletions(-)
 rename flang/test/Parser/{continuation-before-c-comment.f90 => continuation-before-c-comment01.f90} (100%)
 create mode 100644 flang/test/Parser/continuation-before-c-comment02.f90

diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index edbce401d74fc..1cdc42f463457 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -641,6 +641,13 @@ void Prescanner::SkipCComments() {
   }
 }
 
+void Prescanner::WarnCComment(const char *at) {
+  if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
+    Say(LanguageFeature::ClassicCComments, GetProvenance(at),
+        "nonstandard usage: C-style comment"_port_en_US);
+  }
+}
+
 void Prescanner::SkipSpaces() {
   while (IsSpaceOrTab(at_)) {
     NextChar();
@@ -656,12 +663,16 @@ const char *Prescanner::SkipWhiteSpace(const char *p) {
 }
 
 const char *Prescanner::SkipWhiteSpaceIncludingEmptyMacros(
-    const char *p, bool skipCComments) const {
+    const char *p, const char **cComment) const {
+  const char *firstCComment{nullptr};
   while (true) {
     if (int n{IsSpaceOrTab(p)}) {
       p += n;
-    } else if (skipCComments && IsCComment(p)) {
+    } else if (cComment && IsCComment(p)) {
       if (const char *after{SkipCComment(p)}) {
+        if (!firstCComment) {
+          firstCComment = p;
+        }
         p = after;
       } else {
         break;
@@ -682,6 +693,9 @@ const char *Prescanner::SkipWhiteSpaceIncludingEmptyMacros(
       break;
     }
   }
+  if (cComment) {
+    *cComment = firstCComment;
+  }
   return p;
 }
 
@@ -743,10 +757,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
     if (*at_ == '/' && IsCComment(at_)) {
       // Recognize and skip over classic C style /*comments*/ when
       // outside a character literal.
-      if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
-        Say(LanguageFeature::ClassicCComments, GetCurrentProvenance(),
-            "nonstandard usage: C-style comment"_port_en_US);
-      }
+      WarnCComment(at_);
       SkipCComments();
     }
     if (IsSpaceOrTab(at_)) {
@@ -1481,13 +1492,9 @@ constexpr bool IsDirective(const char *match, const char *dir) {
   return true;
 }
 
-const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
+const char *Prescanner::GetFreeFormContinuationLine(
+    bool ampersand, const char *p) {
   const char *lineStart{nextLine_};
-  const char *p{lineStart};
-  if (p >= limit_) {
-    return nullptr;
-  }
-  p = SkipWhiteSpaceIncludingEmptyMacros(p, /*skipCComments=*/true);
   if (InCompilerDirective()) {
     if (InConditionalLine()) {
       if (preprocessingOnly_) {
@@ -1573,6 +1580,21 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
   }
 }
 
+const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
+  const char *lineStart{nextLine_};
+  const char *p{lineStart};
+  if (p >= limit_) {
+    return nullptr;
+  }
+  const char *cComment;
+  p = SkipWhiteSpaceIncludingEmptyMacros(lineStart, &cComment);
+  p = GetFreeFormContinuationLine(ampersand, p);
+  if (p && cComment) {
+    WarnCComment(cComment);
+  }
+  return p;
+}
+
 bool Prescanner::FixedFormContinuation(bool atNewline) {
   // N.B. We accept '&' as a continuation indicator in fixed form, too,
   // but not in a character literal.
@@ -1719,7 +1741,7 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
 std::optional<Prescanner::LineClassification>
 Prescanner::IsFreeFormCompilerDirectiveLine(const char *start) const {
   if (const char *p{
-          SkipWhiteSpaceIncludingEmptyMacros(start, /*skipCComments=*/false)};
+          SkipWhiteSpaceIncludingEmptyMacros(start, /*cComment=*/nullptr)};
       p && *p == '!') {
     if (auto lnClass{IsCompilerDirectiveSentinelAfterKeywordMacro(p + 1)}) {
       if (lnClass->kind == LineClassification::Kind::CompilerDirective) {
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 30ff8bf7c7811..516f8962705b9 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -221,9 +221,11 @@ class Prescanner {
   // True when input flowed to a continuation line
   bool SkipToNextSignificantCharacter();
   void SkipCComments();
+  void WarnCComment(const char *at);
   void SkipSpaces();
   static const char *SkipWhiteSpace(const char *);
-  const char *SkipWhiteSpaceIncludingEmptyMacros(const char *, bool) const;
+  const char *SkipWhiteSpaceIncludingEmptyMacros(
+      const char *, const char **) const;
   const char *SkipWhiteSpaceAndCComments(const char *) const;
   const char *SkipCComment(const char *) const;
   void UpdateSourcePositionAfterSkip(const char *);
@@ -241,6 +243,7 @@ class Prescanner {
   void FortranInclude(const char *quote);
   const char *IsPreprocessorDirectiveLine(const char *) const;
   const char *FixedFormContinuationLine(bool atNewline);
+  const char *GetFreeFormContinuationLine(bool ampersand, const char *p);
   const char *FreeFormContinuationLine(bool ampersand);
   bool IsImplicitContinuation() const;
   bool FixedFormContinuation(bool atNewline);
diff --git a/flang/test/Parser/continuation-before-c-comment.f90 b/flang/test/Parser/continuation-before-c-comment01.f90
similarity index 100%
rename from flang/test/Parser/continuation-before-c-comment.f90
rename to flang/test/Parser/continuation-before-c-comment01.f90
diff --git a/flang/test/Parser/continuation-before-c-comment02.f90 b/flang/test/Parser/continuation-before-c-comment02.f90
new file mode 100644
index 0000000000000..6f5e867ef6011
--- /dev/null
+++ b/flang/test/Parser/continuation-before-c-comment02.f90
@@ -0,0 +1,15 @@
+! RUN: not %flang_fc1 -fopenmp -pedantic -Werror -fdebug-unparse %s 2>&1 | FileCheck %s --check-prefix=ERROR
+! Continuation before C style comment.
+
+integer :: i
+i&
+! ERROR: portability: nonstandard usage: C-style comment
+/* c */ = &
+! ERROR: portability: nonstandard usage: C-style comment
+/* d */ 7
+if (i /= 7) then
+  print *, 'error', i
+else
+  print *, 'pass'
+end if
+end



More information about the flang-commits mailing list