diff --git a/flang/lib/parser/basic-parsers.h b/flang/lib/parser/basic-parsers.h index b7b1f4ddecdd..46e78099f277 100644 --- a/flang/lib/parser/basic-parsers.h +++ b/flang/lib/parser/basic-parsers.h @@ -29,7 +29,7 @@ namespace Fortran { namespace parser { -// fail("..."_en_US) returns a parser that never succeeds. It reports an +// fail("..."_err_en_US) returns a parser that never succeeds. It reports an // error message at the current position. The result type is unused, // but might have to be specified at the point of call for satisfy // the type checker. The state remains valid. @@ -39,7 +39,7 @@ public: constexpr FailParser(const FailParser &) = default; constexpr explicit FailParser(MessageFixedText t) : text_{t} {} std::optional Parse(ParseState *state) const { - state->PutMessage(text_); + state->Say(text_); return {}; } @@ -1188,7 +1188,7 @@ constexpr struct NextCh { constexpr NextCh() {} std::optional Parse(ParseState *state) const { if (state->IsAtEnd()) { - state->PutMessage("end of file"_en_US); + state->Say("end of file"_err_en_US); return {}; } const char *at{state->GetLocation()}; @@ -1214,7 +1214,7 @@ public: if (result.has_value()) { state->set_anyConformanceViolation(); if (state->warnOnNonstandardUsage()) { - state->PutMessage(at, "nonstandard usage"_en_US); + state->Say(at, "nonstandard usage"_en_US); } } return result; @@ -1245,7 +1245,7 @@ public: if (result) { state->set_anyConformanceViolation(); if (state->warnOnDeprecatedUsage()) { - state->PutMessage(at, "deprecated usage"_en_US); + state->Say(at, "deprecated usage"_en_US); } } return result; diff --git a/flang/lib/parser/characters.h b/flang/lib/parser/characters.h index b0985d813a15..472581112192 100644 --- a/flang/lib/parser/characters.h +++ b/flang/lib/parser/characters.h @@ -14,7 +14,7 @@ namespace parser { enum class Encoding { UTF8, EUC_JP }; -static inline constexpr bool IsUpperCaseLetter(char ch) { +inline constexpr bool IsUpperCaseLetter(char ch) { if constexpr ('A' == static_cast(0xc1)) { // EBCDIC return (ch >= 'A' && ch <= 'I') || (ch >= 'J' && ch <= 'R') || @@ -24,7 +24,7 @@ static inline constexpr bool IsUpperCaseLetter(char ch) { } } -static inline constexpr bool IsLowerCaseLetter(char ch) { +inline constexpr bool IsLowerCaseLetter(char ch) { if constexpr ('a' == static_cast(0x81)) { // EBCDIC return (ch >= 'a' && ch <= 'i') || (ch >= 'j' && ch <= 'r') || @@ -34,40 +34,36 @@ static inline constexpr bool IsLowerCaseLetter(char ch) { } } -static inline constexpr bool IsLetter(char ch) { +inline constexpr bool IsLetter(char ch) { return IsUpperCaseLetter(ch) || IsLowerCaseLetter(ch); } -static inline constexpr bool IsDecimalDigit(char ch) { - return ch >= '0' && ch <= '9'; -} +inline constexpr bool IsDecimalDigit(char ch) { return ch >= '0' && ch <= '9'; } -static inline constexpr bool IsHexadecimalDigit(char ch) { +inline constexpr bool IsHexadecimalDigit(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'); } -static inline constexpr bool IsOctalDigit(char ch) { - return ch >= '0' && ch <= '7'; -} +inline constexpr bool IsOctalDigit(char ch) { return ch >= '0' && ch <= '7'; } -static inline constexpr bool IsLegalIdentifierStart(char ch) { +inline constexpr bool IsLegalIdentifierStart(char ch) { return IsLetter(ch) || ch == '_' || ch == '@' || ch == '$'; } -static inline constexpr bool IsLegalInIdentifier(char ch) { +inline constexpr bool IsLegalInIdentifier(char ch) { return IsLegalIdentifierStart(ch) || IsDecimalDigit(ch); } -static inline constexpr char ToLowerCaseLetter(char ch) { +inline constexpr char ToLowerCaseLetter(char ch) { return IsUpperCaseLetter(ch) ? ch - 'A' + 'a' : ch; } -static inline constexpr char ToLowerCaseLetter(char &&ch) { +inline constexpr char ToLowerCaseLetter(char &&ch) { return IsUpperCaseLetter(ch) ? ch - 'A' + 'a' : ch; } -static inline std::string ToLowerCaseLetters(const std::string &str) { +inline std::string ToLowerCaseLetters(const std::string &str) { std::string lowered{str}; for (char &ch : lowered) { ch = ToLowerCaseLetter(ch); @@ -75,11 +71,11 @@ static inline std::string ToLowerCaseLetters(const std::string &str) { return lowered; } -static inline constexpr char ToUpperCaseLetter(char ch) { +inline constexpr char ToUpperCaseLetter(char ch) { return IsLowerCaseLetter(ch) ? ch - 'a' + 'A' : ch; } -static inline constexpr char ToUpperCaseLetter(char &&ch) { +inline constexpr char ToUpperCaseLetter(char &&ch) { return IsLowerCaseLetter(ch) ? ch - 'a' + 'A' : ch; } @@ -91,19 +87,19 @@ static inline std::string ToUpperCaseLetters(const std::string &str) { return raised; } -static inline constexpr bool IsSameApartFromCase(char x, char y) { +inline constexpr bool IsSameApartFromCase(char x, char y) { return ToLowerCaseLetter(x) == ToLowerCaseLetter(y); } -static inline constexpr char DecimalDigitValue(char ch) { return ch - '0'; } +inline constexpr char DecimalDigitValue(char ch) { return ch - '0'; } -static inline constexpr char HexadecimalDigitValue(char ch) { +inline constexpr char HexadecimalDigitValue(char ch) { return IsUpperCaseLetter(ch) ? ch - 'A' + 10 : IsLowerCaseLetter(ch) ? ch - 'a' + 10 : DecimalDigitValue(ch); } -static constexpr std::optional BackslashEscapeValue(char ch) { +constexpr std::optional BackslashEscapeValue(char ch) { switch (ch) { // case 'a': return {'\a'}; pgf90 doesn't know about \a case 'b': return {'\b'}; @@ -119,7 +115,7 @@ static constexpr std::optional BackslashEscapeValue(char ch) { } } -static constexpr std::optional BackslashEscapeChar(char ch) { +constexpr std::optional BackslashEscapeChar(char ch) { switch (ch) { // case '\a': return {'a'}; pgf90 doesn't know about \a case '\b': return {'b'}; diff --git a/flang/lib/parser/debug-parser.h b/flang/lib/parser/debug-parser.h index 0ff96c4b3042..4f3d67500d1f 100644 --- a/flang/lib/parser/debug-parser.h +++ b/flang/lib/parser/debug-parser.h @@ -27,8 +27,8 @@ public: context->Emit(std::cout, cooked); } Provenance p{cooked.GetProvenance(state->GetLocation()).start()}; - cooked.allSources().Identify(std::cout, p, ""); - std::cout << " parser debug: " << std::string{str_, length_} << '\n'; + cooked.allSources().Identify(std::cout, p, "", true); + std::cout << " parser debug: " << std::string{str_, length_} << "\n\n"; return {Success{}}; } diff --git a/flang/lib/parser/message.cc b/flang/lib/parser/message.cc index cd2546d0633a..54bc16d25d4d 100644 --- a/flang/lib/parser/message.cc +++ b/flang/lib/parser/message.cc @@ -18,7 +18,8 @@ std::string MessageFixedText::ToString() const { return std::string{str_, /*not in std::*/ strnlen(str_, bytes_)}; } -MessageFormattedText::MessageFormattedText(MessageFixedText text, ...) { +MessageFormattedText::MessageFormattedText(MessageFixedText text, ...) + : isFatal_{text.isFatal()} { const char *p{text.str()}; std::string asString; if (p[text.size()] != '\0') { @@ -59,13 +60,16 @@ Provenance Message::Emit( cooked.allSources().Identify(o, provenance, "", echoSourceLine); } o << " "; + if (isFatal_) { + o << "ERROR: "; + } if (string_.empty()) { if (isExpectedText_) { std::string goal{text_.ToString()}; if (goal == "\n") { - o << "expected end of line"_en_US; + o << "expected end of line"_err_en_US; } else { - o << MessageFormattedText("expected '%s'"_en_US, goal.data()) + o << MessageFormattedText("expected '%s'"_err_en_US, goal.data()) .MoveString(); } } else { @@ -90,5 +94,14 @@ void Messages::Emit( msg.Emit(o, cooked_, echoSourceLines); } } + +bool Messages::AnyFatalError() const { + for (const auto &msg : messages_) { + if (msg.isFatal()) { + return true; + } + } + return false; +} } // namespace parser } // namespace Fortran diff --git a/flang/lib/parser/message.h b/flang/lib/parser/message.h index b140dba93e66..583507c3a65d 100644 --- a/flang/lib/parser/message.h +++ b/flang/lib/parser/message.h @@ -16,12 +16,14 @@ namespace Fortran { namespace parser { -// Use "..."_en_US literals to define the static text of a message. +// Use "..."_err_en_US and "..."_en_US literals to define the static +// text and fatality of a message. class MessageFixedText { public: MessageFixedText() {} - constexpr MessageFixedText(const char str[], std::size_t n) - : str_{str}, bytes_{n} {} + constexpr MessageFixedText( + const char str[], std::size_t n, bool isFatal = false) + : str_{str}, bytes_{n}, isFatal_{isFatal} {} constexpr MessageFixedText(const MessageFixedText &) = default; MessageFixedText(MessageFixedText &&) = default; constexpr MessageFixedText &operator=(const MessageFixedText &) = default; @@ -30,16 +32,23 @@ public: const char *str() const { return str_; } std::size_t size() const { return bytes_; } bool empty() const { return bytes_ == 0; } + bool isFatal() const { return isFatal_; } std::string ToString() const; private: const char *str_{nullptr}; std::size_t bytes_{0}; + bool isFatal_{false}; }; constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) { - return MessageFixedText{str, n}; + return MessageFixedText{str, n, false /* not fatal */}; +} + +constexpr MessageFixedText operator""_err_en_US( + const char str[], std::size_t n) { + return MessageFixedText{str, n, true /* fatal */}; } std::ostream &operator<<(std::ostream &, const MessageFixedText &); @@ -48,12 +57,15 @@ class MessageFormattedText { public: MessageFormattedText(MessageFixedText, ...); std::string MoveString() { return std::move(string_); } + bool isFatal() const { return isFatal_; } private: std::string string_; + bool isFatal_{false}; }; -// Represents a formatted rendition of "expected '%s'"_en_US on a constant text. +// Represents a formatted rendition of "expected '%s'"_err_en_US +// on a constant text. class MessageExpectedText { public: MessageExpectedText(const char *s, std::size_t n) : str_{s}, bytes_{n} {} @@ -78,20 +90,23 @@ public: Message &operator=(Message &&that) = default; Message(Provenance p, MessageFixedText t, MessageContext c = nullptr) - : provenance_{p}, text_{t}, context_{c} {} + : provenance_{p}, text_{t}, context_{c}, isFatal_{t.isFatal()} {} Message(Provenance p, MessageFormattedText &&s, MessageContext c = nullptr) - : provenance_{p}, string_{s.MoveString()}, context_{c} {} + : provenance_{p}, string_{s.MoveString()}, context_{c}, isFatal_{ + s.isFatal()} {} Message(Provenance p, MessageExpectedText t, MessageContext c = nullptr) : provenance_{p}, text_{t.AsMessageFixedText()}, - isExpectedText_{true}, context_{c} {} + isExpectedText_{true}, context_{c}, isFatal_{true} {} Message(const char *csl, MessageFixedText t, MessageContext c = nullptr) - : cookedSourceLocation_{csl}, text_{t}, context_{c} {} + : cookedSourceLocation_{csl}, text_{t}, context_{c}, isFatal_{t.isFatal()} { + } Message(const char *csl, MessageFormattedText &&s, MessageContext c = nullptr) - : cookedSourceLocation_{csl}, string_{s.MoveString()}, context_{c} {} + : cookedSourceLocation_{csl}, string_{s.MoveString()}, context_{c}, + isFatal_{s.isFatal()} {} Message(const char *csl, MessageExpectedText t, MessageContext c = nullptr) : cookedSourceLocation_{csl}, text_{t.AsMessageFixedText()}, - isExpectedText_{true}, context_{c} {} + isExpectedText_{true}, context_{c}, isFatal_{true} {} bool operator<(const Message &that) const { if (cookedSourceLocation_ != nullptr) { @@ -106,6 +121,7 @@ public: Provenance provenance() const { return provenance_; } const char *cookedSourceLocation() const { return cookedSourceLocation_; } MessageContext context() const { return context_; } + bool isFatal() const { return isFatal_; } Provenance Emit( std::ostream &, const CookedSource &, bool echoSourceLine = true) const; @@ -114,9 +130,10 @@ private: Provenance provenance_; const char *cookedSourceLocation_{nullptr}; MessageFixedText text_; - bool isExpectedText_{false}; // implies "expected '%s'"_en_US + bool isExpectedText_{false}; // implies "expected '%s'"_err_en_US std::string string_; MessageContext context_; + bool isFatal_{false}; }; class Messages { @@ -183,6 +200,8 @@ public: void Emit(std::ostream &, const char *prefix = nullptr, bool echoSourceLines = true) const; + bool AnyFatalError() const; + private: const CookedSource &cooked_; list_type messages_; diff --git a/flang/lib/parser/parse-state.h b/flang/lib/parser/parse-state.h index c5e6625f7501..2ff16bda4c67 100644 --- a/flang/lib/parser/parse-state.h +++ b/flang/lib/parser/parse-state.h @@ -118,21 +118,17 @@ public: } } - Message &PutMessage(MessageFixedText t) { return PutMessage(p_, t); } - Message &PutMessage(MessageFormattedText &&t) { - return PutMessage(p_, std::move(t)); - } - Message &PutMessage(MessageExpectedText &&t) { - return PutMessage(p_, std::move(t)); - } + Message &Say(MessageFixedText t) { return Say(p_, t); } + Message &Say(MessageFormattedText &&t) { return Say(p_, std::move(t)); } + Message &Say(MessageExpectedText &&t) { return Say(p_, std::move(t)); } - Message &PutMessage(const char *at, MessageFixedText t) { + Message &Say(const char *at, MessageFixedText t) { return messages_.Put(Message{at, t, context_}); } - Message &PutMessage(const char *at, MessageFormattedText &&t) { + Message &Say(const char *at, MessageFormattedText &&t) { return messages_.Put(Message{at, std::move(t), context_}); } - Message &PutMessage(const char *at, MessageExpectedText &&t) { + Message &Say(const char *at, MessageExpectedText &&t) { return messages_.Put(Message{at, std::move(t), context_}); } diff --git a/flang/lib/parser/parsing.cc b/flang/lib/parser/parsing.cc index 8e8a8592a508..71ff71f5bc9f 100644 --- a/flang/lib/parser/parsing.cc +++ b/flang/lib/parser/parsing.cc @@ -10,23 +10,21 @@ namespace Fortran { namespace parser { -bool Parsing::Prescan(const std::string &path, Options options) { +void Parsing::Prescan(const std::string &path, Options options) { options_ = options; std::stringstream fileError; const auto *sourceFile = allSources_.Open(path, &fileError); if (sourceFile == nullptr) { ProvenanceRange range{allSources_.AddCompilerInsertion(path)}; - MessageFormattedText msg("%s"_en_US, fileError.str().data()); + MessageFormattedText msg("%s"_err_en_US, fileError.str().data()); messages_.Put(Message(range.start(), std::move(msg))); - anyFatalError_ = true; - return false; + return; } if (sourceFile->bytes() == 0) { ProvenanceRange range{allSources_.AddCompilerInsertion(path)}; - messages_.Put(Message{range.start(), "file is empty"_en_US}); - anyFatalError_ = true; - return false; + messages_.Put(Message{range.start(), "file is empty"_err_en_US}); + return; } for (const auto &path : options.searchDirectories) { @@ -51,19 +49,11 @@ bool Parsing::Prescan(const std::string &path, Options options) { .AddCompilerDirectiveSentinel("dir$"); ProvenanceRange range{ allSources_.AddIncludedFile(*sourceFile, ProvenanceRange{})}; - anyFatalError_ = !prescanner.Prescan(range); - if (anyFatalError_) { - return false; - } - + prescanner.Prescan(range); cooked_.Marshal(); - return true; } void Parsing::DumpCookedChars(std::ostream &out) const { - if (anyFatalError_) { - return; - } UserState userState; ParseState parseState{cooked_}; parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState); @@ -74,10 +64,7 @@ void Parsing::DumpCookedChars(std::ostream &out) const { void Parsing::DumpProvenance(std::ostream &out) const { cooked_.Dump(out); } -bool Parsing::Parse() { - if (anyFatalError_) { - return false; - } +void Parsing::Parse() { UserState userState; ParseState parseState{cooked_}; parseState.set_inFixedForm(options_.isFixedForm) @@ -86,11 +73,34 @@ bool Parsing::Parse() { .set_warnOnDeprecatedUsage(options_.isStrictlyStandard) .set_userState(&userState); parseTree_ = program.Parse(&parseState); - anyFatalError_ = parseState.anyErrorRecovery(); + CHECK( + !parseState.anyErrorRecovery() || parseState.messages()->AnyFatalError()); consumedWholeFile_ = parseState.IsAtEnd(); finalRestingPlace_ = parseState.GetLocation(); messages_.Annex(parseState.messages()); - return parseTree_.has_value() && !anyFatalError_; +} + +std::optional Parsing::ForTesting( + std::string path, std::ostream &err) { + Parsing parsing; + parsing.Prescan(path, Options{}); + if (parsing.messages().AnyFatalError()) { + parsing.messages().Emit(err); + err << "could not scan " << path << '\n'; + return {}; + } + parsing.Parse(); + parsing.messages().Emit(err); + if (!parsing.consumedWholeFile()) { + err << "f18 parser FAIL; final position: "; + parsing.Identify(err, parsing.finalRestingPlace(), " "); + return {}; + } + if (parsing.messages().AnyFatalError()) { + err << "could not parse " << path << '\n'; + return {}; + } + return std::move(parsing.parseTree()); } } // namespace parser } // namespace Fortran diff --git a/flang/lib/parser/parsing.h b/flang/lib/parser/parsing.h index a3fbf6afb1e3..655d46165f9d 100644 --- a/flang/lib/parser/parsing.h +++ b/flang/lib/parser/parsing.h @@ -36,12 +36,12 @@ public: bool consumedWholeFile() const { return consumedWholeFile_; } const char *finalRestingPlace() const { return finalRestingPlace_; } Messages &messages() { return messages_; } - Program &parseTree() { return *parseTree_; } + std::optional &parseTree() { return parseTree_; } - bool Prescan(const std::string &path, Options); + void Prescan(const std::string &path, Options); void DumpCookedChars(std::ostream &) const; void DumpProvenance(std::ostream &) const; - bool Parse(); + void Parse(); void Identify(std::ostream &o, const char *at, const std::string &prefix, bool echoSourceLine = false) const { @@ -49,12 +49,13 @@ public: o, cooked_.GetProvenance(at).start(), prefix, echoSourceLine); } + static std::optional ForTesting(std::string path, std::ostream &); + private: Options options_; AllSources allSources_; CookedSource cooked_{allSources_}; Messages messages_{cooked_}; - bool anyFatalError_{false}; bool consumedWholeFile_{false}; const char *finalRestingPlace_{nullptr}; std::optional parseTree_; diff --git a/flang/lib/parser/preprocessor.cc b/flang/lib/parser/preprocessor.cc index 30634be5caf9..913e0dac1f6c 100644 --- a/flang/lib/parser/preprocessor.cc +++ b/flang/lib/parser/preprocessor.cc @@ -369,7 +369,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { return; } if (dir.TokenAt(j).ToString() != "#") { - prescanner->Error("missing '#'"_en_US, dir.GetTokenProvenance(j)); + prescanner->Say("missing '#'"_err_en_US, dir.GetTokenProvenance(j)); return; } j = SkipBlanks(dir, j + 1, tokens); @@ -390,7 +390,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { // TODO: implement #line } else if (dirName == "define") { if (nameToken.empty()) { - prescanner->Error("#define: missing or invalid name"_en_US, + prescanner->Say("#define: missing or invalid name"_err_en_US, dir.GetTokenProvenance(j < tokens ? j : tokens - 1)); return; } @@ -408,8 +408,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { isVariadic = true; } else { if (an.empty() || !IsLegalIdentifierStart(an[0])) { - prescanner->Error( - "#define: missing or invalid argument name"_en_US, + prescanner->Say( + "#define: missing or invalid argument name"_err_en_US, dir.GetTokenProvenance(j)); return; } @@ -417,7 +417,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } j = SkipBlanks(dir, j + 1, tokens); if (j == tokens) { - prescanner->Error("#define: malformed argument list"_en_US, + prescanner->Say("#define: malformed argument list"_err_en_US, dir.GetTokenProvenance(tokens - 1)); return; } @@ -426,20 +426,20 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { break; } if (isVariadic || punc != ",") { - prescanner->Error("#define: malformed argument list"_en_US, + prescanner->Say("#define: malformed argument list"_err_en_US, dir.GetTokenProvenance(j)); return; } j = SkipBlanks(dir, j + 1, tokens); if (j == tokens) { - prescanner->Error("#define: malformed argument list"_en_US, + prescanner->Say("#define: malformed argument list"_err_en_US, dir.GetTokenProvenance(tokens - 1)); return; } } if (std::set(argName.begin(), argName.end()).size() != argName.size()) { - prescanner->Error("#define: argument names are not distinct"_en_US, + prescanner->Say("#define: argument names are not distinct"_err_en_US, dir.GetTokenProvenance(dirOffset)); return; } @@ -454,12 +454,12 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } } else if (dirName == "undef") { if (nameToken.empty()) { - prescanner->Error("# missing or invalid name"_en_US, + prescanner->Say("# missing or invalid name"_err_en_US, dir.GetTokenProvenance(tokens - 1)); } else { j = SkipBlanks(dir, j + 1, tokens); if (j != tokens) { - prescanner->Error("#undef: excess tokens at end of directive"_en_US, + prescanner->Say("#undef: excess tokens at end of directive"_err_en_US, dir.GetTokenProvenance(j)); } else { definitions_.erase(nameToken); @@ -467,16 +467,16 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } } else if (dirName == "ifdef" || dirName == "ifndef") { if (nameToken.empty()) { - prescanner->Error( - MessageFormattedText("#%s: missing name"_en_US, dirName.data()), + prescanner->Say( + MessageFormattedText("#%s: missing name"_err_en_US, dirName.data()), dir.GetTokenProvenance(tokens - 1)); return; } j = SkipBlanks(dir, j + 1, tokens); if (j != tokens) { - prescanner->Error( - MessageFormattedText( - "#%s: excess tokens at end of directive"_en_US, dirName.data()), + prescanner->Say(MessageFormattedText( + "#%s: excess tokens at end of directive"_err_en_US, + dirName.data()), dir.GetTokenProvenance(j)); } else if (IsNameDefined(nameToken) == (dirName == "ifdef")) { ifStack_.push(CanDeadElseAppear::Yes); @@ -493,15 +493,15 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } } else if (dirName == "else") { if (j != tokens) { - prescanner->Error("#else: excess tokens at end of directive"_en_US, + prescanner->Say("#else: excess tokens at end of directive"_err_en_US, dir.GetTokenProvenance(j)); } else if (ifStack_.empty()) { - prescanner->Error( - "#else: not nested within #if, #ifdef, or #ifndef"_en_US, + prescanner->Say( + "#else: not nested within #if, #ifdef, or #ifndef"_err_en_US, dir.GetTokenProvenance(tokens - 1)); } else if (ifStack_.top() != CanDeadElseAppear::Yes) { - prescanner->Error( - "#else: already appeared within this #if, #ifdef, or #ifndef"_en_US, + prescanner->Say( + "#else: already appeared within this #if, #ifdef, or #ifndef"_err_en_US, dir.GetTokenProvenance(tokens - 1)); } else { ifStack_.pop(); @@ -510,12 +510,12 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } } else if (dirName == "elif") { if (ifStack_.empty()) { - prescanner->Error( - "#elif: not nested within #if, #ifdef, or #ifndef"_en_US, + prescanner->Say( + "#elif: not nested within #if, #ifdef, or #ifndef"_err_en_US, dir.GetTokenProvenance(tokens - 1)); } else if (ifStack_.top() != CanDeadElseAppear::Yes) { - prescanner->Error("#elif: #else previously appeared within this " - "#if, #ifdef, or #ifndef"_en_US, + prescanner->Say("#elif: #else previously appeared within this " + "#if, #ifdef, or #ifndef"_err_en_US, dir.GetTokenProvenance(tokens - 1)); } else { ifStack_.pop(); @@ -524,32 +524,32 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } } else if (dirName == "endif") { if (j != tokens) { - prescanner->Error("#endif: excess tokens at end of directive"_en_US, + prescanner->Say("#endif: excess tokens at end of directive"_err_en_US, dir.GetTokenProvenance(j)); } else if (ifStack_.empty()) { - prescanner->Error("#endif: no #if, #ifdef, or #ifndef"_en_US, + prescanner->Say("#endif: no #if, #ifdef, or #ifndef"_err_en_US, dir.GetTokenProvenance(tokens - 1)); } else { ifStack_.pop(); } } else if (dirName == "error") { - prescanner->Error( - MessageFormattedText("#error: %s"_en_US, dir.ToString().data()), + prescanner->Say( + MessageFormattedText("#error: %s"_err_en_US, dir.ToString().data()), dir.GetTokenProvenance(dirOffset)); } else if (dirName == "warning") { - prescanner->Complain( + prescanner->Say( MessageFormattedText("#warning: %s"_en_US, dir.ToString().data()), dir.GetTokenProvenance(dirOffset)); } else if (dirName == "include") { if (j == tokens) { - prescanner->Error("#include: missing name of file to include"_en_US, + prescanner->Say("#include: missing name of file to include"_err_en_US, dir.GetTokenProvenance(tokens - 1)); return; } std::string include; if (dir.TokenAt(j).ToString() == "<") { if (dir.TokenAt(tokens - 1).ToString() != ">") { - prescanner->Error("#include: expected '>' at end of directive"_en_US, + prescanner->Say("#include: expected '>' at end of directive"_err_en_US, dir.GetTokenProvenance(tokens - 1)); return; } @@ -560,20 +560,20 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { include.substr(include.size() - 1, 1) == "\"") { include = include.substr(1, include.size() - 2); } else { - prescanner->Error("#include: expected name of file to include"_en_US, + prescanner->Say("#include: expected name of file to include"_err_en_US, dir.GetTokenProvenance(j < tokens ? j : tokens - 1)); return; } if (include.empty()) { - prescanner->Error("#include: empty include file name"_en_US, + prescanner->Say("#include: empty include file name"_err_en_US, dir.GetTokenProvenance(dirOffset)); return; } std::stringstream error; const SourceFile *included{allSources_.Open(include, &error)}; if (included == nullptr) { - prescanner->Error( - MessageFormattedText("#include: %s"_en_US, error.str().data()), + prescanner->Say( + MessageFormattedText("#include: %s"_err_en_US, error.str().data()), dir.GetTokenProvenance(dirOffset)); return; } @@ -582,13 +582,11 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } ProvenanceRange fileRange{ allSources_.AddIncludedFile(*included, dir.GetProvenanceRange())}; - if (!Prescanner{*prescanner}.Prescan(fileRange)) { - prescanner->set_anyFatalErrors(); - } + Prescanner{*prescanner}.Prescan(fileRange); } else { - prescanner->Error( - MessageFormattedText( - "#%s: unknown or unimplemented directive"_en_US, dirName.data()), + prescanner->Say(MessageFormattedText( + "#%s: unknown or unimplemented directive"_err_en_US, + dirName.data()), dir.GetTokenProvenance(dirOffset)); } } @@ -649,8 +647,8 @@ void Preprocessor::SkipDisabledConditionalCode(const std::string &dirName, } } } - prescanner->Error( - MessageFormattedText("#%s: missing #endif"_en_US, dirName.data()), + prescanner->Say( + MessageFormattedText("#%s: missing #endif"_err_en_US, dirName.data()), provenance); } @@ -751,8 +749,8 @@ static std::int64_t ExpressionValue(const TokenSequence &token, std::size_t tokens{token.SizeInTokens()}; if (*atToken >= tokens) { - *error = Message{ - token.GetTokenProvenance(tokens - 1), "incomplete expression"_en_US}; + *error = Message{token.GetTokenProvenance(tokens - 1), + "incomplete expression"_err_en_US}; return 0; } @@ -770,7 +768,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, if (consumed < t.size()) { *error = Message{token.GetTokenProvenance(opAt), MessageFormattedText( - "uninterpretable numeric constant '%s'"_en_US, t.data())}; + "uninterpretable numeric constant '%s'"_err_en_US, t.data())}; return 0; } } else if (IsLegalIdentifierStart(t[0])) { @@ -792,13 +790,13 @@ static std::int64_t ExpressionValue(const TokenSequence &token, op = it->second; } else { *error = Message{token.GetTokenProvenance(tokens - 1), - "operand expected in expression"_en_US}; + "operand expected in expression"_err_en_US}; return 0; } } if (precedence[op] < minimumPrecedence) { *error = Message{ - token.GetTokenProvenance(opAt), "operator precedence error"_en_US}; + token.GetTokenProvenance(opAt), "operator precedence error"_err_en_US}; return 0; } ++*atToken; @@ -813,7 +811,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, ++*atToken; } else { *error = Message{token.GetTokenProvenance(tokens - 1), - "')' missing from expression"_en_US}; + "')' missing from expression"_err_en_US}; return 0; } break; @@ -855,8 +853,8 @@ static std::int64_t ExpressionValue(const TokenSequence &token, switch (op) { case POWER: if (left == 0 && right < 0) { - *error = - Message{token.GetTokenProvenance(opAt), "0 ** negative power"_en_US}; + *error = Message{ + token.GetTokenProvenance(opAt), "0 ** negative power"_err_en_US}; return 0; } if (left == 0 || left == 1 || right == 1) { @@ -870,7 +868,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, for (; right > 0; --right) { if ((power * left) / left != power) { *error = Message{token.GetTokenProvenance(opAt), - "overflow in exponentation"_en_US}; + "overflow in exponentation"_err_en_US}; return 0; } power *= left; @@ -882,45 +880,46 @@ static std::int64_t ExpressionValue(const TokenSequence &token, return 0; } if ((left * right) / left != right) { - *error = Message{ - token.GetTokenProvenance(opAt), "overflow in multiplication"_en_US}; + *error = Message{token.GetTokenProvenance(opAt), + "overflow in multiplication"_err_en_US}; } return left * right; case DIVIDE: if (right == 0) { *error = - Message{token.GetTokenProvenance(opAt), "division by zero"_en_US}; + Message{token.GetTokenProvenance(opAt), "division by zero"_err_en_US}; return 0; } return left / right; case MODULUS: if (right == 0) { - *error = Message{token.GetTokenProvenance(opAt), "modulus by zero"_en_US}; + *error = + Message{token.GetTokenProvenance(opAt), "modulus by zero"_err_en_US}; return 0; } return left % right; case ADD: if ((left < 0) == (right < 0) && (left < 0) != (left + right < 0)) { - *error = - Message{token.GetTokenProvenance(opAt), "overflow in addition"_en_US}; + *error = Message{ + token.GetTokenProvenance(opAt), "overflow in addition"_err_en_US}; } return left + right; case SUBTRACT: if ((left < 0) != (right < 0) && (left < 0) == (left - right < 0)) { *error = Message{ - token.GetTokenProvenance(opAt), "overflow in subtraction"_en_US}; + token.GetTokenProvenance(opAt), "overflow in subtraction"_err_en_US}; } return left - right; case LEFTSHIFT: if (right < 0 || right > 64) { - *error = - Message{token.GetTokenProvenance(opAt), "bad left shift count"_en_US}; + *error = Message{ + token.GetTokenProvenance(opAt), "bad left shift count"_err_en_US}; } return right >= 64 ? 0 : left << right; case RIGHTSHIFT: if (right < 0 || right > 64) { *error = Message{ - token.GetTokenProvenance(opAt), "bad right shift count"_en_US}; + token.GetTokenProvenance(opAt), "bad right shift count"_err_en_US}; } return right >= 64 ? 0 : left >> right; case BITAND: @@ -939,7 +938,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, case SELECT: if (*atToken >= tokens || token.TokenAt(*atToken).ToString() != ":") { *error = Message{token.GetTokenProvenance(opAt), - "':' required in selection expression"_en_US}; + "':' required in selection expression"_err_en_US}; return left; } else { ++*atToken; @@ -983,10 +982,11 @@ bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr, std::optional error; bool result{ExpressionValue(expr4, 0, &atToken, &error) != 0}; if (error.has_value()) { - prescanner->Error(std::move(*error)); + prescanner->Say(std::move(*error)); } else if (atToken < expr4.SizeInTokens()) { - prescanner->Error(atToken == 0 ? "could not parse any expression"_en_US - : "excess characters after expression"_en_US, + prescanner->Say(atToken == 0 + ? "could not parse any expression"_err_en_US + : "excess characters after expression"_err_en_US, expr4.GetTokenProvenance(atToken)); } return result; diff --git a/flang/lib/parser/prescan.cc b/flang/lib/parser/prescan.cc index 1fcd0c217717..429de34ed34c 100644 --- a/flang/lib/parser/prescan.cc +++ b/flang/lib/parser/prescan.cc @@ -42,7 +42,7 @@ static void NormalizeCompilerDirectiveCommentMarker(TokenSequence *dir) { CHECK(!"compiler directive all blank"); } -bool Prescanner::Prescan(ProvenanceRange range) { +void Prescanner::Prescan(ProvenanceRange range) { AllSources &allSources{cooked_.allSources()}; ProvenanceRange around{allSources.GetContiguousRangeAround(range)}; startProvenance_ = range.start(); @@ -67,7 +67,6 @@ bool Prescanner::Prescan(ProvenanceRange range) { TokenSequence tokens{dir, allSources.AddCompilerInsertion(dir).start()}; tokens.Emit(&cooked_); } - return !anyFatalErrors_; } void Prescanner::Statement() { @@ -131,7 +130,7 @@ void Prescanner::Statement() { FortranInclude(ppd + ppl.payloadOffset); break; case LineClassification::Kind::PreprocessorDirective: - Complain("preprocessed line looks like a preprocessor directive"_en_US, + Say("preprocessed line looks like a preprocessor directive"_en_US, preprocessed->GetProvenanceRange().start()); preprocessed->ToLowerCase().Emit(&cooked_); break; @@ -169,31 +168,14 @@ TokenSequence Prescanner::TokenizePreprocessorDirective() { return {std::move(tokens)}; } -Message &Prescanner::Error(Message &&message) { - anyFatalErrors_ = true; - return messages_.Put(std::move(message)); +void Prescanner::Say(Message &&message) { messages_.Put(std::move(message)); } + +void Prescanner::Say(MessageFixedText text, Provenance p) { + messages_.Put({p, text}); } -Message &Prescanner::Error(MessageFixedText text, Provenance p) { - anyFatalErrors_ = true; - return messages_.Put({p, text}); -} - -Message &Prescanner::Error(MessageFormattedText &&text, Provenance p) { - anyFatalErrors_ = true; - return messages_.Put({p, std::move(text)}); -} - -Message &Prescanner::Complain(Message &&message) { - return messages_.Put(std::move(message)); -} - -Message &Prescanner::Complain(MessageFixedText text, Provenance p) { - return messages_.Put({p, text}); -} - -Message &Prescanner::Complain(MessageFormattedText &&text, Provenance p) { - return messages_.Put({p, std::move(text)}); +void Prescanner::Say(MessageFormattedText &&text, Provenance p) { + messages_.Put({p, std::move(text)}); } void Prescanner::NextLine() { @@ -424,7 +406,7 @@ void Prescanner::QuotedCharacterLiteral(TokenSequence *tokens) { } if (*at_ == '\n') { if (!inPreprocessorDirective_) { - Error("incomplete character literal"_en_US, GetProvenance(start)); + Say("incomplete character literal"_err_en_US, GetProvenance(start)); } break; } @@ -474,7 +456,7 @@ void Prescanner::Hollerith(TokenSequence *tokens, int count) { } if (*at_ == '\n') { if (!inPreprocessorDirective_) { - Error("incomplete Hollerith literal"_en_US, GetProvenance(start)); + Say("incomplete Hollerith literal"_err_en_US, GetProvenance(start)); } } else { NextChar(); @@ -575,13 +557,13 @@ bool Prescanner::FortranInclude(const char *firstQuote) { path += *p; } if (*p != quote) { - Error("malformed path name string"_en_US, GetProvenance(p)); + Say("malformed path name string"_err_en_US, GetProvenance(p)); return true; } for (++p; *p == ' ' || *p == '\t'; ++p) { } if (*p != '\n' && *p != '!') { - Complain("excess characters after path name"_en_US, GetProvenance(p)); + Say("excess characters after path name"_en_US, GetProvenance(p)); } std::stringstream error; Provenance provenance{GetProvenance(lineStart_)}; @@ -595,7 +577,7 @@ bool Prescanner::FortranInclude(const char *firstQuote) { allSources.PopSearchPathDirectory(); } if (included == nullptr) { - Error(MessageFormattedText("INCLUDE: %s"_en_US, error.str().data()), + Say(MessageFormattedText("INCLUDE: %s"_err_en_US, error.str().data()), provenance); return true; } @@ -606,7 +588,7 @@ bool Prescanner::FortranInclude(const char *firstQuote) { provenance, static_cast(p - lineStart_)}; ProvenanceRange fileRange{ allSources.AddIncludedFile(*included, includeLineRange)}; - anyFatalErrors_ |= !Prescanner{*this}.Prescan(fileRange); + Prescanner{*this}.Prescan(fileRange); return true; } @@ -672,7 +654,7 @@ const char *Prescanner::FixedFormContinuationLine() { if (col1 == '&') { // Extension: '&' as continuation marker if (warnOnNonstandardUsage_) { - Complain("nonstandard usage"_en_US, GetProvenance(lineStart_)); + Say("nonstandard usage"_en_US, GetProvenance(lineStart_)); } return lineStart_ + 1; } diff --git a/flang/lib/parser/prescan.h b/flang/lib/parser/prescan.h index 9630e85d7d3b..9dc14dd70a3a 100644 --- a/flang/lib/parser/prescan.h +++ b/flang/lib/parser/prescan.h @@ -28,8 +28,6 @@ public: Prescanner(Messages &, CookedSource &, Preprocessor &); Prescanner(const Prescanner &); - bool anyFatalErrors() const { return anyFatalErrors_; } - void set_anyFatalErrors() { anyFatalErrors_ = true; } Messages &messages() const { return messages_; } Prescanner &set_fixedForm(bool yes) { @@ -59,7 +57,7 @@ public: Prescanner &AddCompilerDirectiveSentinel(const std::string &); - bool Prescan(ProvenanceRange); + void Prescan(ProvenanceRange); void Statement(); void NextLine(); @@ -69,12 +67,9 @@ public: TokenSequence TokenizePreprocessorDirective(); Provenance GetCurrentProvenance() const { return GetProvenance(at_); } - Message &Error(Message &&); - Message &Error(MessageFixedText, Provenance); - Message &Error(MessageFormattedText &&, Provenance); - Message &Complain(Message &&); - Message &Complain(MessageFixedText, Provenance); - Message &Complain(MessageFormattedText &&, Provenance); + void Say(Message &&); + void Say(MessageFixedText, Provenance); + void Say(MessageFormattedText &&, Provenance); private: struct LineClassification { diff --git a/flang/lib/parser/token-parsers.h b/flang/lib/parser/token-parsers.h index 29954644b59d..9c38cfd9bfa2 100644 --- a/flang/lib/parser/token-parsers.h +++ b/flang/lib/parser/token-parsers.h @@ -33,7 +33,7 @@ public: return {at}; } } - state->PutMessage(at, messageText_); + state->Say(at, messageText_); return {}; } @@ -42,9 +42,10 @@ private: const MessageFixedText messageText_; }; -constexpr auto letter = CharPredicateGuard{IsLetter, "expected letter"_en_US}; +constexpr auto letter = + CharPredicateGuard{IsLetter, "expected letter"_err_en_US}; constexpr auto digit = - CharPredicateGuard{IsDecimalDigit, "expected digit"_en_US}; + CharPredicateGuard{IsDecimalDigit, "expected digit"_err_en_US}; // "xyz"_ch matches one instance of the characters x, y, or z without skipping // any spaces before or after. The parser returns the location of the character @@ -66,7 +67,7 @@ public: } } } - state->PutMessage(at, MessageExpectedText{chars_, bytes_}); + state->Say(at, MessageExpectedText{chars_, bytes_}); return {}; } @@ -100,7 +101,7 @@ static inline void MissingSpace(ParseState *state) { if (!state->inFixedForm()) { state->set_anyConformanceViolation(); if (state->warnOnNonstandardUsage()) { - state->PutMessage("expected space"_en_US); + state->Say("expected space"_err_en_US); } } } @@ -171,7 +172,7 @@ public: } else if (**at == ToLowerCaseLetter(*p)) { at.reset(); } else { - state->PutMessage(start, MessageExpectedText{str_, bytes_}); + state->Say(start, MessageExpectedText{str_, bytes_}); return {}; } } @@ -241,7 +242,7 @@ struct CharLiteralChar { } char ch{**och}; if (ch == '\n') { - state->PutMessage(at, "unclosed character constant"_en_US); + state->Say(at, "unclosed character constant"_err_en_US); return {}; } if (ch != '\\') { @@ -252,7 +253,7 @@ struct CharLiteralChar { } ch = **och; if (ch == '\n') { - state->PutMessage(at, "unclosed character constant"_en_US); + state->Say(at, "unclosed character constant"_err_en_US); return {}; } if (std::optional escChar{BackslashEscapeValue(ch)}) { @@ -262,7 +263,7 @@ struct CharLiteralChar { ch -= '0'; for (int j = (ch > 3 ? 1 : 2); j-- > 0;) { static constexpr auto octalDigit = - CharPredicateGuard{IsOctalDigit, "expected octal digit"_en_US}; + CharPredicateGuard{IsOctalDigit, "expected octal digit"_err_en_US}; och = octalDigit.Parse(state); if (och.has_value()) { ch = 8 * ch + **och - '0'; @@ -274,7 +275,7 @@ struct CharLiteralChar { ch = 0; for (int j = 0; j++ < 2;) { static constexpr auto hexDigit = CharPredicateGuard{ - IsHexadecimalDigit, "expected hexadecimal digit"_en_US}; + IsHexadecimalDigit, "expected hexadecimal digit"_err_en_US}; och = hexDigit.Parse(state); if (och.has_value()) { ch = 16 * ch + HexadecimalDigitValue(**och); @@ -283,7 +284,7 @@ struct CharLiteralChar { } } } else { - state->PutMessage(at, "bad escaped character"_en_US); + state->Say(at, "bad escaped character"_err_en_US); } return {Result::Escaped(ch)}; } @@ -314,7 +315,7 @@ static bool IsNonstandardUsageOk(ParseState *state) { } state->set_anyConformanceViolation(); if (state->warnOnNonstandardUsage()) { - state->PutMessage("nonstandard usage"_en_US); + state->Say("nonstandard usage"_en_US); } return true; } @@ -385,7 +386,7 @@ struct BOZLiteral { } if (content.empty()) { - state->PutMessage(start, "no digit in BOZ literal"_en_US); + state->Say(start, "no digit in BOZ literal"_err_en_US); return {}; } @@ -393,13 +394,13 @@ struct BOZLiteral { for (auto digit : content) { digit = HexadecimalDigitValue(digit); if ((digit >> *shift) > 0) { - state->PutMessage(start, "bad digit in BOZ literal"_en_US); + state->Say(start, "bad digit in BOZ literal"_err_en_US); return {}; } std::uint64_t was{value}; value <<= *shift; if ((value >> *shift) != was) { - state->PutMessage(start, "excessive digits in BOZ literal"_en_US); + state->Say(start, "excessive digits in BOZ literal"_err_en_US); return {}; } value |= digit; @@ -431,7 +432,7 @@ struct DigitString { value += digitValue; } if (overflow) { - state->PutMessage(*firstDigit, "overflow in decimal literal"_en_US); + state->Say(*firstDigit, "overflow in decimal literal"_err_en_US); } return {value}; } @@ -458,14 +459,14 @@ struct HollerithLiteral { if (state->encoding() == Encoding::EUC_JP) { std::optional chBytes{EUC_JPCharacterBytes(p)}; if (!chBytes.has_value()) { - state->PutMessage(start, "bad EUC_JP characters in Hollerith"_en_US); + state->Say(start, "bad EUC_JP characters in Hollerith"_err_en_US); return {}; } bytes = *chBytes; } else if (state->encoding() == Encoding::UTF8) { std::optional chBytes{UTF8CharacterBytes(p)}; if (!chBytes.has_value()) { - state->PutMessage(start, "bad UTF-8 characters in Hollerith"_en_US); + state->Say(start, "bad UTF-8 characters in Hollerith"_err_en_US); return {}; } bytes = *chBytes; @@ -473,8 +474,8 @@ struct HollerithLiteral { if (bytes == 1) { std::optional at{nextCh.Parse(state)}; if (!at.has_value() || !isprint(**at)) { - state->PutMessage( - start, "insufficient or bad characters in Hollerith"_en_US); + state->Say( + start, "insufficient or bad characters in Hollerith"_err_en_US); return {}; } content += **at; diff --git a/flang/lib/parser/unparse.cc b/flang/lib/parser/unparse.cc index cb8a04c59ae1..e9d01e766997 100644 --- a/flang/lib/parser/unparse.cc +++ b/flang/lib/parser/unparse.cc @@ -2124,9 +2124,7 @@ private: WalkTupleElements(tuple, separator); } - void EndSubprogram() { - structureComponents_.clear(); - } + void EndSubprogram() { structureComponents_.clear(); } std::ostream &out_; int indent_{0}; diff --git a/flang/tools/f18/f18.cc b/flang/tools/f18/f18.cc index 4b73d18a5f1f..1a7bc32da187 100644 --- a/flang/tools/f18/f18.cc +++ b/flang/tools/f18/f18.cc @@ -141,7 +141,10 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options, } } Fortran::parser::Parsing parsing; - if (!parsing.Prescan(path, options)) { + parsing.Prescan(path, options); + if (!parsing.messages().empty() && + (driver.warningsAreErrors || parsing.messages().AnyFatalError())) { + std::cerr << driver.prefix << "could not scan " << path << '\n'; parsing.messages().Emit(std::cerr, driver.prefix); exit(EXIT_FAILURE); } @@ -153,29 +156,27 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options, parsing.DumpCookedChars(std::cout); return {}; } - if (!parsing.Parse()) { - if (!parsing.consumedWholeFile()) { - std::cerr << "f18 FAIL; final position: "; - parsing.Identify(std::cerr, parsing.finalRestingPlace(), " "); - } + parsing.Parse(); + parsing.messages().Emit(std::cerr, driver.prefix); + if (!parsing.consumedWholeFile()) { + std::cerr << "f18 parser FAIL; final position: "; + parsing.Identify(std::cerr, parsing.finalRestingPlace(), " "); + exit(EXIT_FAILURE); + } + if (!parsing.messages().empty() && + (driver.warningsAreErrors || parsing.messages().AnyFatalError()) || + !parsing.parseTree().has_value()) { std::cerr << driver.prefix << "could not parse " << path << '\n'; - parsing.messages().Emit(std::cerr, driver.prefix); exit(EXIT_FAILURE); } if (driver.measureTree) { - MeasureParseTree(parsing.parseTree()); + MeasureParseTree(*parsing.parseTree()); } if (driver.dumpUnparse) { - Unparse(std::cout, parsing.parseTree(), driver.encoding, + Unparse(std::cout, *parsing.parseTree(), driver.encoding, true /*capitalize*/); return {}; } - - parsing.messages().Emit(std::cerr, driver.prefix); - if (driver.warningsAreErrors && - !parsing.messages().empty()) { - exit(EXIT_FAILURE); - } if (driver.parseOnly) { return {}; } @@ -187,7 +188,7 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options, static_cast(getpid())); { std::ofstream tmpSource; tmpSource.open(tmpSourcePath); - Unparse(tmpSource, parsing.parseTree(), driver.encoding); + Unparse(tmpSource, *parsing.parseTree(), driver.encoding); } if (ParentProcess()) { diff --git a/flang/tools/f18/test-sema.cc b/flang/tools/f18/test-sema.cc index b156fbb4167f..38c98bfee1f1 100644 --- a/flang/tools/f18/test-sema.cc +++ b/flang/tools/f18/test-sema.cc @@ -22,12 +22,9 @@ int main(int argc, char *const argv[]) { return EXIT_FAILURE; } std::string path{argv[1]}; - Parsing parsing; - if (!parsing.Prescan(path, Options{}) || !parsing.Parse()) { - std::cerr << "parse FAILED\n"; - parsing.messages().Emit(std::cerr); - return EXIT_FAILURE; + if (std::optional parseTree{Parsing::ForTesting(path, std::cerr)}) { + DoSemanticAnalysis(parsing.messages().cooked(), *parseTree); + return EXIT_SUCCESS; } - DoSemanticAnalysis(parsing.messages().cooked(), parsing.parseTree()); - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/flang/tools/f18/test-type.cc b/flang/tools/f18/test-type.cc index ec5a7efd407c..c58461861c93 100644 --- a/flang/tools/f18/test-type.cc +++ b/flang/tools/f18/test-type.cc @@ -15,12 +15,9 @@ int main(int argc, char *const argv[]) { return EXIT_FAILURE; } std::string path{argv[1]}; - Parsing parsing; - if (!parsing.Prescan(path, Options{}) || !parsing.Parse()) { - std::cerr << "parse FAILED\n"; - parsing.messages().Emit(std::cerr); - return EXIT_FAILURE; + if (std::optional parseTree{Parsing::ForTesting(path, std::cerr)}) { + semantics::MakeTypes(std::cout, *parseTree); + return EXIT_SUCCESS; } - semantics::MakeTypes(std::cout, parsing.parseTree()); - return EXIT_SUCCESS; + return EXIT_FAILURE; }