Skip to content

Commit

Permalink
[flang] Allow ! and // comments after some preprocessing directives
Browse files Browse the repository at this point in the history
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
  • Loading branch information
klausler committed Jul 17, 2020
1 parent 86fb2db commit cf2274b
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 9 deletions.
16 changes: 7 additions & 9 deletions flang/lib/Parser/preprocessor.cpp
Expand Up @@ -453,10 +453,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"# missing or invalid name"_err_en_US);
} else {
j = dir.SkipBlanks(j + 1);
if (j != tokens) {
if (dir.IsAnythingLeft(++j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
"#undef: excess tokens at end of directive"_err_en_US);
"#undef: excess tokens at end of directive"_en_US);
} else {
definitions_.erase(nameToken);
}
Expand All @@ -468,8 +467,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"#%s: missing name"_err_en_US, dirName);
} else {
j = dir.SkipBlanks(j + 1);
if (j != tokens) {
if (dir.IsAnythingLeft(++j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
"#%s: excess tokens at end of directive"_en_US, dirName);
}
Expand All @@ -489,9 +487,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetTokenProvenanceRange(dirOffset));
}
} else if (dirName == "else") {
if (j != tokens) {
if (dir.IsAnythingLeft(j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
"#else: excess tokens at end of directive"_err_en_US);
"#else: excess tokens at end of directive"_en_US);
} else if (ifStack_.empty()) {
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
"#else: not nested within #if, #ifdef, or #ifndef"_err_en_US);
Expand All @@ -516,9 +514,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetTokenProvenanceRange(dirOffset));
}
} else if (dirName == "endif") {
if (j != tokens) {
if (dir.IsAnythingLeft(j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
"#endif: excess tokens at end of directive"_err_en_US);
"#endif: excess tokens at end of directive"_en_US);
} else if (ifStack_.empty()) {
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
"#endif: no #if, #ifdef, or #ifndef"_err_en_US);
Expand Down
25 changes: 25 additions & 0 deletions flang/lib/Parser/token-sequence.cpp
Expand Up @@ -56,6 +56,31 @@ std::size_t TokenSequence::SkipBlanks(std::size_t at) const {
return tokens; // even if at > tokens
}

// C-style /*comments*/ are removed from preprocessing directive
// token sequences by the prescanner, but not C++ or Fortran
// free-form line-ending comments (//... and !...) because
// ignoring them is directive-specific.
bool TokenSequence::IsAnythingLeft(std::size_t at) const {
std::size_t tokens{start_.size()};
for (; at < tokens; ++at) {
auto tok{TokenAt(at)};
const char *end{tok.end()};
for (const char *p{tok.begin()}; p < end; ++p) {
switch (*p) {
case '/':
return p + 1 >= end || p[1] != '/';
case '!':
return false;
case ' ':
break;
default:
return true;
}
}
}
return false;
}

void TokenSequence::RemoveLastToken() {
CHECK(!start_.empty());
CHECK(nextStart_ > start_.back());
Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Parser/token-sequence.h
Expand Up @@ -71,6 +71,10 @@ class TokenSequence {

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

// True if anything remains in the sequence at & after the given offset
// except blanks and line-ending C++ and Fortran free-form comments.
bool IsAnythingLeft(std::size_t) const;

void PutNextTokenChar(char ch, Provenance provenance) {
char_.emplace_back(ch);
provenances_.Put({provenance, 1});
Expand Down
19 changes: 19 additions & 0 deletions flang/test/Parser/pp-dir-comments.f90
@@ -0,0 +1,19 @@
! RUN: %f18 -funparse %s 2>&1 | FileCheck %s

#define pmk
#ifdef pmk // comment
! CHECK: t1
real t1
#endif // comment
#undef pmk ! comment
#ifndef pmk ! comment
! CHECK: t2
real t2
#endif // comment
#if 0 /* C comment */ + 0
! CHECK-NOT: misinterpreted
# error misinterpreted #if
#else // comment
! CHECK: END PROGRAM
end
#endif ! comment

0 comments on commit cf2274b

Please sign in to comment.