Skip to content

[flang][CLI] Have the CLI hint the flag to disable a warning #144767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions flang/include/flang/Parser/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@ class Message : public common::ReferenceCounted<Message> {
std::optional<ProvenanceRange> GetProvenanceRange(
const AllCookedSources &) const;
void Emit(llvm::raw_ostream &, const AllCookedSources &,
bool echoSourceLine = true) const;
bool echoSourceLine = true,
const common::LanguageFeatureControl *hintFlags = nullptr) const;

// If this Message or any of its attachments locates itself via a CharBlock,
// replace its location with the corresponding ProvenanceRange.
Expand Down Expand Up @@ -352,7 +353,8 @@ class Messages {
void Copy(const Messages &);
void ResolveProvenances(const AllCookedSources &);
void Emit(llvm::raw_ostream &, const AllCookedSources &,
bool echoSourceLines = true) const;
bool echoSourceLines = true,
const common::LanguageFeatureControl *hintFlags = nullptr) const;
void AttachTo(Message &, std::optional<Severity> = std::nullopt);
bool AnyFatalError() const;

Expand Down
7 changes: 3 additions & 4 deletions flang/include/flang/Support/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,13 @@ class LanguageFeatureControl {
private:
// Map from Cli syntax of language features and usage warnings to their enum
// values.
std::unordered_map<std::string, std::variant<LanguageFeature, UsageWarning>>
cliOptions_;
std::unordered_map<std::string, LanguageFeatureOrWarning> cliOptions_;
// These two arrays map the enum values to their cannonical Cli spellings.
// Since each of the CanonicalSpelling is a string in the domain of the map
// above we just use a view of the string instead of another copy.
std::array<std::string_view, LanguageFeature_enumSize>
std::array<std::string, LanguageFeature_enumSize>
languageFeatureCliCanonicalSpelling_;
std::array<std::string_view, UsageWarning_enumSize>
std::array<std::string, UsageWarning_enumSize>
usageWarningCliCanonicalSpelling_;
LanguageFeatures disable_;
LanguageFeatures warnLanguage_;
Expand Down
13 changes: 10 additions & 3 deletions flang/lib/Frontend/FrontendAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ bool FrontendAction::runParse(bool emitMessages) {
if (emitMessages) {
// Report any non-fatal diagnostics from getParsing now rather than
// combining them with messages from semantics.
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
const common::LanguageFeatureControl &features{
ci.getInvocation().getFortranOpts().features};
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources(),
/*echoSourceLine=*/true, &features);
}
return true;
}
Expand Down Expand Up @@ -223,14 +226,17 @@ bool FrontendAction::generateRtTypeTables() {

template <unsigned N>
bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
const common::LanguageFeatureControl &features{
instance->getInvocation().getFortranOpts().features};
if (!instance->getParsing().messages().empty() &&
(instance->getInvocation().getWarnAsErr() ||
instance->getParsing().messages().AnyFatalError())) {
const unsigned diagID = instance->getDiagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, message);
instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
instance->getParsing().messages().Emit(llvm::errs(),
instance->getAllCookedSources());
instance->getAllCookedSources(),
/*echoSourceLines=*/true, &features);
return true;
}
if (instance->getParsing().parseTree().has_value() &&
Expand All @@ -240,7 +246,8 @@ bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
clang::DiagnosticsEngine::Error, message);
instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
instance->getParsing().messages().Emit(llvm::errs(),
instance->getAllCookedSources());
instance->getAllCookedSources(),
/*echoSourceLine=*/true, &features);
instance->getParsing().EmitMessage(
llvm::errs(), instance->getParsing().finalRestingPlace(),
"parser FAIL (final position)", "error: ", llvm::raw_ostream::RED);
Expand Down
31 changes: 27 additions & 4 deletions flang/lib/Parser/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,36 @@ static llvm::raw_ostream::Colors PrefixColor(Severity severity) {
return llvm::raw_ostream::SAVEDCOLOR;
}

static std::string HintLanguageControlFlag(
const common::LanguageFeatureControl *hintFlagPtr,
std::optional<common::LanguageFeature> feature,
std::optional<common::UsageWarning> warning) {
if (hintFlagPtr) {
std::string flag;
if (warning) {
flag = hintFlagPtr->getDefaultCliSpelling(*warning);
} else if (feature) {
flag = hintFlagPtr->getDefaultCliSpelling(*feature);
}
if (!flag.empty()) {
return " [-W" + flag + "]";
}
}
return "";
}

static constexpr int MAX_CONTEXTS_EMITTED{2};
static constexpr bool OMIT_SHARED_CONTEXTS{true};

