In particular, both `-fcolor-diagnostics` and `-fno-color-diagnostics` are
now available in `flang-new` (the diagnostics are formatted by default). In
the frontend driver, `flang-new -fc1`, only `-fcolor-diagnostics` is
- available (by default, the diagnostics are not formatted). Note that this
- will only affect the diagnostics printed by driver (scanning, parsing and
- semantic diagnostics are not affected).
+ available (by default, the diagnostics are not formatted).
## Windows Support
bool needProvenanceRangeToCharBlockMappings{false};
Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
bool prescanAndReformat{false}; // -E
+ bool showColors{false};
};
class Parsing {
void ClearLog();
void EmitMessage(llvm::raw_ostream &o, const char *at,
- const std::string &message, bool echoSourceLine = false) const {
+ const std::string &message, const std::string &prefix,
+ llvm::raw_ostream::Colors color = llvm::raw_ostream::SAVEDCOLOR,
+ bool echoSourceLine = false) const {
allCooked_.allSources().EmitMessage(o,
- allCooked_.GetProvenanceRange(CharBlock(at)), message, echoSourceLine);
+ allCooked_.GetProvenanceRange(CharBlock(at)), message, prefix, color,
+ echoSourceLine);
}
private:
bool IsValid(ProvenanceRange range) const {
return range.size() > 0 && range_.Contains(range);
}
+ void setShowColors(bool showColors) { showColors_ = showColors; }
+ bool getShowColors() const { return showColors_; }
void EmitMessage(llvm::raw_ostream &, const std::optional<ProvenanceRange> &,
- const std::string &message, bool echoSourceLine = false) const;
+ const std::string &message, const std::string &prefix,
+ llvm::raw_ostream::Colors color, bool echoSourceLine = false) const;
const SourceFile *GetSourceFile(
Provenance, std::size_t *offset = nullptr) const;
const char *GetSource(ProvenanceRange) const;
std::vector<std::unique_ptr<SourceFile>> ownedSourceFiles_;
std::list<std::string> searchPath_;
Encoding encoding_{Encoding::UTF_8};
+ bool showColors_{false};
};
// Represents the result of preprocessing and prescanning a single source
if (frontendOptions.instrumentedParse)
fortranOptions.instrumentedParse = true;
+ if (frontendOptions.showColors)
+ fortranOptions.showColors = true;
+
if (frontendOptions.needProvenanceRangeToCharBlockMappings)
fortranOptions.needProvenanceRangeToCharBlockMappings = true;
return "";
}
+static llvm::raw_ostream::Colors PrefixColor(Severity severity) {
+ switch (severity) {
+ case Severity::Error:
+ case Severity::Todo:
+ return llvm::raw_ostream::RED;
+ case Severity::Warning:
+ case Severity::Portability:
+ return llvm::raw_ostream::MAGENTA;
+ default:
+ // TODO: Set the color.
+ break;
+ }
+ return llvm::raw_ostream::SAVEDCOLOR;
+}
+
void Message::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
bool echoSourceLine) const {
std::optional<ProvenanceRange> provenanceRange{GetProvenanceRange(allCooked)};
const AllSources &sources{allCooked.allSources()};
- sources.EmitMessage(
- o, provenanceRange, Prefix(severity()) + ToString(), echoSourceLine);
+ sources.EmitMessage(o, provenanceRange, ToString(), Prefix(severity()),
+ PrefixColor(severity()), echoSourceLine);
bool isContext{attachmentIsContext_};
for (const Message *attachment{attachment_.get()}; attachment;
attachment = attachment->attachment_.get()) {
+ Severity severity = isContext ? Severity::Context : attachment->severity();
sources.EmitMessage(o, attachment->GetProvenanceRange(allCooked),
- Prefix(isContext ? Severity::Context : attachment->severity()) +
- attachment->ToString(),
+ attachment->ToString(), Prefix(severity), PrefixColor(severity),
echoSourceLine);
}
}
if (options.needProvenanceRangeToCharBlockMappings) {
currentCooked_->CompileProvenanceRangeToOffsetMappings(allSources);
}
+ if (options.showColors) {
+ allSources.setShowColors(/*showColors=*/true);
+ }
return sourceFile;
}
return covers;
}
+static void EmitPrefix(llvm::raw_ostream &o, llvm::raw_ostream::Colors color,
+ const std::string &prefix, bool showColors) {
+ if (prefix.empty()) {
+ return;
+ }
+ if (showColors) {
+ o.changeColor(color, true);
+ }
+ o << prefix;
+ if (showColors) {
+ o.resetColor();
+ }
+}
+
void AllSources::EmitMessage(llvm::raw_ostream &o,
const std::optional<ProvenanceRange> &range, const std::string &message,
+ const std::string &prefix, llvm::raw_ostream::Colors color,
bool echoSourceLine) const {
if (!range) {
+ EmitPrefix(o, color, prefix, this->getShowColors());
o << message << '\n';
return;
}
o << inc.source.path();
std::size_t offset{origin.covers.MemberOffset(range->start())};
SourcePosition pos{inc.source.FindOffsetLineAndColumn(offset)};
- o << ':' << pos.line << ':' << pos.column;
- o << ": " << message << '\n';
+ o << ':' << pos.line << ':' << pos.column << ": ";
+ EmitPrefix(o, color, prefix, this->getShowColors());
+ o << message << '\n';
if (echoSourceLine) {
const char *text{inc.source.content().data() +
inc.source.GetLineStartOffset(pos.line)};
}
if (IsValid(origin.replaces)) {
EmitMessage(o, origin.replaces,
- inc.isModule ? "used here"s : "included here"s,
+ inc.isModule ? "used here"s : "included here"s, prefix, color,
echoSourceLine);
}
},
[&](const Macro &mac) {
- EmitMessage(o, origin.replaces, message, echoSourceLine);
EmitMessage(
- o, mac.definition, "in a macro defined here", echoSourceLine);
+ o, origin.replaces, message, prefix, color, echoSourceLine);
+ EmitMessage(o, mac.definition, "in a macro defined here", prefix,
+ color, echoSourceLine);
if (echoSourceLine) {
o << "that expanded to:\n " << mac.expansion << "\n ";
for (std::size_t j{0};
o << "^\n";
}
},
- [&](const CompilerInsertion &) { o << message << '\n'; },
+ [&](const CompilerInsertion &) {
+ EmitPrefix(o, color, prefix, this->getShowColors());
+ o << message << '\n';
+ },
},
origin.u);
}
--- /dev/null
+! Test the behaviors of -f{no-}color-diagnostics when emitting parsing
+! diagnostics.
+! Windows command prompt doesn't support ANSI escape sequences.
+! REQUIRES: shell
+
+! RUN: not %flang %s -fcolor-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_CD
+! RUN: not %flang %s -fno-color-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_NCD
+! RUN: not %flang_fc1 %s -fcolor-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_CD
+! RUN: not %flang_fc1 %s 2>&1 | FileCheck %s --check-prefix=CHECK_NCD
+
+! CHECK_CD: {{.*}}[0;1;31merror: {{.*}}[0mexpected '('
+
+! CHECK_NCD: error: expected '('
+
+program m
+ integer :: i =
+end
--- /dev/null
+! Test the behaviors of -f{no-}color-diagnostics when emitting scanning
+! diagnostics.
+! Windows command prompt doesn't support ANSI escape sequences.
+! REQUIRES: shell
+
+! RUN: not %flang %s -E -Werror -fcolor-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_CD
+! RUN: not %flang %s -E -Werror -fno-color-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_NCD
+! RUN: not %flang_fc1 -E -Werror %s -fcolor-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_CD
+! RUN: not %flang_fc1 -E -Werror %s 2>&1 | FileCheck %s --check-prefix=CHECK_NCD
+
+! CHECK_CD: {{.*}}[0;1;35mwarning: {{.*}}[0mCharacter in fixed-form label field must be a digit
+
+! CHECK_NCD: warning: Character in fixed-form label field must be a digit
+
+1 continue
+end
--- /dev/null
+! Test the behaviors of -f{no-}color-diagnostics when emitting semantic
+! diagnostics.
+! Windows command prompt doesn't support ANSI escape sequences.
+! REQUIRES: shell
+
+! RUN: not %flang %s -fcolor-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_CD
+! RUN: not %flang %s -fno-color-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_NCD
+! RUN: not %flang_fc1 %s -fcolor-diagnostics 2>&1 \
+! RUN: | FileCheck %s --check-prefix=CHECK_CD
+! RUN: not %flang_fc1 %s 2>&1 | FileCheck %s --check-prefix=CHECK_NCD
+
+! CHECK_CD: {{.*}}[0;1;31merror: {{.*}}[0mMust be a constant value
+
+! CHECK_NCD: error: Must be a constant value
+
+program m
+ integer :: i = k
+end
parsing.messages().Emit(llvm::errs(), parsing.allCooked());
if (!parsing.consumedWholeFile()) {
parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
- "parser FAIL (final position)");
+ "parser FAIL (final position)",
+ "error: ", llvm::raw_ostream::RED);
return mlir::failure();
}
if ((!parsing.messages().empty() && (parsing.messages().AnyFatalError())) ||
parsing.messages().Emit(llvm::errs(), parsing.allCooked());
if (!parsing.consumedWholeFile()) {
parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
- "parser FAIL (final position)");
+ "parser FAIL (final position)", "error: ", llvm::raw_ostream::RED);
exitStatus = EXIT_FAILURE;
return {};
}