[flang-commits] [flang] [flang] Ignore empty keyword macros before directives (PR #130333)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Fri Mar 7 12:17:40 PST 2025
https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/130333
>From 4698f11af4865cf38444e4d9c7331f6574a6b334 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Fri, 7 Mar 2025 11:32:17 -0800
Subject: [PATCH] [flang] Ignore empty keyword macros before directives
Ignore any keyword macros with empty directives that might
appear before a compiler directive.
Fixes https://github.com/llvm/llvm-project/issues/126459.
---
flang/include/flang/Parser/preprocessor.h | 1 +
flang/lib/Parser/preprocessor.cpp | 9 +++++
flang/lib/Parser/prescan.cpp | 41 ++++++++++++++++++-----
flang/lib/Parser/prescan.h | 1 +
flang/test/Preprocessing/bug126459.F90 | 5 +++
5 files changed, 48 insertions(+), 9 deletions(-)
create mode 100644 flang/test/Preprocessing/bug126459.F90
diff --git a/flang/include/flang/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h
index f8d3346065981..86528a7e68def 100644
--- a/flang/include/flang/Parser/preprocessor.h
+++ b/flang/include/flang/Parser/preprocessor.h
@@ -81,6 +81,7 @@ class Preprocessor {
void Define(const std::string ¯o, const std::string &value);
void Undefine(std::string macro);
bool IsNameDefined(const CharBlock &);
+ bool IsNameDefinedEmpty(const CharBlock &);
bool IsFunctionLikeDefinition(const CharBlock &);
bool AnyDefinitions() const { return !definitions_.empty(); }
bool InConditional() const { return !ifStack_.empty(); }
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 6c257f57c2d57..7e6a1c2ca6977 100644
--- a/flang/lib/Parser/preprocessor.cpp
+++ b/flang/lib/Parser/preprocessor.cpp
@@ -842,6 +842,15 @@ bool Preprocessor::IsNameDefined(const CharBlock &token) {
return definitions_.find(token) != definitions_.end();
}
+bool Preprocessor::IsNameDefinedEmpty(const CharBlock &token) {
+ if (auto it{definitions_.find(token)}; it != definitions_.end()) {
+ const Definition &def{it->second};
+ return !def.isFunctionLike() && def.replacement().SizeInChars() == 0;
+ } else {
+ return false;
+ }
+}
+
bool Preprocessor::IsFunctionLikeDefinition(const CharBlock &token) {
auto it{definitions_.find(token)};
return it != definitions_.end() && it->second.isFunctionLike();
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index f479cc51871ef..b4ac82839b73f 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -145,9 +145,8 @@ void Prescanner::Statement() {
if (inFixedForm_) {
CHECK(IsFixedFormCommentChar(*at_));
} else {
- while (int n{IsSpaceOrTab(at_)}) {
- at_ += n, ++column_;
- }
+ at_ += line.payloadOffset;
+ column_ += line.payloadOffset;
CHECK(*at_ == '!');
}
std::optional<int> condOffset;
@@ -597,6 +596,30 @@ const char *Prescanner::SkipWhiteSpace(const char *p) {
return p;
}
+const char *Prescanner::SkipWhiteSpaceIncludingEmptyMacros(
+ const char *p) const {
+ while (true) {
+ if (int n{IsSpaceOrTab(p)}) {
+ p += n;
+ } else if (preprocessor_.AnyDefinitions() && IsLegalIdentifierStart(*p)) {
+ // Skip keyword macros with empty definitions
+ const char *q{p + 1};
+ while (IsLegalInIdentifier(*q)) {
+ ++q;
+ }
+ if (preprocessor_.IsNameDefinedEmpty(
+ CharBlock{p, static_cast<std::size_t>(q - p)})) {
+ p = q;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ return p;
+}
+
const char *Prescanner::SkipWhiteSpaceAndCComments(const char *p) const {
while (true) {
if (int n{IsSpaceOrTab(p)}) {
@@ -1463,18 +1486,18 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
*sp = '\0';
if (const char *ss{IsCompilerDirectiveSentinel(
sentinel, static_cast<std::size_t>(sp - sentinel))}) {
- std::size_t payloadOffset = p - start;
- return {LineClassification{
- LineClassification::Kind::CompilerDirective, payloadOffset, ss}};
+ return {
+ LineClassification{LineClassification::Kind::CompilerDirective, 0, ss}};
}
return std::nullopt;
}
std::optional<Prescanner::LineClassification>
Prescanner::IsFreeFormCompilerDirectiveLine(const char *start) const {
- if (const char *p{SkipWhiteSpace(start)}; p && *p++ == '!') {
+ if (const char *p{SkipWhiteSpaceIncludingEmptyMacros(start)};
+ p && *p++ == '!') {
if (auto maybePair{IsCompilerDirectiveSentinel(p)}) {
- auto offset{static_cast<std::size_t>(maybePair->second - start)};
+ auto offset{static_cast<std::size_t>(p - start - 1)};
return {LineClassification{LineClassification::Kind::CompilerDirective,
offset, maybePair->first}};
}
@@ -1529,7 +1552,7 @@ Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
if (int n{*p == '&' ? 1 : IsSpaceOrTab(p)}) {
if (j > 0) {
sentinel[j] = '\0';
- p = SkipWhiteSpace(p + n);
+ p = SkipWhiteSpaceIncludingEmptyMacros(p + n);
if (*p != '!') {
if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) {
return std::make_pair(sp, p);
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index e2440ad6fbc42..9cf1b389f5b19 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -182,6 +182,7 @@ class Prescanner {
void SkipCComments();
void SkipSpaces();
static const char *SkipWhiteSpace(const char *);
+ const char *SkipWhiteSpaceIncludingEmptyMacros(const char *) const;
const char *SkipWhiteSpaceAndCComments(const char *) const;
const char *SkipCComment(const char *) const;
bool NextToken(TokenSequence &);
diff --git a/flang/test/Preprocessing/bug126459.F90 b/flang/test/Preprocessing/bug126459.F90
new file mode 100644
index 0000000000000..fae8a07659f72
--- /dev/null
+++ b/flang/test/Preprocessing/bug126459.F90
@@ -0,0 +1,5 @@
+! RUN: %flang -E -fopenmp %s 2>&1 | FileCheck %s
+!CHECK: NDIR=0
+#define BLANKMACRO
+BLANKMACRO !$ NDIR=0
+end
More information about the flang-commits
mailing list