Skip to content

Commit cf2274b

Browse files
committed
[flang] Allow ! and // comments after some preprocessing directives
Old-style C /*comments*/ are omitted from preprocessor directive token sequences by the prescanner, but line-ending C++ and Fortran free-form comments are not since their handling might depend on the directive. Add code to skip these line-ending comments as appropriate in place of existing code that just skipped blanks. Reviewed By: sscalpone Differential Revision: https://reviews.llvm.org/D84061
1 parent 86fb2db commit cf2274b

File tree

4 files changed

+55
-9
lines changed

4 files changed

+55
-9
lines changed

flang/lib/Parser/preprocessor.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -453,10 +453,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
453453
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
454454
"# missing or invalid name"_err_en_US);
455455
} else {
456-
j = dir.SkipBlanks(j + 1);
457-
if (j != tokens) {
456+
if (dir.IsAnythingLeft(++j)) {
458457
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
459-
"#undef: excess tokens at end of directive"_err_en_US);
458+
"#undef: excess tokens at end of directive"_en_US);
460459
} else {
461460
definitions_.erase(nameToken);
462461
}
@@ -468,8 +467,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
468467
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
469468
"#%s: missing name"_err_en_US, dirName);
470469
} else {
471-
j = dir.SkipBlanks(j + 1);
472-
if (j != tokens) {
470+
if (dir.IsAnythingLeft(++j)) {
473471
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
474472
"#%s: excess tokens at end of directive"_en_US, dirName);
475473
}
@@ -489,9 +487,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
489487
dir.GetTokenProvenanceRange(dirOffset));
490488
}
491489
} else if (dirName == "else") {
492-
if (j != tokens) {
490+
if (dir.IsAnythingLeft(j)) {
493491
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
494-
"#else: excess tokens at end of directive"_err_en_US);
492+
"#else: excess tokens at end of directive"_en_US);
495493
} else if (ifStack_.empty()) {
496494
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
497495
"#else: not nested within #if, #ifdef, or #ifndef"_err_en_US);
@@ -516,9 +514,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
516514
dir.GetTokenProvenanceRange(dirOffset));
517515
}
518516
} else if (dirName == "endif") {
519-
if (j != tokens) {
517+
if (dir.IsAnythingLeft(j)) {
520518
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
521-
"#endif: excess tokens at end of directive"_err_en_US);
519+
"#endif: excess tokens at end of directive"_en_US);
522520
} else if (ifStack_.empty()) {
523521
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
524522
"#endif: no #if, #ifdef, or #ifndef"_err_en_US);

flang/lib/Parser/token-sequence.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,31 @@ std::size_t TokenSequence::SkipBlanks(std::size_t at) const {
5656
return tokens; // even if at > tokens
5757
}
5858

59+
// C-style /*comments*/ are removed from preprocessing directive
60+
// token sequences by the prescanner, but not C++ or Fortran
61+
// free-form line-ending comments (//... and !...) because
62+
// ignoring them is directive-specific.
63+
bool TokenSequence::IsAnythingLeft(std::size_t at) const {
64+
std::size_t tokens{start_.size()};
65+
for (; at < tokens; ++at) {
66+
auto tok{TokenAt(at)};
67+
const char *end{tok.end()};
68+
for (const char *p{tok.begin()}; p < end; ++p) {
69+
switch (*p) {
70+
case '/':
71+
return p + 1 >= end || p[1] != '/';
72+
case '!':
73+
return false;
74+
case ' ':
75+
break;
76+
default:
77+
return true;
78+
}
79+
}
80+
}
81+
return false;
82+
}
83+
5984
void TokenSequence::RemoveLastToken() {
6085
CHECK(!start_.empty());
6186
CHECK(nextStart_ > start_.back());

flang/lib/Parser/token-sequence.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class TokenSequence {
7171

7272
std::size_t SkipBlanks(std::size_t) const;
7373

74+
// True if anything remains in the sequence at & after the given offset
75+
// except blanks and line-ending C++ and Fortran free-form comments.
76+
bool IsAnythingLeft(std::size_t) const;
77+
7478
void PutNextTokenChar(char ch, Provenance provenance) {
7579
char_.emplace_back(ch);
7680
provenances_.Put({provenance, 1});

flang/test/Parser/pp-dir-comments.f90

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
! RUN: %f18 -funparse %s 2>&1 | FileCheck %s
2+
3+
#define pmk
4+
#ifdef pmk // comment
5+
! CHECK: t1
6+
real t1
7+
#endif // comment
8+
#undef pmk ! comment
9+
#ifndef pmk ! comment
10+
! CHECK: t2
11+
real t2
12+
#endif // comment
13+
#if 0 /* C comment */ + 0
14+
! CHECK-NOT: misinterpreted
15+
# error misinterpreted #if
16+
#else // comment
17+
! CHECK: END PROGRAM
18+
end
19+
#endif ! comment

0 commit comments

Comments
 (0)