diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp --- a/flang/lib/Parser/preprocessor.cpp +++ b/flang/lib/Parser/preprocessor.cpp @@ -453,10 +453,9 @@ 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); } @@ -468,8 +467,7 @@ 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); } @@ -489,9 +487,9 @@ 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); @@ -516,9 +514,9 @@ 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); diff --git a/flang/lib/Parser/token-sequence.h b/flang/lib/Parser/token-sequence.h --- a/flang/lib/Parser/token-sequence.h +++ b/flang/lib/Parser/token-sequence.h @@ -71,6 +71,10 @@ 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}); diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp --- a/flang/lib/Parser/token-sequence.cpp +++ b/flang/lib/Parser/token-sequence.cpp @@ -56,6 +56,31 @@ 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()); diff --git a/flang/test/Parser/pp-dir-comments.f90 b/flang/test/Parser/pp-dir-comments.f90 new file mode 100644 --- /dev/null +++ b/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