From 35aef1025eaaf1888c56aa1f0633012d95c3a613 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 3 May 2018 11:09:04 -0700 Subject: [PATCH] [flang] Improve error message location. Original-commit: flang-compiler/f18@5efd011d184a1dc88262ce68a7cbee6094c1ca2f Reviewed-on: https://github.com/flang-compiler/f18/pull/81 Tree-same-pre-rewrite: false --- flang/lib/parser/message.cc | 8 +++--- flang/lib/parser/message.h | 2 +- flang/lib/parser/parsing.h | 2 +- flang/lib/parser/preprocessor.cc | 5 ++++ flang/lib/parser/prescan.cc | 55 ++++++++++++++++++++++------------------ flang/lib/parser/prescan.h | 1 + flang/lib/parser/provenance.cc | 2 +- flang/lib/parser/provenance.h | 6 ++--- 8 files changed, 47 insertions(+), 34 deletions(-) diff --git a/flang/lib/parser/message.cc b/flang/lib/parser/message.cc index 2eeb9cb..62f849e 100644 --- a/flang/lib/parser/message.cc +++ b/flang/lib/parser/message.cc @@ -104,16 +104,16 @@ std::string Message::ToString() const { return s; } -ProvenanceRange Message::GetProvenance(const CookedSource &cooked) const { +ProvenanceRange Message::GetProvenanceRange(const CookedSource &cooked) const { if (cookedSourceRange_.begin() != nullptr) { - return cooked.GetProvenance(cookedSourceRange_); + return cooked.GetProvenanceRange(cookedSourceRange_); } return provenanceRange_; } void Message::Emit( std::ostream &o, const CookedSource &cooked, bool echoSourceLine) const { - ProvenanceRange provenanceRange{GetProvenance(cooked)}; + ProvenanceRange provenanceRange{GetProvenanceRange(cooked)}; std::string text; if (isFatal_) { text += "ERROR: "; @@ -122,7 +122,7 @@ void Message::Emit( cooked.allSources().EmitMessage(o, provenanceRange, text, echoSourceLine); for (const Message *context{context_.get()}; context != nullptr; context = context->context_.get()) { - ProvenanceRange contextProvenance{context->GetProvenance(cooked)}; + ProvenanceRange contextProvenance{context->GetProvenanceRange(cooked)}; text = "in the context: "; text += context->ToString(); // TODO: don't echo the source lines of a context when it's the diff --git a/flang/lib/parser/message.h b/flang/lib/parser/message.h index babf1fb..32c3006 100644 --- a/flang/lib/parser/message.h +++ b/flang/lib/parser/message.h @@ -150,7 +150,7 @@ public: void Incorporate(Message &); std::string ToString() const; - ProvenanceRange GetProvenance(const CookedSource &) const; + ProvenanceRange GetProvenanceRange(const CookedSource &) const; void Emit( std::ostream &, const CookedSource &, bool echoSourceLine = true) const; diff --git a/flang/lib/parser/parsing.h b/flang/lib/parser/parsing.h index dbb1a3d..aa5ae47 100644 --- a/flang/lib/parser/parsing.h +++ b/flang/lib/parser/parsing.h @@ -64,7 +64,7 @@ public: void EmitMessage(std::ostream &o, const char *at, const std::string &message, bool echoSourceLine = false) const { allSources_.EmitMessage( - o, cooked_.GetProvenance(at).start(), message, echoSourceLine); + o, cooked_.GetProvenanceRange(at).start(), message, echoSourceLine); } bool ForTesting(std::string path, std::ostream &); diff --git a/flang/lib/parser/preprocessor.cc b/flang/lib/parser/preprocessor.cc index 94bc2bd..f2b8fc2 100644 --- a/flang/lib/parser/preprocessor.cc +++ b/flang/lib/parser/preprocessor.cc @@ -759,6 +759,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, } std::size_t tokens{token.SizeInTokens()}; + CHECK(tokens > 0); if (*atToken >= tokens) { *error = Message{token.GetProvenanceRange(), "incomplete expression"_err_en_US}; @@ -993,6 +994,10 @@ bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr, } TokenSequence expr3{ReplaceMacros(expr2, *prescanner)}; TokenSequence expr4{StripBlanks(expr3, 0, expr3.SizeInTokens())}; + if (expr4.empty()) { + prescanner->Say("empty expression"_err_en_US, expr.GetProvenanceRange()); + return false; + } std::size_t atToken{0}; std::optional error; bool result{ExpressionValue(expr4, 0, &atToken, &error) != 0}; diff --git a/flang/lib/parser/prescan.cc b/flang/lib/parser/prescan.cc index 6afb639..e34a080 100644 --- a/flang/lib/parser/prescan.cc +++ b/flang/lib/parser/prescan.cc @@ -150,7 +150,7 @@ void Prescanner::Statement() { break; case LineClassification::Kind::ConditionalCompilationDirective: case LineClassification::Kind::PreprocessorDirective: - Say("preprocessed line looks like a preprocessor directive"_en_US, + Say("preprocessed line resembles a preprocessor directive"_en_US, preprocessed->GetProvenanceRange()); preprocessed->ToLowerCase().Emit(&cooked_); break; @@ -188,13 +188,18 @@ TokenSequence Prescanner::TokenizePreprocessorDirective() { return tokens; } -void Prescanner::Say(Message &&message) { messages_.Put(std::move(message)); } +void Prescanner::Say(Message &&message) { + CHECK(cooked_.IsValid(message.GetProvenanceRange(cooked_))); + messages_.Put(std::move(message)); +} void Prescanner::Say(MessageFixedText text, ProvenanceRange r) { + CHECK(cooked_.IsValid(r)); messages_.Put({r, text}); } void Prescanner::Say(MessageFormattedText &&text, ProvenanceRange r) { + CHECK(cooked_.IsValid(r)); messages_.Put({r, std::move(text)}); } @@ -239,10 +244,15 @@ void Prescanner::LabelField(TokenSequence *token) { } } +void Prescanner::SkipToEndOfLine() { + while (*at_ != '\n') { + ++at_, ++column_; + } +} + void Prescanner::NextChar() { CHECK(*at_ != '\n'); - ++at_; - ++column_; + ++at_, ++column_; if (inPreprocessorDirective_) { while (*at_ == '/' && at_[1] == '*') { char star{' '}, slash{' '}; @@ -258,14 +268,11 @@ void Prescanner::NextChar() { BeginSourceLineAndAdvance(); } } else { - if ((inFixedForm_ && column_ > fixedFormColumnLimit_ && - !tabInCurrentLine_) || - (*at_ == '!' && !inCharLiteral_)) { - // Skip remainder of the line due to '!' comment marker or - // hitting the right margin in fixed form. - while (*at_ != '\n') { - ++at_; - } + if (inFixedForm_ && column_ > fixedFormColumnLimit_ && + !tabInCurrentLine_) { + SkipToEndOfLine(); + } else if (*at_ == '!' && !inCharLiteral_) { + SkipToEndOfLine(); } while (*at_ == '\n' || *at_ == '&') { if (inFixedForm_) { @@ -413,7 +420,7 @@ bool Prescanner::ExponentAndKind(TokenSequence *tokens) { } void Prescanner::QuotedCharacterLiteral(TokenSequence *tokens) { - const char *start{at_}, quote{*start}; + const char *start{at_}, quote{*start}, *end{at_ + 1}; inCharLiteral_ = true; const auto emit = [&](char ch) { EmitChar(tokens, ch); }; const auto insert = [&](char ch) { EmitInsertedChar(tokens, ch); }; @@ -428,10 +435,11 @@ void Prescanner::QuotedCharacterLiteral(TokenSequence *tokens) { if (*at_ == '\n') { if (!inPreprocessorDirective_) { Say("incomplete character literal"_err_en_US, - GetProvenanceRange(start, at_)); + GetProvenanceRange(start, end)); } break; } + end = at_ + 1; NextChar(); if (*at_ == quote && !escape) { // A doubled quote mark becomes a single instance of the quote character @@ -454,11 +462,17 @@ void Prescanner::QuotedCharacterLiteral(TokenSequence *tokens) { void Prescanner::Hollerith(TokenSequence *tokens, int count) { inCharLiteral_ = true; + CHECK(*at_ == 'h' || *at_ == 'H'); EmitChar(tokens, 'H'); - const char *start{at_}; + const char *start{at_}, *end{at_ + 1}; while (count-- > 0) { if (PadOutCharacterLiteral(tokens)) { - } else if (*at_ != '\n') { + } else if (*at_ == '\n') { + Say("incomplete Hollerith literal"_err_en_US, + GetProvenanceRange(start, end)); + break; + } else { + end = at_ + 1; NextChar(); EmitChar(tokens, *at_); // Multi-byte character encodings should count as single characters. @@ -475,16 +489,9 @@ void Prescanner::Hollerith(TokenSequence *tokens, int count) { while (bytes-- > 1) { EmitChar(tokens, *++at_); } - } else { - break; } } - if (*at_ == '\n') { - if (!inPreprocessorDirective_) { - Say("incomplete Hollerith literal"_err_en_US, - GetProvenanceRange(start, at_)); - } - } else { + if (*at_ != '\n') { NextChar(); } inCharLiteral_ = false; diff --git a/flang/lib/parser/prescan.h b/flang/lib/parser/prescan.h index f57fa82..147e002 100644 --- a/flang/lib/parser/prescan.h +++ b/flang/lib/parser/prescan.h @@ -142,6 +142,7 @@ private: } void LabelField(TokenSequence *); + void SkipToEndOfLine(); void NextChar(); void SkipSpaces(); bool NextToken(TokenSequence *); diff --git a/flang/lib/parser/provenance.cc b/flang/lib/parser/provenance.cc index fe39794..1b696cc 100644 --- a/flang/lib/parser/provenance.cc +++ b/flang/lib/parser/provenance.cc @@ -293,7 +293,7 @@ const AllSources::Origin &AllSources::MapToOrigin(Provenance at) const { return origin_[low]; } -ProvenanceRange CookedSource::GetProvenance(CharBlock cookedRange) const { +ProvenanceRange CookedSource::GetProvenanceRange(CharBlock cookedRange) const { ProvenanceRange range{provenanceMap_.Map(cookedRange.begin() - &data_[0])}; if (cookedRange.size() < range.size()) { return {range.start(), cookedRange.size()}; diff --git a/flang/lib/parser/provenance.h b/flang/lib/parser/provenance.h index 48fbbf4..84b7d05 100644 --- a/flang/lib/parser/provenance.h +++ b/flang/lib/parser/provenance.h @@ -193,12 +193,12 @@ public: return p >= &data_.front() && p <= &data_.back() + 1; } bool IsValid(CharBlock range) const { - return range.empty() || - (IsValid(range.begin()) && IsValid(range.end() - 1)); + return !range.empty() && IsValid(range.begin()) && IsValid(range.end() - 1); } bool IsValid(Provenance p) const { return allSources_.IsValid(p); } + bool IsValid(ProvenanceRange r) const { return allSources_.IsValid(r); } - ProvenanceRange GetProvenance(CharBlock) const; + ProvenanceRange GetProvenanceRange(CharBlock) const; void Put(const char *data, std::size_t bytes) { buffer_.Put(data, bytes); } void Put(char ch) { buffer_.Put(&ch, 1); } -- 2.7.4