void Message::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
bool echoSourceLine) const {
bool echoSourceLine,
const common::LanguageFeatureControl *hintFlagPtr) const {
std::optional<ProvenanceRange> provenanceRange{GetProvenanceRange(allCooked)};
const AllSources &sources{allCooked.allSources()};
sources.EmitMessage(o, provenanceRange, ToString(), Prefix(severity()),
const std::string text{ToString()};
const std::string hint{
HintLanguageControlFlag(hintFlagPtr, languageFeature_, usageWarning_)};
sources.EmitMessage(o, provenanceRange, text + hint, Prefix(severity()),
PrefixColor(severity()), echoSourceLine);
// Refers to whether the attachment in the loop below is a context, but can't
// be declared inside the loop because the previous iteration's
Expand Down Expand Up @@ -430,7 +452,8 @@ void Messages::ResolveProvenances(const AllCookedSources &allCooked) {
}

void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
bool echoSourceLines) const {
bool echoSourceLines,
const common::LanguageFeatureControl *hintFlagPtr) const {
std::vector<const Message *> sorted;
for (const auto &msg : messages_) {
sorted.push_back(&msg);
Expand All @@ -443,7 +466,7 @@ void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
// Don't emit two identical messages for the same location
continue;
}
msg->Emit(o, allCooked, echoSourceLines);
msg->Emit(o, allCooked, echoSourceLines, hintFlagPtr);
lastMsg = msg;
}
}
Expand Down
4 changes: 3 additions & 1 deletion flang/lib/Semantics/semantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,10 @@ bool Semantics::Perform() {
void Semantics::EmitMessages(llvm::raw_ostream &os) {
// Resolve the CharBlock locations of the Messages to ProvenanceRanges
// so messages from parsing and semantics are intermixed in source order.
const common::LanguageFeatureControl &features{context_.languageFeatures()};
context_.messages().ResolveProvenances(context_.allCookedSources());
context_.messages().Emit(os, context_.allCookedSources());
context_.messages().Emit(
os, context_.allCookedSources(), /*echoSourceLine=*/true, &features);
}

void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {
Expand Down
14 changes: 6 additions & 8 deletions flang/lib/Support/Fortran-features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ LanguageFeatureControl::LanguageFeatureControl() {
std::string cliOption{details::CamelCaseToLowerCaseHyphenated(name)};
cliOptions_.insert({cliOption, {feature}});
languageFeatureCliCanonicalSpelling_[EnumToInt(feature)] =
std::string_view{cliOption};
std::move(cliOption);
});

ForEachUsageWarning([&](auto warning) {
std::string_view name{Fortran::common::EnumToString(warning)};
std::string cliOption{details::CamelCaseToLowerCaseHyphenated(name)};
cliOptions_.insert({cliOption, {warning}});
usageWarningCliCanonicalSpelling_[EnumToInt(warning)] =
std::string_view{cliOption};
std::move(cliOption);
});

// These features must be explicitly enabled by command line options.
Expand Down Expand Up @@ -174,18 +174,16 @@ bool LanguageFeatureControl::EnableWarning(std::string_view input) {

void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
LanguageFeature f, std::string input) {
std::string_view &old{languageFeatureCliCanonicalSpelling_[EnumToInt(f)]};
cliOptions_.erase(std::string{old});
languageFeatureCliCanonicalSpelling_[EnumToInt(f)] = input;
cliOptions_.erase(languageFeatureCliCanonicalSpelling_[EnumToInt(f)]);
cliOptions_.insert({input, {f}});
languageFeatureCliCanonicalSpelling_[EnumToInt(f)] = std::move(input);
}

void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
UsageWarning w, std::string input) {
std::string_view &old{usageWarningCliCanonicalSpelling_[EnumToInt(w)]};
cliOptions_.erase(std::string{old});
usageWarningCliCanonicalSpelling_[EnumToInt(w)] = input;
cliOptions_.erase(usageWarningCliCanonicalSpelling_[EnumToInt(w)]);
cliOptions_.insert({input, {w}});
usageWarningCliCanonicalSpelling_[EnumToInt(w)] = std::move(input);
}

