Skip to content

Commit 544dc78

Browse files
committed
[flang] Ignore empty keyword macros before directives
Ignore any keyword macros with empty directives that might appear before a compiler directive. Fixes #126459.
1 parent fb08913 commit 544dc78

File tree

5 files changed

+48
-10
lines changed

5 files changed

+48
-10
lines changed

flang/include/flang/Parser/preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class Preprocessor {
8181
void Define(const std::string &macro, const std::string &value);
8282
void Undefine(std::string macro);
8383
bool IsNameDefined(const CharBlock &);
84+
bool IsNameDefinedEmpty(const CharBlock &);
8485
bool IsFunctionLikeDefinition(const CharBlock &);
8586
bool AnyDefinitions() const { return !definitions_.empty(); }
8687
bool InConditional() const { return !ifStack_.empty(); }

flang/lib/Parser/preprocessor.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,15 @@ bool Preprocessor::IsNameDefined(const CharBlock &token) {
842842
return definitions_.find(token) != definitions_.end();
843843
}
844844

845+
bool Preprocessor::IsNameDefinedEmpty(const CharBlock &token) {
846+
if (auto it{definitions_.find(token)}; it != definitions_.end()) {
847+
const Definition &def{it->second};
848+
return !def.isFunctionLike() && def.replacement().SizeInChars() == 0;
849+
} else {
850+
return false;
851+
}
852+
}
853+
845854
bool Preprocessor::IsFunctionLikeDefinition(const CharBlock &token) {
846855
auto it{definitions_.find(token)};
847856
return it != definitions_.end() && it->second.isFunctionLike();

flang/lib/Parser/prescan.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,8 @@ void Prescanner::Statement() {
145145
if (inFixedForm_) {
146146
CHECK(IsFixedFormCommentChar(*at_));
147147
} else {
148-
while (int n{IsSpaceOrTab(at_)}) {
149-
at_ += n, ++column_;
150-
}
151-
CHECK(*at_ == '!');
148+
at_ += line.payloadOffset;
149+
column_ += line.payloadOffset;
152150
}
153151
std::optional<int> condOffset;
154152
if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
@@ -597,6 +595,30 @@ const char *Prescanner::SkipWhiteSpace(const char *p) {
597595
return p;
598596
}
599597

598+
const char *Prescanner::SkipWhiteSpaceIncludingEmptyMacros(
599+
const char *p) const {
600+
while (true) {
601+
if (int n{IsSpaceOrTab(p)}) {
602+
p += n;
603+
} else if (preprocessor_.AnyDefinitions() && IsLegalIdentifierStart(*p)) {
604+
// Skip keyword macros with empty definitions
605+
const char *q{p + 1};
606+
while (IsLegalInIdentifier(*q)) {
607+
++q;
608+
}
609+
if (preprocessor_.IsNameDefinedEmpty(
610+
CharBlock{p, static_cast<std::size_t>(q - p)})) {
611+
p = q;
612+
} else {
613+
break;
614+
}
615+
} else {
616+
break;
617+
}
618+
}
619+
return p;
620+
}
621+
600622
const char *Prescanner::SkipWhiteSpaceAndCComments(const char *p) const {
601623
while (true) {
602624
if (int n{IsSpaceOrTab(p)}) {
@@ -1463,18 +1485,18 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
14631485
*sp = '\0';
14641486
if (const char *ss{IsCompilerDirectiveSentinel(
14651487
sentinel, static_cast<std::size_t>(sp - sentinel))}) {
1466-
std::size_t payloadOffset = p - start;
1467-
return {LineClassification{
1468-
LineClassification::Kind::CompilerDirective, payloadOffset, ss}};
1488+
return {
1489+
LineClassification{LineClassification::Kind::CompilerDirective, 0, ss}};
14691490
}
14701491
return std::nullopt;
14711492
}
14721493

14731494
std::optional<Prescanner::LineClassification>
14741495
Prescanner::IsFreeFormCompilerDirectiveLine(const char *start) const {
1475-
if (const char *p{SkipWhiteSpace(start)}; p && *p++ == '!') {
1496+
if (const char *p{SkipWhiteSpaceIncludingEmptyMacros(start)};
1497+
p && *p++ == '!') {
14761498
if (auto maybePair{IsCompilerDirectiveSentinel(p)}) {
1477-
auto offset{static_cast<std::size_t>(maybePair->second - start)};
1499+
auto offset{static_cast<std::size_t>(p - start - 1)};
14781500
return {LineClassification{LineClassification::Kind::CompilerDirective,
14791501
offset, maybePair->first}};
14801502
}
@@ -1529,7 +1551,7 @@ Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
15291551
if (int n{*p == '&' ? 1 : IsSpaceOrTab(p)}) {
15301552
if (j > 0) {
15311553
sentinel[j] = '\0';
1532-
p = SkipWhiteSpace(p + n);
1554+
p = SkipWhiteSpaceIncludingEmptyMacros(p + n);
15331555
if (*p != '!') {
15341556
if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) {
15351557
return std::make_pair(sp, p);

flang/lib/Parser/prescan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class Prescanner {
182182
void SkipCComments();
183183
void SkipSpaces();
184184
static const char *SkipWhiteSpace(const char *);
185+
const char *SkipWhiteSpaceIncludingEmptyMacros(const char *) const;
185186
const char *SkipWhiteSpaceAndCComments(const char *) const;
186187
const char *SkipCComment(const char *) const;
187188
bool NextToken(TokenSequence &);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
! RUN: %flang -E -fopenmp %s 2>&1 | FileCheck %s
2+
!CHECK: NDIR=0
3+
#define BLANKMACRO
4+
BLANKMACRO !$ NDIR=0
5+
end

0 commit comments

Comments
 (0)