std::vector<const char *> LanguageFeatureControl::GetNames(
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Evaluate/fold-dim.f90
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module m
logical, parameter :: test_a3 = dim(2., 1.) == 1.
logical, parameter :: test_a4 = dim(2., -1.) == 3.
logical, parameter :: test_a5 = dim(-1., 2.) == 0.
!WARN: warning: invalid argument on division
!WARN: warning: invalid argument on division [-Wfolding-exception]
real, parameter :: nan = 0./0.
logical, parameter :: test_a6 = dim(nan, 1.) /= dim(nan, 1.)
end module
22 changes: 11 additions & 11 deletions flang/test/Evaluate/fold-nearest.f90
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ module m1
real, parameter :: negZero = sign(0., -1.)
logical, parameter :: test_12 = nearest(negZero, 1.) == minSubnormal
logical, parameter :: test_13 = nearest(negZero, -1.) == -minSubnormal
!WARN: warning: NEAREST: S argument is zero
!WARN: warning: NEAREST: S argument is zero [-Wfolding-value-checks]
logical, parameter :: test_14 = nearest(0., negZero) == -minSubnormal
!WARN: warning: NEAREST: S argument is zero
!WARN: warning: NEAREST: S argument is zero [-Wfolding-value-checks]
logical, parameter :: test_15 = nearest(negZero, 0.) == minSubnormal
logical, parameter :: test_16 = nearest(tiny(1.),-1.) == 1.1754942E-38
logical, parameter :: test_17 = nearest(tiny(1.),1.) == 1.1754945E-38
contains
subroutine subr(a)
real, intent(in) :: a
!WARN: warning: NEAREST: S argument is zero
!WARN: warning: NEAREST: S argument is zero [-Wfolding-value-checks]
print *, nearest(a, 0.)
end
end module
Expand All @@ -42,7 +42,7 @@ module m2
logical, parameter :: test_2 = ieee_next_after(minSubnormal, -1.) == 0
logical, parameter :: test_3 = ieee_next_after(1., 2.) == 1.0000001
logical, parameter :: test_4 = ieee_next_after(1.0000001, -1.) == 1
!WARN: warning: division by zero
!WARN: warning: division by zero [-Wfolding-exception]
real, parameter :: inf = 1. / 0.
logical, parameter :: test_5 = ieee_next_after(inf, inf) == inf
logical, parameter :: test_6 = ieee_next_after(inf, -inf) == h
Expand All @@ -54,12 +54,12 @@ module m2
logical, parameter :: test_11 = ieee_next_after(1.9999999999999999999_10, 3.) == 2._10
#endif
logical, parameter :: test_12 = ieee_next_after(1., 1.) == 1.
!WARN: warning: invalid argument on division
!WARN: warning: invalid argument on division [-Wfolding-exception]
real, parameter :: nan = 0. / 0.
!WARN: warning: IEEE_NEXT_AFTER intrinsic folding: arguments are unordered
!WARN: warning: IEEE_NEXT_AFTER intrinsic folding: arguments are unordered [-Wfolding-value-checks]
real, parameter :: x13 = ieee_next_after(nan, nan)
logical, parameter :: test_13 = .not. (x13 == x13)
!WARN: warning: IEEE_NEXT_AFTER intrinsic folding: arguments are unordered
!WARN: warning: IEEE_NEXT_AFTER intrinsic folding: arguments are unordered [-Wfolding-value-checks]
real, parameter :: x14 = ieee_next_after(nan, 0.)
logical, parameter :: test_14 = .not. (x14 == x14)
end module
Expand All @@ -72,7 +72,7 @@ module m3
logical, parameter :: test_2 = ieee_next_down(0.d0) == -minSubnormal
logical, parameter :: test_3 = ieee_next_up(1.d0) == 1.0000000000000002d0
logical, parameter :: test_4 = ieee_next_down(1.0000000000000002d0) == 1.d0
!WARN: warning: division by zero
!WARN: warning: division by zero [-Wfolding-exception]
real(kind(0.d0)), parameter :: inf = 1.d0 / 0.d0
logical, parameter :: test_5 = ieee_next_up(huge(0.d0)) == inf
logical, parameter :: test_6 = ieee_next_down(-huge(0.d0)) == -inf
Expand All @@ -82,12 +82,12 @@ module m3
logical, parameter :: test_10 = ieee_next_down(-inf) == -inf
logical, parameter :: test_11 = ieee_next_up(1.9999999999999997d0) == 2.d0
logical, parameter :: test_12 = ieee_next_down(2.d0) == 1.9999999999999997d0
!WARN: warning: invalid argument on division
!WARN: warning: invalid argument on division [-Wfolding-exception]
real(kind(0.d0)), parameter :: nan = 0.d0 / 0.d0
!WARN: warning: IEEE_NEXT_UP intrinsic folding: argument is NaN
!WARN: warning: IEEE_NEXT_UP intrinsic folding: argument is NaN [-Wfolding-exception]
real(kind(0.d0)), parameter :: x13 = ieee_next_up(nan)
logical, parameter :: test_13 = .not. (x13 == x13)
!WARN: warning: IEEE_NEXT_DOWN intrinsic folding: argument is NaN
!WARN: warning: IEEE_NEXT_DOWN intrinsic folding: argument is NaN [-Wfolding-exception]
real(kind(0.d0)), parameter :: x14 = ieee_next_down(nan)
logical, parameter :: test_14 = .not. (x14 == x14)
end module
Expand Down
Loading