[flang-commits] [flang] [flang][warnings] systematically guard warnings (PR #154234)
Andre Kuhlenschmidt via flang-commits
flang-commits at lists.llvm.org
Thu Aug 21 14:54:28 PDT 2025
https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/154234
>From a6cb61bb88263487d6147bd7a30457e69ecfa905 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Mon, 18 Aug 2025 16:32:50 -0700
Subject: [PATCH 1/3] initial commit
---
flang/include/flang/Evaluate/common.h | 10 ++
flang/include/flang/Evaluate/tools.h | 12 ++
flang/include/flang/Parser/message.h | 82 +++++++---
flang/include/flang/Semantics/semantics.h | 65 ++++++--
flang/lib/Evaluate/check-expression.cpp | 27 ++--
flang/lib/Evaluate/common.cpp | 32 ++--
flang/lib/Evaluate/fold-character.cpp | 20 +--
flang/lib/Evaluate/fold-complex.cpp | 5 +-
flang/lib/Evaluate/fold-implementation.h | 109 +++++---------
flang/lib/Evaluate/fold-integer.cpp | 106 +++++--------
flang/lib/Evaluate/fold-logical.cpp | 10 +-
flang/lib/Evaluate/fold-matmul.h | 6 +-
flang/lib/Evaluate/fold-real.cpp | 129 ++++++----------
flang/lib/Evaluate/fold-reduction.h | 18 +--
flang/lib/Evaluate/fold.cpp | 7 +-
flang/lib/Evaluate/host.cpp | 9 +-
flang/lib/Evaluate/intrinsics.cpp | 85 ++++-------
flang/lib/Evaluate/variable.cpp | 18 +--
flang/lib/Parser/preprocessor.cpp | 51 +++----
flang/lib/Parser/prescan.h | 9 ++
flang/lib/Semantics/check-call.cpp | 165 +++++++++------------
flang/lib/Semantics/check-declarations.cpp | 44 +++---
flang/test/Semantics/spec-expr.f90 | 4 +-
23 files changed, 450 insertions(+), 573 deletions(-)
diff --git a/flang/include/flang/Evaluate/common.h b/flang/include/flang/Evaluate/common.h
index fbfe411ebc977..26bb0da9b8be3 100644
--- a/flang/include/flang/Evaluate/common.h
+++ b/flang/include/flang/Evaluate/common.h
@@ -255,6 +255,16 @@ class FoldingContext {
const common::LanguageFeatureControl &languageFeatures() const {
return languageFeatures_;
}
+ template <typename... A>
+ parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
+ return messages_.Warn(/*isInModuleFile=*/false, languageFeatures_, feature,
+ std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(common::UsageWarning warning, A &&...args) {
+ return messages_.Warn(/*isInModuleFile=*/false, languageFeatures_, warning,
+ std::forward<A>(args)...);
+ }
std::optional<parser::CharBlock> moduleFileName() const {
return moduleFileName_;
}
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 212356136d6ee..2ae25529842ad 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1136,6 +1136,18 @@ parser::Message *SayWithDeclaration(
MESSAGES &messages, const Symbol &symbol, A &&...x) {
return AttachDeclaration(messages.Say(std::forward<A>(x)...), symbol);
}
+template <typename... A>
+parser::Message *WarnWithDeclaration(FoldingContext context,
+ const Symbol &symbol, common::LanguageFeature feature, A &&...x) {
+ return AttachDeclaration(
+ context.Warn(feature, std::forward<A>(x)...), symbol);
+}
+template <typename... A>
+parser::Message *WarnWithDeclaration(FoldingContext &context,
+ const Symbol &symbol, common::UsageWarning warning, A &&...x) {
+ return AttachDeclaration(
+ context.Warn(warning, std::forward<A>(x)...), symbol);
+}
// Check for references to impure procedures; returns the name
// of one to complain about, if any exist.
diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h
index 9192d23529913..46aec5bb3dc12 100644
--- a/flang/include/flang/Parser/message.h
+++ b/flang/include/flang/Parser/message.h
@@ -19,6 +19,7 @@
#include "flang/Common/reference-counted.h"
#include "flang/Common/restorer.h"
#include "flang/Support/Fortran-features.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstddef>
#include <cstring>
#include <forward_list>
@@ -334,14 +335,36 @@ class Messages {
return messages_.emplace_back(std::forward<A>(args)...);
}
+ // AddWarning bypasses the language feature control, it is only exposed for
+ // legacy code that cannot be easily refactored to use Warn().
template <typename... A>
- Message &Say(common::LanguageFeature feature, A &&...args) {
- return Say(std::forward<A>(args)...).set_languageFeature(feature);
+ Message &AddWarning(common::UsageWarning warning, A &&...args) {
+ return messages_.emplace_back(warning, std::forward<A>(args)...);
}
template <typename... A>
- Message &Say(common::UsageWarning warning, A &&...args) {
- return Say(std::forward<A>(args)...).set_usageWarning(warning);
+ Message &AddWarning(common::LanguageFeature feature, A &&...args) {
+ return messages_.emplace_back(feature, std::forward<A>(args)...);
+ }
+
+ template <typename... A>
+ Message *Warn(bool isInModuleFile,
+ const common::LanguageFeatureControl &control,
+ common::LanguageFeature feature, A &&...args) {
+ if (!isInModuleFile && control.ShouldWarn(feature)) {
+ return &AddWarning(feature, std::forward<A>(args)...);
+ }
+ return nullptr;
+ }
+
+ template <typename... A>
+ Message *Warn(bool isInModuleFile,
+ const common::LanguageFeatureControl &control,
+ common::UsageWarning warning, A &&...args) {
+ if (!isInModuleFile && control.ShouldWarn(warning)) {
+ return &AddWarning(warning, std::forward<A>(args)...);
+ }
+ return nullptr;
}
void Annex(Messages &&that) {
@@ -422,24 +445,6 @@ class ContextualMessages {
return Say(at.value_or(at_), std::forward<A>(args)...);
}
- template <typename... A>
- Message *Say(common::LanguageFeature feature, A &&...args) {
- Message *msg{Say(std::forward<A>(args)...)};
- if (msg) {
- msg->set_languageFeature(feature);
- }
- return msg;
- }
-
- template <typename... A>
- Message *Say(common::UsageWarning warning, A &&...args) {
- Message *msg{Say(std::forward<A>(args)...)};
- if (msg) {
- msg->set_usageWarning(warning);
- }
- return msg;
- }
-
Message *Say(Message &&msg) {
if (messages_ != nullptr) {
if (contextMessage_) {
@@ -451,6 +456,39 @@ class ContextualMessages {
}
}
+ template <typename FeatureOrUsageWarning, typename... A>
+ Message *Warn(bool isInModuleFile,
+ const common::LanguageFeatureControl &control,
+ FeatureOrUsageWarning feature, CharBlock at, A &&...args) {
+ if (messages_ != nullptr) {
+ if (Message *
+ msg{messages_->Warn(isInModuleFile, control, feature, at,
+ std::forward<A>(args)...)}) {
+ if (contextMessage_) {
+ msg->SetContext(contextMessage_.get());
+ }
+ return msg;
+ }
+ }
+ return nullptr;
+ }
+
+ template <typename FeatureOrUsageWarning, typename... A>
+ Message *Warn(bool isInModuleFile,
+ const common::LanguageFeatureControl &control,
+ FeatureOrUsageWarning feature, A &&...args) {
+ return Warn(
+ isInModuleFile, control, feature, at_, std::forward<A>(args)...);
+ }
+
+ template <typename FeatureOrUsageWarning, typename... A>
+ Message *Warn(bool isInModuleFile,
+ const common::LanguageFeatureControl &control,
+ FeatureOrUsageWarning feature, std::optional<CharBlock> at, A &&...args) {
+ return Warn(isInModuleFile, control, feature, at.value_or(at_),
+ std::forward<A>(args)...);
+ }
+
private:
CharBlock at_;
Messages *messages_{nullptr};
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index 12220cc7f0edd..f7910ad38a19d 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -200,20 +200,59 @@ class SemanticsContext {
return message;
}
- template <typename FeatureOrUsageWarning, typename... A>
+ template <typename... A>
+ parser::Message *Warn(parser::Messages &messages,
+ common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
+ return messages.Warn(IsInModuleFile(at), languageFeatures_, feature, at,
+ std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(parser::Messages &messages,
+ common::UsageWarning warning, parser::CharBlock at, A &&...args) {
+ return messages.Warn(IsInModuleFile(at), languageFeatures_, warning, at,
+ std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(parser::ContextualMessages &messages,
+ common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
+ return messages.Warn(IsInModuleFile(at), languageFeatures_, feature, at,
+ std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(parser::ContextualMessages &messages,
+ common::UsageWarning warning, parser::CharBlock at, A &&...args) {
+ return messages.Warn(IsInModuleFile(at), languageFeatures_, warning, at,
+ std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(parser::ContextualMessages &messages,
+ common::LanguageFeature feature, A &&...args) {
+ return messages.Warn(IsInModuleFile(messages.at()), languageFeatures_,
+ feature, messages.at(), std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(parser::ContextualMessages &messages,
+ common::UsageWarning warning, A &&...args) {
+ return messages.Warn(IsInModuleFile(messages.at()), languageFeatures_,
+ warning, messages.at(), std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(
+ common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
+ return Warn(messages_, feature, at, std::forward<A>(args)...);
+ }
+ template <typename... A>
parser::Message *Warn(
- FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
- if (languageFeatures_.ShouldWarn(warning) && !IsInModuleFile(at)) {
- parser::Message &msg{
- messages_.Say(warning, at, std::forward<A>(args)...)};
- return &msg;
- } else {
- return nullptr;
- }
- }
-
- template <typename FeatureOrUsageWarning, typename... A>
- parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
+ common::UsageWarning warning, parser::CharBlock at, A &&...args) {
+ return Warn(messages_, warning, at, std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
+ CHECK(location_);
+ return Warn(feature, *location_, std::forward<A>(args)...);
+ }
+ template <typename... A>
+ parser::Message *Warn(common::UsageWarning warning, A &&...args) {
CHECK(location_);
return Warn(warning, *location_, std::forward<A>(args)...);
}
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 522ab1980f4ee..a88d4cd03a5a5 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -415,7 +415,7 @@ class SuspiciousRealLiteralFinder
template <int KIND>
bool operator()(const Constant<Type<TypeCategory::Real, KIND>> &x) const {
if (kind_ > KIND && x.result().isFromInexactLiteralConversion()) {
- context_.messages().Say(common::UsageWarning::RealConstantWidening,
+ context_.Warn(common::UsageWarning::RealConstantWidening,
"Default real literal in REAL(%d) context might need a kind suffix, as its rounded value %s is inexact"_warn_en_US,
kind_, x.AsFortran());
return true;
@@ -426,7 +426,7 @@ class SuspiciousRealLiteralFinder
template <int KIND>
bool operator()(const Constant<Type<TypeCategory::Complex, KIND>> &x) const {
if (kind_ > KIND && x.result().isFromInexactLiteralConversion()) {
- context_.messages().Say(common::UsageWarning::RealConstantWidening,
+ context_.Warn(common::UsageWarning::RealConstantWidening,
"Default real literal in COMPLEX(%d) context might need a kind suffix, as its rounded value %s is inexact"_warn_en_US,
kind_, x.AsFortran());
return true;
@@ -504,11 +504,8 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
symbol.owner().context().IsEnabled(
common::LanguageFeature::LogicalIntegerAssignment)) {
converted = DataConstantConversionExtension(context, symTS->type(), x);
- if (converted &&
- symbol.owner().context().ShouldWarn(
- common::LanguageFeature::LogicalIntegerAssignment)) {
- context.messages().Say(
- common::LanguageFeature::LogicalIntegerAssignment,
+ if (converted) {
+ context.Warn(common::LanguageFeature::LogicalIntegerAssignment,
"nonstandard usage: initialization of %s with %s"_port_en_US,
symTS->type().AsFortran(), x.GetType().value().AsFortran());
}
@@ -663,10 +660,8 @@ class CheckSpecificationExprHelper
// host-associated dummy argument, and that doesn't seem like a
// good idea.
if (!inInquiry_ && hasHostAssociation &&
- ultimate.attrs().test(semantics::Attr::INTENT_OUT) &&
- context_.languageFeatures().ShouldWarn(
- common::UsageWarning::HostAssociatedIntentOutInSpecExpr)) {
- context_.messages().Say(
+ ultimate.attrs().test(semantics::Attr::INTENT_OUT)) {
+ context_.Warn(common::UsageWarning::HostAssociatedIntentOutInSpecExpr,
"specification expression refers to host-associated INTENT(OUT) dummy argument '%s'"_port_en_US,
ultimate.name());
}
@@ -677,13 +672,9 @@ class CheckSpecificationExprHelper
} else if (isInitialized &&
context_.languageFeatures().IsEnabled(
common::LanguageFeature::SavedLocalInSpecExpr)) {
- if (!scope_.IsModuleFile() &&
- context_.languageFeatures().ShouldWarn(
- common::LanguageFeature::SavedLocalInSpecExpr)) {
- context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
- "specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
- ultimate.name());
- }
+ context_.Warn(common::LanguageFeature::SavedLocalInSpecExpr,
+ "specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
+ ultimate.name());
return std::nullopt;
} else if (const auto *object{
ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
diff --git a/flang/lib/Evaluate/common.cpp b/flang/lib/Evaluate/common.cpp
index 6a960d46166e9..46c75a5c2ee44 100644
--- a/flang/lib/Evaluate/common.cpp
+++ b/flang/lib/Evaluate/common.cpp
@@ -16,26 +16,22 @@ namespace Fortran::evaluate {
void RealFlagWarnings(
FoldingContext &context, const RealFlags &flags, const char *operation) {
static constexpr auto warning{common::UsageWarning::FoldingException};
- if (context.languageFeatures().ShouldWarn(warning)) {
- if (flags.test(RealFlag::Overflow)) {
- context.messages().Say(warning, "overflow on %s"_warn_en_US, operation);
- }
- if (flags.test(RealFlag::DivideByZero)) {
- if (std::strcmp(operation, "division") == 0) {
- context.messages().Say(warning, "division by zero"_warn_en_US);
- } else {
- context.messages().Say(
- warning, "division by zero on %s"_warn_en_US, operation);
- }
- }
- if (flags.test(RealFlag::InvalidArgument)) {
- context.messages().Say(
- warning, "invalid argument on %s"_warn_en_US, operation);
- }
- if (flags.test(RealFlag::Underflow)) {
- context.messages().Say(warning, "underflow on %s"_warn_en_US, operation);
+ if (flags.test(RealFlag::Overflow)) {
+ context.Warn(warning, "overflow on %s"_warn_en_US, operation);
+ }
+ if (flags.test(RealFlag::DivideByZero)) {
+ if (std::strcmp(operation, "division") == 0) {
+ context.Warn(warning, "division by zero"_warn_en_US);
+ } else {
+ context.Warn(warning, "division by zero on %s"_warn_en_US, operation);
}
}
+ if (flags.test(RealFlag::InvalidArgument)) {
+ context.Warn(warning, "invalid argument on %s"_warn_en_US, operation);
+ }
+ if (flags.test(RealFlag::Underflow)) {
+ context.Warn(warning, "underflow on %s"_warn_en_US, operation);
+ }
}
ConstantSubscript &FoldingContext::StartImpliedDo(
diff --git a/flang/lib/Evaluate/fold-character.cpp b/flang/lib/Evaluate/fold-character.cpp
index 76ac497e16646..a43742ae8dc68 100644
--- a/flang/lib/Evaluate/fold-character.cpp
+++ b/flang/lib/Evaluate/fold-character.cpp
@@ -58,13 +58,10 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
return FoldElementalIntrinsic<T, IntT>(context, std::move(funcRef),
ScalarFunc<T, IntT>([&](const Scalar<IntT> &i) {
if (i.IsNegative() || i.BGE(Scalar<IntT>{0}.IBSET(8 * KIND))) {
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingValueChecks)) {
- context.messages().Say(common::UsageWarning::FoldingValueChecks,
- "%s(I=%jd) is out of range for CHARACTER(KIND=%d)"_warn_en_US,
- parser::ToUpperCaseLetters(name),
- static_cast<std::intmax_t>(i.ToInt64()), KIND);
- }
+ context.Warn(common::UsageWarning::FoldingValueChecks,
+ "%s(I=%jd) is out of range for CHARACTER(KIND=%d)"_warn_en_US,
+ parser::ToUpperCaseLetters(name),
+ static_cast<std::intmax_t>(i.ToInt64()), KIND);
}
return CharacterUtils<KIND>::CHAR(i.ToUInt64());
}));
@@ -106,12 +103,9 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
static_cast<std::intmax_t>(n));
} else if (static_cast<double>(n) * str.size() >
(1 << 20)) { // sanity limit of 1MiB
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingLimit)) {
- context.messages().Say(common::UsageWarning::FoldingLimit,
- "Result of REPEAT() is too large to compute at compilation time (%g characters)"_port_en_US,
- static_cast<double>(n) * str.size());
- }
+ context.Warn(common::UsageWarning::FoldingLimit,
+ "Result of REPEAT() is too large to compute at compilation time (%g characters)"_port_en_US,
+ static_cast<double>(n) * str.size());
} else {
return Expr<T>{Constant<T>{CharacterUtils<KIND>::REPEAT(str, n)}};
}
diff --git a/flang/lib/Evaluate/fold-complex.cpp b/flang/lib/Evaluate/fold-complex.cpp
index bcaede5536260..84066ee5be71b 100644
--- a/flang/lib/Evaluate/fold-complex.cpp
+++ b/flang/lib/Evaluate/fold-complex.cpp
@@ -29,9 +29,8 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldIntrinsicFunction(
if (auto callable{GetHostRuntimeWrapper<T, T>(name)}) {
return FoldElementalIntrinsic<T, T>(
context, std::move(funcRef), *callable);
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
+ } else {
+ context.Warn(common::UsageWarning::FoldingFailure,
"%s(complex(kind=%d)) cannot be folded on host"_warn_en_US, name,
KIND);
}
diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h
index 7c80d76784463..d757ef6e62eb4 100644
--- a/flang/lib/Evaluate/fold-implementation.h
+++ b/flang/lib/Evaluate/fold-implementation.h
@@ -1814,10 +1814,8 @@ Expr<TO> FoldOperation(
if constexpr (TO::category == TypeCategory::Integer) {
if constexpr (FromCat == TypeCategory::Integer) {
auto converted{Scalar<TO>::ConvertSigned(*value)};
- if (converted.overflow &&
- msvcWorkaround.context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- ctx.messages().Say(common::UsageWarning::FoldingException,
+ if (converted.overflow) {
+ ctx.Warn(common::UsageWarning::FoldingException,
"conversion of %s_%d to INTEGER(%d) overflowed; result is %s"_warn_en_US,
value->SignedDecimal(), Operand::kind, TO::kind,
converted.value.SignedDecimal());
@@ -1825,10 +1823,8 @@ Expr<TO> FoldOperation(
return ScalarConstantToExpr(std::move(converted.value));
} else if constexpr (FromCat == TypeCategory::Unsigned) {
auto converted{Scalar<TO>::ConvertUnsigned(*value)};
- if ((converted.overflow || converted.value.IsNegative()) &&
- msvcWorkaround.context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- ctx.messages().Say(common::UsageWarning::FoldingException,
+ if ((converted.overflow || converted.value.IsNegative())) {
+ ctx.Warn(common::UsageWarning::FoldingException,
"conversion of %s_U%d to INTEGER(%d) overflowed; result is %s"_warn_en_US,
value->UnsignedDecimal(), Operand::kind, TO::kind,
converted.value.SignedDecimal());
@@ -1836,17 +1832,14 @@ Expr<TO> FoldOperation(
return ScalarConstantToExpr(std::move(converted.value));
} else if constexpr (FromCat == TypeCategory::Real) {
auto converted{value->template ToInteger<Scalar<TO>>()};
- if (msvcWorkaround.context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- if (converted.flags.test(RealFlag::InvalidArgument)) {
- ctx.messages().Say(common::UsageWarning::FoldingException,
- "REAL(%d) to INTEGER(%d) conversion: invalid argument"_warn_en_US,
- Operand::kind, TO::kind);
- } else if (converted.flags.test(RealFlag::Overflow)) {
- ctx.messages().Say(
- "REAL(%d) to INTEGER(%d) conversion overflowed"_warn_en_US,
- Operand::kind, TO::kind);
- }
+ if (converted.flags.test(RealFlag::InvalidArgument)) {
+ ctx.Warn(common::UsageWarning::FoldingException,
+ "REAL(%d) to INTEGER(%d) conversion: invalid argument"_warn_en_US,
+ Operand::kind, TO::kind);
+ } else if (converted.flags.test(RealFlag::Overflow)) {
+ ctx.Warn(common::UsageWarning::FoldingException,
+ "REAL(%d) to INTEGER(%d) conversion overflowed"_warn_en_US,
+ Operand::kind, TO::kind);
}
return ScalarConstantToExpr(std::move(converted.value));
}
@@ -1966,10 +1959,8 @@ Expr<T> FoldOperation(FoldingContext &context, Negate<T> &&x) {
} else if (auto value{GetScalarConstantValue<T>(operand)}) {
if constexpr (T::category == TypeCategory::Integer) {
auto negated{value->Negate()};
- if (negated.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (negated.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"INTEGER(%d) negation overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{std::move(negated.value)}};
@@ -2010,10 +2001,8 @@ Expr<T> FoldOperation(FoldingContext &context, Add<T> &&x) {
if (auto folded{OperandsAreConstants(x)}) {
if constexpr (T::category == TypeCategory::Integer) {
auto sum{folded->first.AddSigned(folded->second)};
- if (sum.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (sum.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"INTEGER(%d) addition overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{sum.value}};
@@ -2041,10 +2030,8 @@ Expr<T> FoldOperation(FoldingContext &context, Subtract<T> &&x) {
if (auto folded{OperandsAreConstants(x)}) {
if constexpr (T::category == TypeCategory::Integer) {
auto difference{folded->first.SubtractSigned(folded->second)};
- if (difference.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (difference.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"INTEGER(%d) subtraction overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{difference.value}};
@@ -2072,10 +2059,8 @@ Expr<T> FoldOperation(FoldingContext &context, Multiply<T> &&x) {
if (auto folded{OperandsAreConstants(x)}) {
if constexpr (T::category == TypeCategory::Integer) {
auto product{folded->first.MultiplySigned(folded->second)};
- if (product.SignedMultiplicationOverflowed() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (product.SignedMultiplicationOverflowed()) {
+ context.Warn(common::UsageWarning::FoldingException,
"INTEGER(%d) multiplication overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{product.lower}};
@@ -2122,28 +2107,20 @@ Expr<T> FoldOperation(FoldingContext &context, Divide<T> &&x) {
if constexpr (T::category == TypeCategory::Integer) {
auto quotAndRem{folded->first.DivideSigned(folded->second)};
if (quotAndRem.divisionByZero) {
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
- "INTEGER(%d) division by zero"_warn_en_US, T::kind);
- }
+ context.Warn(common::UsageWarning::FoldingException,
+ "INTEGER(%d) division by zero"_warn_en_US, T::kind);
return Expr<T>{std::move(x)};
}
- if (quotAndRem.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (quotAndRem.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"INTEGER(%d) division overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{quotAndRem.quotient}};
} else if constexpr (T::category == TypeCategory::Unsigned) {
auto quotAndRem{folded->first.DivideUnsigned(folded->second)};
if (quotAndRem.divisionByZero) {
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
- "UNSIGNED(%d) division by zero"_warn_en_US, T::kind);
- }
+ context.Warn(common::UsageWarning::FoldingException,
+ "UNSIGNED(%d) division by zero"_warn_en_US, T::kind);
return Expr<T>{std::move(x)};
}
return Expr<T>{Constant<T>{quotAndRem.quotient}};
@@ -2183,24 +2160,21 @@ Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
if (auto folded{OperandsAreConstants(x)}) {
if constexpr (T::category == TypeCategory::Integer) {
auto power{folded->first.Power(folded->second)};
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- if (power.divisionByZero) {
- context.messages().Say(common::UsageWarning::FoldingException,
- "INTEGER(%d) zero to negative power"_warn_en_US, T::kind);
- } else if (power.overflow) {
- context.messages().Say(common::UsageWarning::FoldingException,
- "INTEGER(%d) power overflowed"_warn_en_US, T::kind);
- } else if (power.zeroToZero) {
- context.messages().Say(common::UsageWarning::FoldingException,
- "INTEGER(%d) 0**0 is not defined"_warn_en_US, T::kind);
- }
+ if (power.divisionByZero) {
+ context.Warn(common::UsageWarning::FoldingException,
+ "INTEGER(%d) zero to negative power"_warn_en_US, T::kind);
+ } else if (power.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
+ "INTEGER(%d) power overflowed"_warn_en_US, T::kind);
+ } else if (power.zeroToZero) {
+ context.Warn(common::UsageWarning::FoldingException,
+ "INTEGER(%d) 0**0 is not defined"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{power.power}};
} else {
if (folded->first.IsZero()) {
if (folded->second.IsZero()) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ context.Warn(common::UsageWarning::FoldingException,
"REAL/COMPLEX 0**0 is not defined"_warn_en_US);
} else {
return Expr<T>(Constant<T>{folded->first}); // 0. ** nonzero -> 0.
@@ -2208,9 +2182,8 @@ Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
} else if (auto callable{GetHostRuntimeWrapper<T, T, T>("pow")}) {
return Expr<T>{
Constant<T>{(*callable)(context, folded->first, folded->second)}};
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
+ } else {
+ context.Warn(common::UsageWarning::FoldingFailure,
"Power for %s cannot be folded on host"_warn_en_US,
T{}.AsFortran());
}
@@ -2297,10 +2270,8 @@ Expr<Type<TypeCategory::Real, KIND>> ToReal(
CHECK(constant);
Scalar<Result> real{constant->GetScalarValue().value()};
From converted{From::ConvertUnsigned(real.RawBits()).value};
- if (original != converted &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingValueChecks)) { // C1601
- context.messages().Say(common::UsageWarning::FoldingValueChecks,
+ if (original != converted) { // C1601
+ context.Warn(common::UsageWarning::FoldingValueChecks,
"Nonzero bits truncated from BOZ literal constant in REAL intrinsic"_warn_en_US);
}
} else if constexpr (IsNumericCategoryExpr<From>()) {
diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp
index 352dec4bb5ee2..dec8eb1550e01 100644
--- a/flang/lib/Evaluate/fold-integer.cpp
+++ b/flang/lib/Evaluate/fold-integer.cpp
@@ -350,10 +350,8 @@ static Expr<T> FoldCount(FoldingContext &context, FunctionRef<T> &&ref) {
CountAccumulator<T, maskKind> accumulator{arrayAndMask->array};
Constant<T> result{DoReduction<T>(arrayAndMask->array, arrayAndMask->mask,
dim, Scalar<T>{}, accumulator)};
- if (accumulator.overflow() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (accumulator.overflow()) {
+ context.Warn(common::UsageWarning::FoldingException,
"Result of intrinsic function COUNT overflows its result type"_warn_en_US);
}
return Expr<T>{std::move(result)};
@@ -965,10 +963,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
auto FromInt64{[&name, &context](std::int64_t n) {
Scalar<T> result{n};
- if (result.ToInt64() != n &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (result.ToInt64() != n) {
+ context.Warn(common::UsageWarning::FoldingException,
"Result of intrinsic function '%s' (%jd) overflows its result type"_warn_en_US,
name, std::intmax_t{n});
}
@@ -979,10 +975,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
return FoldElementalIntrinsic<T, T>(context, std::move(funcRef),
ScalarFunc<T, T>([&context](const Scalar<T> &i) -> Scalar<T> {
typename Scalar<T>::ValueWithOverflow j{i.ABS()};
- if (j.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (j.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"abs(integer(kind=%d)) folding overflowed"_warn_en_US, KIND);
}
return j.value;
@@ -999,11 +993,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
return FoldElementalIntrinsic<T, TR>(context, std::move(funcRef),
ScalarFunc<T, TR>([&](const Scalar<TR> &x) {
auto y{x.template ToInteger<Scalar<T>>(mode)};
- if (y.flags.test(RealFlag::Overflow) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(
- common::UsageWarning::FoldingException,
+ if (y.flags.test(RealFlag::Overflow)) {
+ context.Warn(common::UsageWarning::FoldingException,
"%s intrinsic folding overflow"_warn_en_US, name);
}
return y.value;
@@ -1029,10 +1020,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T, T>(
[&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
auto result{x.DIM(y)};
- if (result.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (result.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"DIM intrinsic folding overflow"_warn_en_US);
}
return result.value;
@@ -1061,11 +1050,9 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
context.messages().Say(
"Character in intrinsic function %s must have length one"_err_en_US,
name);
- } else if (len.value() > 1 &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::Portability)) {
+ } else if (len.value() > 1) {
// Do not die, this was not checked before
- context.messages().Say(common::UsageWarning::Portability,
+ context.Warn(common::UsageWarning::Portability,
"Character in intrinsic function %s should have length one"_port_en_US,
name);
} else {
@@ -1256,11 +1243,9 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
bool badPConst{false};
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
*pExpr = Fold(context, std::move(*pExpr));
- if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
- pConst->IsZero() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)};
+ pConst && pConst->IsZero()) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MOD: P argument is zero"_warn_en_US);
badPConst = true;
}
@@ -1270,17 +1255,12 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
[badPConst](FoldingContext &context, const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto quotRem{x.DivideSigned(y)};
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- if (!badPConst && quotRem.divisionByZero) {
- context.messages().Say(
- common::UsageWarning::FoldingAvoidsRuntimeCrash,
- "mod() by zero"_warn_en_US);
- } else if (quotRem.overflow) {
- context.messages().Say(
- common::UsageWarning::FoldingAvoidsRuntimeCrash,
- "mod() folding overflowed"_warn_en_US);
- }
+ if (!badPConst && quotRem.divisionByZero) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ "mod() by zero"_warn_en_US);
+ } else if (quotRem.overflow) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ "mod() folding overflowed"_warn_en_US);
}
return quotRem.remainder;
}));
@@ -1288,11 +1268,9 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
bool badPConst{false};
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
*pExpr = Fold(context, std::move(*pExpr));
- if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
- pConst->IsZero() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)};
+ pConst && pConst->IsZero()) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MODULO: P argument is zero"_warn_en_US);
badPConst = true;
}
@@ -1302,10 +1280,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto result{x.MODULO(y)};
- if (!badPConst && result.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (!badPConst && result.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"modulo() folding overflowed"_warn_en_US);
}
return result.value;
@@ -1405,10 +1381,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T, T>([&context](const Scalar<T> &j,
const Scalar<T> &k) -> Scalar<T> {
typename Scalar<T>::ValueWithOverflow result{j.SIGN(k)};
- if (result.overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (result.overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"sign(integer(kind=%d)) folding overflowed"_warn_en_US, KIND);
}
return result.value;
@@ -1465,10 +1439,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
auto realBytes{
context.targetCharacteristics().GetByteSize(TypeCategory::Real,
context.defaults().GetDefaultKind(TypeCategory::Real))};
- if (intBytes != realBytes &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingValueChecks)) {
- context.messages().Say(common::UsageWarning::FoldingValueChecks,
+ if (intBytes != realBytes) {
+ context.Warn(common::UsageWarning::FoldingValueChecks,
*context.moduleFileName(),
"NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined when default INTEGER and REAL are not consistent due to compiler options"_warn_en_US);
}
@@ -1496,11 +1468,9 @@ Expr<Type<TypeCategory::Unsigned, KIND>> FoldIntrinsicFunction(
bool badPConst{false};
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
*pExpr = Fold(context, std::move(*pExpr));
- if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
- pConst->IsZero() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)};
+ pConst && pConst->IsZero()) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"%s: P argument is zero"_warn_en_US, name);
badPConst = true;
}
@@ -1510,13 +1480,9 @@ Expr<Type<TypeCategory::Unsigned, KIND>> FoldIntrinsicFunction(
[badPConst, &name](FoldingContext &context, const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto quotRem{x.DivideUnsigned(y)};
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- if (!badPConst && quotRem.divisionByZero) {
- context.messages().Say(
- common::UsageWarning::FoldingAvoidsRuntimeCrash,
- "%s() by zero"_warn_en_US, name);
- }
+ if (!badPConst && quotRem.divisionByZero) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ "%s() by zero"_warn_en_US, name);
}
return quotRem.remainder;
}));
diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index 6950caf327419..c64f79e06a8ac 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -530,13 +530,11 @@ static Expr<Type<TypeCategory::Logical, KIND>> RewriteOutOfRange(
if (args.size() >= 3) {
// Bounds depend on round= value
if (auto *round{UnwrapExpr<Expr<SomeType>>(args[2])}) {
- if (const Symbol * whole{UnwrapWholeSymbolDataRef(*round)};
- whole && semantics::IsOptional(whole->GetUltimate()) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::OptionalMustBePresent)) {
+ if (const Symbol *whole{UnwrapWholeSymbolDataRef(*round)};
+ whole && semantics::IsOptional(whole->GetUltimate())) {
if (auto source{args[2]->sourceLocation()}) {
- context.messages().Say(
- common::UsageWarning::OptionalMustBePresent, *source,
+ context.Warn(common::UsageWarning::OptionalMustBePresent,
+ *source,
"ROUND= argument to OUT_OF_RANGE() is an optional dummy argument that must be present at execution"_warn_en_US);
}
}
diff --git a/flang/lib/Evaluate/fold-matmul.h b/flang/lib/Evaluate/fold-matmul.h
index 9237d6e313877..ae9221f9ce042 100644
--- a/flang/lib/Evaluate/fold-matmul.h
+++ b/flang/lib/Evaluate/fold-matmul.h
@@ -92,10 +92,8 @@ static Expr<T> FoldMatmul(FoldingContext &context, FunctionRef<T> &&funcRef) {
elements.push_back(sum);
}
}
- if (overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"MATMUL of %s data overflowed during computation"_warn_en_US,
T::AsFortran());
}
diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp
index 6fb5249c8a5e2..225e3402fd1ad 100644
--- a/flang/lib/Evaluate/fold-real.cpp
+++ b/flang/lib/Evaluate/fold-real.cpp
@@ -35,9 +35,8 @@ static Expr<T> FoldTransformationalBessel(
}
return Expr<T>{Constant<T>{
std::move(results), ConstantSubscripts{std::max(n2 - n1 + 1, 0)}}};
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
+ } else {
+ context.Warn(common::UsageWarning::FoldingFailure,
"%s(integer(kind=4), real(kind=%d)) cannot be folded on host"_warn_en_US,
name, T::kind);
}
@@ -131,10 +130,8 @@ static Expr<Type<TypeCategory::Real, KIND>> FoldNorm2(FoldingContext &context,
context.targetCharacteristics().roundingMode()};
Constant<T> result{DoReduction<T>(arrayAndMask->array, arrayAndMask->mask,
dim, identity, norm2Accumulator)};
- if (norm2Accumulator.overflow() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (norm2Accumulator.overflow()) {
+ context.Warn(common::UsageWarning::FoldingException,
"NORM2() of REAL(%d) data overflowed"_warn_en_US, KIND);
}
return Expr<T>{std::move(result)};
@@ -165,9 +162,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (auto callable{GetHostRuntimeWrapper<T, T>(name)}) {
return FoldElementalIntrinsic<T, T>(
context, std::move(funcRef), *callable);
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
+ } else {
+ context.Warn(common::UsageWarning::FoldingFailure,
"%s(real(kind=%d)) cannot be folded on host"_warn_en_US, name, KIND);
}
} else if (name == "amax0" || name == "amin0" || name == "amin1" ||
@@ -179,9 +175,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (auto callable{GetHostRuntimeWrapper<T, T, T>(localName)}) {
return FoldElementalIntrinsic<T, T, T>(
context, std::move(funcRef), *callable);
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
+ } else {
+ context.Warn(common::UsageWarning::FoldingFailure,
"%s(real(kind=%d), real(kind%d)) cannot be folded on host"_warn_en_US,
name, KIND, KIND);
}
@@ -191,9 +186,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (auto callable{GetHostRuntimeWrapper<T, Int4, T>(name)}) {
return FoldElementalIntrinsic<T, Int4, T>(
context, std::move(funcRef), *callable);
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
+ } else {
+ context.Warn(common::UsageWarning::FoldingFailure,
"%s(integer(kind=4), real(kind=%d)) cannot be folded on host"_warn_en_US,
name, KIND);
}
@@ -210,10 +204,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, ComplexT>([&name, &context](
const Scalar<ComplexT> &z) -> Scalar<T> {
ValueWithRealFlags<Scalar<T>> y{z.ABS()};
- if (y.flags.test(RealFlag::Overflow) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (y.flags.test(RealFlag::Overflow)) {
+ context.Warn(common::UsageWarning::FoldingException,
"complex ABS intrinsic folding overflow"_warn_en_US, name);
}
return y.value;
@@ -234,10 +226,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T>(
[&name, &context, mode](const Scalar<T> &x) -> Scalar<T> {
ValueWithRealFlags<Scalar<T>> y{x.ToWholeNumber(mode)};
- if (y.flags.test(RealFlag::Overflow) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (y.flags.test(RealFlag::Overflow)) {
+ context.Warn(common::UsageWarning::FoldingException,
"%s intrinsic folding overflow"_warn_en_US, name);
}
return y.value;
@@ -247,10 +237,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T, T>([&context](const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
ValueWithRealFlags<Scalar<T>> result{x.DIM(y)};
- if (result.flags.test(RealFlag::Overflow) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (result.flags.test(RealFlag::Overflow)) {
+ context.Warn(common::UsageWarning::FoldingException,
"DIM intrinsic folding overflow"_warn_en_US);
}
return result.value;
@@ -282,10 +270,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T, T>(
[&](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
ValueWithRealFlags<Scalar<T>> result{x.HYPOT(y)};
- if (result.flags.test(RealFlag::Overflow) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (result.flags.test(RealFlag::Overflow)) {
+ context.Warn(common::UsageWarning::FoldingException,
"HYPOT intrinsic folding overflow"_warn_en_US);
}
return result.value;
@@ -307,11 +293,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
bool badPConst{false};
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
*pExpr = Fold(context, std::move(*pExpr));
- if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
- pConst->IsZero() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)};
+ pConst && pConst->IsZero()) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MOD: P argument is zero"_warn_en_US);
badPConst = true;
}
@@ -320,11 +304,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T, T>([&context, badPConst](const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto result{x.MOD(y)};
- if (!badPConst && result.flags.test(RealFlag::DivideByZero) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(
- common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (!badPConst && result.flags.test(RealFlag::DivideByZero)) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"second argument to MOD must not be zero"_warn_en_US);
}
return result.value;
@@ -334,11 +315,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
bool badPConst{false};
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
*pExpr = Fold(context, std::move(*pExpr));
- if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
- pConst->IsZero() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)};
+ pConst && pConst->IsZero()) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MODULO: P argument is zero"_warn_en_US);
badPConst = true;
}
@@ -347,11 +326,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
ScalarFunc<T, T, T>([&context, badPConst](const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto result{x.MODULO(y)};
- if (!badPConst && result.flags.test(RealFlag::DivideByZero) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(
- common::UsageWarning::FoldingAvoidsRuntimeCrash,
+ if (!badPConst && result.flags.test(RealFlag::DivideByZero)) {
+ context.Warn(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"second argument to MODULO must not be zero"_warn_en_US);
}
return result.value;
@@ -363,11 +339,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
[&](const auto &sVal) {
using TS = ResultType<decltype(sVal)>;
bool badSConst{false};
- if (auto sConst{GetScalarConstantValue<TS>(sVal)}; sConst &&
- (sConst->IsZero() || sConst->IsNotANumber()) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingValueChecks)) {
- context.messages().Say(common::UsageWarning::FoldingValueChecks,
+ if (auto sConst{GetScalarConstantValue<TS>(sVal)};
+ sConst && (sConst->IsZero() || sConst->IsNotANumber())) {
+ context.Warn(common::UsageWarning::FoldingValueChecks,
"NEAREST: S argument is %s"_warn_en_US,
sConst->IsZero() ? "zero" : "NaN");
badSConst = true;
@@ -375,22 +349,15 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
return FoldElementalIntrinsic<T, T, TS>(context, std::move(funcRef),
ScalarFunc<T, T, TS>([&](const Scalar<T> &x,
const Scalar<TS> &s) -> Scalar<T> {
- if (!badSConst && (s.IsZero() || s.IsNotANumber()) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingValueChecks)) {
- context.messages().Say(
- common::UsageWarning::FoldingValueChecks,
+ if (!badSConst && (s.IsZero() || s.IsNotANumber())) {
+ context.Warn(common::UsageWarning::FoldingValueChecks,
"NEAREST: S argument is %s"_warn_en_US,
s.IsZero() ? "zero" : "NaN");
}
auto result{x.NEAREST(!s.IsNegative())};
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- if (result.flags.test(RealFlag::InvalidArgument)) {
- context.messages().Say(
- common::UsageWarning::FoldingException,
- "NEAREST intrinsic folding: bad argument"_warn_en_US);
- }
+ if (result.flags.test(RealFlag::InvalidArgument)) {
+ context.Warn(common::UsageWarning::FoldingException,
+ "NEAREST intrinsic folding: bad argument"_warn_en_US);
}
return result.value;
}));
@@ -427,11 +394,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
template
#endif
SCALE<Scalar<TBY>>(y)};
- if (result.flags.test(RealFlag::Overflow) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(
- common::UsageWarning::FoldingException,
+ if (result.flags.test(RealFlag::Overflow)) {
+ context.Warn(common::UsageWarning::FoldingException,
"SCALE/IEEE_SCALB intrinsic folding overflow"_warn_en_US);
}
return result.value;
@@ -481,12 +445,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
auto yBig{Scalar<LargestReal>::Convert(y).value};
switch (xBig.Compare(yBig)) {
case Relation::Unordered:
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingValueChecks)) {
- context.messages().Say(
- common::UsageWarning::FoldingValueChecks,
- "IEEE_NEXT_AFTER intrinsic folding: arguments are unordered"_warn_en_US);
- }
+ context.Warn(common::UsageWarning::FoldingValueChecks,
+ "IEEE_NEXT_AFTER intrinsic folding: arguments are unordered"_warn_en_US);
return x.NotANumber();
case Relation::Equal:
break;
@@ -507,12 +467,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
return FoldElementalIntrinsic<T, T>(context, std::move(funcRef),
ScalarFunc<T, T>([&](const Scalar<T> &x) -> Scalar<T> {
auto result{x.NEAREST(upward)};
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- if (result.flags.test(RealFlag::InvalidArgument)) {
- context.messages().Say(common::UsageWarning::FoldingException,
- "%s intrinsic folding: argument is NaN"_warn_en_US, iName);
- }
+ if (result.flags.test(RealFlag::InvalidArgument)) {
+ context.Warn(common::UsageWarning::FoldingException,
+ "%s intrinsic folding: argument is NaN"_warn_en_US, iName);
}
return result.value;
}));
diff --git a/flang/lib/Evaluate/fold-reduction.h b/flang/lib/Evaluate/fold-reduction.h
index b6f2d219ed5b1..fe897393fe13e 100644
--- a/flang/lib/Evaluate/fold-reduction.h
+++ b/flang/lib/Evaluate/fold-reduction.h
@@ -112,10 +112,8 @@ static Expr<T> FoldDotProduct(
}
}
}
- if (overflow &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (overflow) {
+ context.Warn(common::UsageWarning::FoldingException,
"DOT_PRODUCT of %s data overflowed during computation"_warn_en_US,
T::AsFortran());
}
@@ -334,10 +332,8 @@ static Expr<T> FoldProduct(
ProductAccumulator accumulator{arrayAndMask->array};
auto result{Expr<T>{DoReduction<T>(
arrayAndMask->array, arrayAndMask->mask, dim, identity, accumulator)}};
- if (accumulator.overflow() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (accumulator.overflow()) {
+ context.Warn(common::UsageWarning::FoldingException,
"PRODUCT() of %s data overflowed"_warn_en_US, T::AsFortran());
}
return result;
@@ -406,10 +402,8 @@ static Expr<T> FoldSum(FoldingContext &context, FunctionRef<T> &&ref) {
arrayAndMask->array, context.targetCharacteristics().roundingMode()};
auto result{Expr<T>{DoReduction<T>(
arrayAndMask->array, arrayAndMask->mask, dim, identity, accumulator)}};
- if (accumulator.overflow() &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingException)) {
- context.messages().Say(common::UsageWarning::FoldingException,
+ if (accumulator.overflow()) {
+ context.Warn(common::UsageWarning::FoldingException,
"SUM() of %s data overflowed"_warn_en_US, T::AsFortran());
}
return result;
diff --git a/flang/lib/Evaluate/fold.cpp b/flang/lib/Evaluate/fold.cpp
index 71ead1b3afa91..1fbbbba909fbf 100644
--- a/flang/lib/Evaluate/fold.cpp
+++ b/flang/lib/Evaluate/fold.cpp
@@ -290,11 +290,8 @@ std::optional<Expr<SomeType>> FoldTransfer(
} else if (source && moldType) {
if (const auto *boz{std::get_if<BOZLiteralConstant>(&source->u)}) {
// TRANSFER(BOZ, MOLD=integer or real) extension
- if (context.languageFeatures().ShouldWarn(
- common::LanguageFeature::TransferBOZ)) {
- context.messages().Say(common::LanguageFeature::TransferBOZ,
- "TRANSFER(BOZ literal) is not standard"_port_en_US);
- }
+ context.Warn(common::LanguageFeature::TransferBOZ,
+ "TRANSFER(BOZ literal) is not standard"_port_en_US);
return Fold(context, ConvertToType(*moldType, Expr<SomeType>{*boz}));
}
}
diff --git a/flang/lib/Evaluate/host.cpp b/flang/lib/Evaluate/host.cpp
index 187bb2f09806b..25409ac3418b8 100644
--- a/flang/lib/Evaluate/host.cpp
+++ b/flang/lib/Evaluate/host.cpp
@@ -100,13 +100,8 @@ void HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment(
break;
case common::RoundingMode::TiesAwayFromZero:
fesetround(FE_TONEAREST);
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingFailure)) {
- context.messages().Say(common::UsageWarning::FoldingFailure,
- "TiesAwayFromZero rounding mode is not available when folding "
- "constants"
- " with host runtime; using TiesToEven instead"_warn_en_US);
- }
+ context.Warn(common::UsageWarning::FoldingFailure,
+ "TiesAwayFromZero rounding mode is not available when folding constants with host runtime; using TiesToEven instead"_warn_en_US);
break;
}
flags_.clear();
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index c37a7f908d4d1..e698d163e003a 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -2617,15 +2617,12 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
if (const Symbol *whole{
UnwrapWholeSymbolOrComponentDataRef(actualForDummy[*dimArg])}) {
if (IsOptional(*whole) || IsAllocatableOrObjectPointer(whole)) {
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::OptionalMustBePresent)) {
- if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
- messages.Say(common::UsageWarning::OptionalMustBePresent,
- "The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US);
- } else {
- messages.Say(common::UsageWarning::OptionalMustBePresent,
- "The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
- }
+ if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
+ context.Warn(common::UsageWarning::OptionalMustBePresent,
+ "The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US);
+ } else {
+ context.Warn(common::UsageWarning::OptionalMustBePresent,
+ "The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
}
}
}
@@ -3109,16 +3106,12 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
context.messages().Say(at,
"FPTR= argument to C_F_POINTER() may not have a deferred type parameter"_err_en_US);
} else if (type->category() == TypeCategory::Derived) {
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::Interoperability) &&
- type->IsUnlimitedPolymorphic()) {
- context.messages().Say(common::UsageWarning::Interoperability, at,
+ if (type->IsUnlimitedPolymorphic()) {
+ context.Warn(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not be unlimited polymorphic"_warn_en_US);
} else if (!type->GetDerivedTypeSpec().typeSymbol().attrs().test(
- semantics::Attr::BIND_C) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::Portability)) {
- context.messages().Say(common::UsageWarning::Portability, at,
+ semantics::Attr::BIND_C)) {
+ context.Warn(common::UsageWarning::Portability, at,
"FPTR= argument to C_F_POINTER() should not have a derived type that is not BIND(C)"_port_en_US);
}
} else if (!IsInteroperableIntrinsicType(
@@ -3126,16 +3119,11 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
.value_or(true)) {
if (type->category() == TypeCategory::Character &&
type->kind() == 1) {
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::CharacterInteroperability)) {
- context.messages().Say(
- common::UsageWarning::CharacterInteroperability, at,
- "FPTR= argument to C_F_POINTER() should not have the non-interoperable character length %s"_warn_en_US,
- type->AsFortran());
- }
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::Interoperability)) {
- context.messages().Say(common::UsageWarning::Interoperability, at,
+ context.Warn(common::UsageWarning::CharacterInteroperability, at,
+ "FPTR= argument to C_F_POINTER() should not have the non-interoperable character length %s"_warn_en_US,
+ type->AsFortran());
+ } else {
+ context.Warn(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type or kind %s"_warn_en_US,
type->AsFortran());
}
@@ -3274,16 +3262,11 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
if (typeAndShape->type().category() == TypeCategory::Character &&
typeAndShape->type().kind() == 1) {
// Default character kind, but length is not known to be 1
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::CharacterInteroperability)) {
- context.messages().Say(
- common::UsageWarning::CharacterInteroperability,
- arguments[0]->sourceLocation(),
- "C_LOC() argument has non-interoperable character length"_warn_en_US);
- }
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::Interoperability)) {
- context.messages().Say(common::UsageWarning::Interoperability,
+ context.Warn(common::UsageWarning::CharacterInteroperability,
+ arguments[0]->sourceLocation(),
+ "C_LOC() argument has non-interoperable character length"_warn_en_US);
+ } else {
+ context.Warn(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable intrinsic type or kind"_warn_en_US);
}
@@ -3341,16 +3324,11 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Devloc(
if (typeAndShape->type().category() == TypeCategory::Character &&
typeAndShape->type().kind() == 1) {
// Default character kind, but length is not known to be 1
- if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::CharacterInteroperability)) {
- context.messages().Say(
- common::UsageWarning::CharacterInteroperability,
- arguments[0]->sourceLocation(),
- "C_DEVLOC() argument has non-interoperable character length"_warn_en_US);
- }
- } else if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::Interoperability)) {
- context.messages().Say(common::UsageWarning::Interoperability,
+ context.Warn(common::UsageWarning::CharacterInteroperability,
+ arguments[0]->sourceLocation(),
+ "C_DEVLOC() argument has non-interoperable character length"_warn_en_US);
+ } else {
+ context.Warn(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_DEVLOC() argument has non-interoperable intrinsic type or kind"_warn_en_US);
}
@@ -3673,15 +3651,10 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
genericType.category() == TypeCategory::Real) &&
(newType.category() == TypeCategory::Integer ||
newType.category() == TypeCategory::Real))) {
- if (context.languageFeatures().ShouldWarn(
- common::LanguageFeature::
- UseGenericIntrinsicWhenSpecificDoesntMatch)) {
- context.messages().Say(
- common::LanguageFeature::
- UseGenericIntrinsicWhenSpecificDoesntMatch,
- "Argument types do not match specific intrinsic '%s' requirements; using '%s' generic instead and converting the result to %s if needed"_port_en_US,
- call.name, genericName, newType.AsFortran());
- }
+ context.Warn(common::LanguageFeature::
+ UseGenericIntrinsicWhenSpecificDoesntMatch,
+ "Argument types do not match specific intrinsic '%s' requirements; using '%s' generic instead and converting the result to %s if needed"_port_en_US,
+ call.name, genericName, newType.AsFortran());
specificCall->specificIntrinsic.name = call.name;
specificCall->specificIntrinsic.characteristics.value()
.functionResult.value()
diff --git a/flang/lib/Evaluate/variable.cpp b/flang/lib/Evaluate/variable.cpp
index d1bff03a6ea5f..b9b34d4d5bc89 100644
--- a/flang/lib/Evaluate/variable.cpp
+++ b/flang/lib/Evaluate/variable.cpp
@@ -212,21 +212,17 @@ std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {
}
if (!result) { // error cases
if (*lbi < 1) {
- if (context.languageFeatures().ShouldWarn(common::UsageWarning::Bounds)) {
- context.messages().Say(common::UsageWarning::Bounds,
- "Lower bound (%jd) on substring is less than one"_warn_en_US,
- static_cast<std::intmax_t>(*lbi));
- }
+ context.Warn(common::UsageWarning::Bounds,
+ "Lower bound (%jd) on substring is less than one"_warn_en_US,
+ static_cast<std::intmax_t>(*lbi));
*lbi = 1;
lower_ = AsExpr(Constant<SubscriptInteger>{1});
}
if (length && *ubi > *length) {
- if (context.languageFeatures().ShouldWarn(common::UsageWarning::Bounds)) {
- context.messages().Say(common::UsageWarning::Bounds,
- "Upper bound (%jd) on substring is greater than character length (%jd)"_warn_en_US,
- static_cast<std::intmax_t>(*ubi),
- static_cast<std::intmax_t>(*length));
- }
+ context.Warn(common::UsageWarning::Bounds,
+ "Upper bound (%jd) on substring is greater than character length (%jd)"_warn_en_US,
+ static_cast<std::intmax_t>(*ubi),
+ static_cast<std::intmax_t>(*length));
*ubi = *length;
upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});
}
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 0aadc41934f3c..ae14e2d46020f 100644
--- a/flang/lib/Parser/preprocessor.cpp
+++ b/flang/lib/Parser/preprocessor.cpp
@@ -742,12 +742,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
"# missing or invalid name"_err_en_US);
} else {
if (dir.IsAnythingLeft(++j)) {
- if (prescanner.features().ShouldWarn(
- common::UsageWarning::Portability)) {
- prescanner.Say(common::UsageWarning::Portability,
- dir.GetIntervalProvenanceRange(j, tokens - j),
- "#undef: excess tokens at end of directive"_port_en_US);
- }
+ prescanner.Warn(common::UsageWarning::Portability,
+ dir.GetIntervalProvenanceRange(j, tokens - j),
+ "#undef: excess tokens at end of directive"_port_en_US);
} else {
definitions_.erase(nameToken);
}
@@ -760,12 +757,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
"#%s: missing name"_err_en_US, dirName);
} else {
if (dir.IsAnythingLeft(++j)) {
- if (prescanner.features().ShouldWarn(
- common::UsageWarning::Portability)) {
- prescanner.Say(common::UsageWarning::Portability,
- dir.GetIntervalProvenanceRange(j, tokens - j),
- "#%s: excess tokens at end of directive"_port_en_US, dirName);
- }
+ prescanner.Warn(common::UsageWarning::Portability,
+ dir.GetIntervalProvenanceRange(j, tokens - j),
+ "#%s: excess tokens at end of directive"_port_en_US, dirName);
}
doThen = IsNameDefined(nameToken) == (dirName == "ifdef");
}
@@ -784,11 +778,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
}
} else if (dirName == "else") {
if (dir.IsAnythingLeft(j)) {
- if (prescanner.features().ShouldWarn(common::UsageWarning::Portability)) {
- prescanner.Say(common::UsageWarning::Portability,
- dir.GetIntervalProvenanceRange(j, tokens - j),
- "#else: excess tokens at end of directive"_port_en_US);
- }
+ prescanner.Warn(common::UsageWarning::Portability,
+ dir.GetIntervalProvenanceRange(j, tokens - j),
+ "#else: excess tokens at end of directive"_port_en_US);
}
if (ifStack_.empty()) {
prescanner.Say(dir.GetTokenProvenanceRange(dirOffset),
@@ -815,11 +807,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
}
} else if (dirName == "endif") {
if (dir.IsAnythingLeft(j)) {
- if (prescanner.features().ShouldWarn(common::UsageWarning::Portability)) {
- prescanner.Say(common::UsageWarning::Portability,
- dir.GetIntervalProvenanceRange(j, tokens - j),
- "#endif: excess tokens at end of directive"_port_en_US);
- }
+ prescanner.Warn(common::UsageWarning::Portability,
+ dir.GetIntervalProvenanceRange(j, tokens - j),
+ "#endif: excess tokens at end of directive"_port_en_US);
} else if (ifStack_.empty()) {
prescanner.Say(dir.GetTokenProvenanceRange(dirOffset),
"#endif: no #if, #ifdef, or #ifndef"_err_en_US);
@@ -866,12 +856,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
++k;
}
if (k >= pathTokens) {
- if (prescanner.features().ShouldWarn(
- common::UsageWarning::Portability)) {
- prescanner.Say(common::UsageWarning::Portability,
- dir.GetIntervalProvenanceRange(j, tokens - j),
- "#include: expected '>' at end of included file"_port_en_US);
- }
+ prescanner.Warn(common::UsageWarning::Portability,
+ dir.GetIntervalProvenanceRange(j, tokens - j),
+ "#include: expected '>' at end of included file"_port_en_US);
}
TokenSequence braced{path, 1, k - 1};
include = braced.ToString();
@@ -897,11 +884,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
}
k = path.SkipBlanks(k + 1);
if (k < pathTokens && path.TokenAt(k).ToString() != "!") {
- if (prescanner.features().ShouldWarn(common::UsageWarning::Portability)) {
- prescanner.Say(common::UsageWarning::Portability,
- dir.GetIntervalProvenanceRange(j, tokens - j),
- "#include: extra stuff ignored after file name"_port_en_US);
- }
+ prescanner.Warn(common::UsageWarning::Portability,
+ dir.GetIntervalProvenanceRange(j, tokens - j),
+ "#include: extra stuff ignored after file name"_port_en_US);
}
std::string buf;
llvm::raw_string_ostream error{buf};
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index f650d548e6eff..c181c03273ccc 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -91,6 +91,15 @@ class Prescanner {
return messages_.Say(std::forward<A>(a)...);
}
+ template <typename... A>
+ Message *Warn(common::UsageWarning warning, A &&...a) {
+ return messages_.Warn(false, features_, warning, std::forward<A>(a)...);
+ }
+ template <typename... A>
+ Message *Warn(common::LanguageFeature feature, A &&...a) {
+ return messages_.Warn(false, features_, feature, std::forward<A>(a)...);
+ }
+
private:
struct LineClassification {
enum class Kind {
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index 83f59f0cac3df..6ee8c653cbb51 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -140,7 +140,8 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
messages.Say(
"Assumed-rank character array may not be associated with a dummy argument that is not assumed-rank"_err_en_US);
} else {
- context.Warn(common::LanguageFeature::AssumedRankPassedToNonAssumedRank,
+ context.Warn(messages,
+ common::LanguageFeature::AssumedRankPassedToNonAssumedRank,
messages.at(),
"Assumed-rank character array should not be associated with a dummy argument that is not assumed-rank"_port_en_US);
}
@@ -187,9 +188,9 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
"Actual argument has fewer characters remaining in storage sequence (%jd) than %s (%jd)"_err_en_US,
static_cast<std::intmax_t>(actualChars), dummyName,
static_cast<std::intmax_t>(dummyChars));
- } else if (context.ShouldWarn(
- common::UsageWarning::ShortCharacterActual)) {
- messages.Say(common::UsageWarning::ShortCharacterActual,
+ } else {
+ context.Warn(messages,
+ common::UsageWarning::ShortCharacterActual,
"Actual argument has fewer characters remaining in storage sequence (%jd) than %s (%jd)"_warn_en_US,
static_cast<std::intmax_t>(actualChars), dummyName,
static_cast<std::intmax_t>(dummyChars));
@@ -207,9 +208,9 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
static_cast<std::intmax_t>(*actualSize * *actualLength),
dummyName,
static_cast<std::intmax_t>(*dummySize * *dummyLength));
- } else if (context.ShouldWarn(
- common::UsageWarning::ShortCharacterActual)) {
- messages.Say(common::UsageWarning::ShortCharacterActual,
+ } else {
+ context.Warn(messages,
+ common::UsageWarning::ShortCharacterActual,
"Actual argument array has fewer characters (%jd) than %s array (%jd)"_warn_en_US,
static_cast<std::intmax_t>(*actualSize * *actualLength),
dummyName,
@@ -229,17 +230,14 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
} else if (*actualLength < *dummyLength) {
CHECK(dummy.type.Rank() == 0);
bool isVariable{evaluate::IsVariable(actual)};
- if (context.ShouldWarn(
- common::UsageWarning::ShortCharacterActual)) {
- if (isVariable) {
- messages.Say(common::UsageWarning::ShortCharacterActual,
- "Actual argument variable length '%jd' is less than expected length '%jd'"_warn_en_US,
- *actualLength, *dummyLength);
- } else {
- messages.Say(common::UsageWarning::ShortCharacterActual,
- "Actual argument expression length '%jd' is less than expected length '%jd'"_warn_en_US,
- *actualLength, *dummyLength);
- }
+ if (isVariable) {
+ context.Warn(messages, common::UsageWarning::ShortCharacterActual,
+ "Actual argument variable length '%jd' is less than expected length '%jd'"_warn_en_US,
+ *actualLength, *dummyLength);
+ } else {
+ context.Warn(messages, common::UsageWarning::ShortCharacterActual,
+ "Actual argument expression length '%jd' is less than expected length '%jd'"_warn_en_US,
+ *actualLength, *dummyLength);
}
if (!isVariable) {
auto converted{
@@ -279,9 +277,8 @@ static void ConvertIntegerActual(evaluate::Expr<evaluate::SomeType> &actual,
messages.Say(
"Actual argument scalar expression of type INTEGER(%d) cannot be implicitly converted to smaller dummy argument type INTEGER(%d)"_err_en_US,
actualType.type().kind(), dummyType.type().kind());
- } else if (semanticsContext.ShouldWarn(common::LanguageFeature::
- ActualIntegerConvertedToSmallerKind)) {
- messages.Say(
+ } else {
+ semanticsContext.Warn(messages,
common::LanguageFeature::ActualIntegerConvertedToSmallerKind,
"Actual argument scalar expression of type INTEGER(%d) was converted to smaller dummy argument type INTEGER(%d)"_port_en_US,
actualType.type().kind(), dummyType.type().kind());
@@ -364,20 +361,16 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
if (const auto *constantChar{
evaluate::UnwrapConstantValue<evaluate::Ascii>(actual)};
constantChar && constantChar->wasHollerith() &&
- dummy.type.type().IsUnlimitedPolymorphic() &&
- context.ShouldWarn(common::LanguageFeature::HollerithPolymorphic)) {
- messages.Say(common::LanguageFeature::HollerithPolymorphic,
+ dummy.type.type().IsUnlimitedPolymorphic()) {
+ foldingContext.Warn(common::LanguageFeature::HollerithPolymorphic,
"passing Hollerith to unlimited polymorphic as if it were CHARACTER"_port_en_US);
}
} else if (dummyRank == 0 && allowActualArgumentConversions) {
// Extension: pass Hollerith literal to scalar as if it had been BOZ
if (auto converted{evaluate::HollerithToBOZ(
foldingContext, actual, dummy.type.type())}) {
- if (context.ShouldWarn(
- common::LanguageFeature::HollerithOrCharacterAsBOZ)) {
- messages.Say(common::LanguageFeature::HollerithOrCharacterAsBOZ,
- "passing Hollerith or character literal as if it were BOZ"_port_en_US);
- }
+ foldingContext.Warn(common::LanguageFeature::HollerithOrCharacterAsBOZ,
+ "passing Hollerith or character literal as if it were BOZ"_port_en_US);
actual = *converted;
actualType.type() = dummy.type.type();
typesCompatible = true;
@@ -411,7 +404,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
"%s actual argument may not be associated with INTENT(OUT) assumed-rank dummy argument requiring finalization, destruction, or initialization"_err_en_US,
actualDesc);
} else {
- context.Warn(common::UsageWarning::Portability, messages.at(),
+ foldingContext.Warn(common::UsageWarning::Portability, messages.at(),
"%s actual argument should not be associated with INTENT(OUT) assumed-rank dummy argument"_port_en_US,
actualDesc);
}
@@ -671,9 +664,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
"Actual argument has fewer elements remaining in storage sequence (%jd) than %s array (%jd)"_err_en_US,
static_cast<std::intmax_t>(*actualElements), dummyName,
static_cast<std::intmax_t>(*dummySize));
- } else if (context.ShouldWarn(
- common::UsageWarning::ShortArrayActual)) {
- messages.Say(common::UsageWarning::ShortArrayActual,
+ } else {
+ context.Warn(common::UsageWarning::ShortArrayActual,
"Actual argument has fewer elements remaining in storage sequence (%jd) than %s array (%jd)"_warn_en_US,
static_cast<std::intmax_t>(*actualElements), dummyName,
static_cast<std::intmax_t>(*dummySize));
@@ -690,9 +682,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
"Actual argument array has fewer elements (%jd) than %s array (%jd)"_err_en_US,
static_cast<std::intmax_t>(*actualSize), dummyName,
static_cast<std::intmax_t>(*dummySize));
- } else if (context.ShouldWarn(
- common::UsageWarning::ShortArrayActual)) {
- messages.Say(common::UsageWarning::ShortArrayActual,
+ } else {
+ context.Warn(common::UsageWarning::ShortArrayActual,
"Actual argument array has fewer elements (%jd) than %s array (%jd)"_warn_en_US,
static_cast<std::intmax_t>(*actualSize), dummyName,
static_cast<std::intmax_t>(*dummySize));
@@ -821,10 +812,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
messages.Say(
"A null pointer should not be associated with allocatable %s without INTENT(IN)"_warn_en_US,
dummyName);
- } else if (dummy.intent == common::Intent::In &&
- context.ShouldWarn(
- common::LanguageFeature::NullActualForAllocatable)) {
- messages.Say(common::LanguageFeature::NullActualForAllocatable,
+ } else if (dummy.intent == common::Intent::In) {
+ foldingContext.Warn(common::LanguageFeature::NullActualForAllocatable,
"Allocatable %s is associated with a null pointer"_port_en_US,
dummyName);
}
@@ -878,11 +867,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
checkTypeCompatibility = false;
if (dummyIsUnlimited && dummy.intent == common::Intent::In &&
context.IsEnabled(common::LanguageFeature::RelaxedIntentInChecking)) {
- if (context.ShouldWarn(
- common::LanguageFeature::RelaxedIntentInChecking)) {
- messages.Say(common::LanguageFeature::RelaxedIntentInChecking,
- "If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both should be so"_port_en_US);
- }
+ foldingContext.Warn(common::LanguageFeature::RelaxedIntentInChecking,
+ "If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both should be so"_port_en_US);
} else {
messages.Say(
"If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both must be so"_err_en_US);
@@ -890,21 +876,15 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
} else if (dummyIsPolymorphic != actualIsPolymorphic) {
if (dummyIsPolymorphic && dummy.intent == common::Intent::In &&
context.IsEnabled(common::LanguageFeature::RelaxedIntentInChecking)) {
- if (context.ShouldWarn(
- common::LanguageFeature::RelaxedIntentInChecking)) {
- messages.Say(common::LanguageFeature::RelaxedIntentInChecking,
- "If a POINTER or ALLOCATABLE dummy or actual argument is polymorphic, both should be so"_port_en_US);
- }
+ foldingContext.Warn(common::LanguageFeature::RelaxedIntentInChecking,
+ "If a POINTER or ALLOCATABLE dummy or actual argument is polymorphic, both should be so"_port_en_US);
} else if (actualIsPolymorphic &&
context.IsEnabled(common::LanguageFeature::
PolymorphicActualAllocatableOrPointerToMonomorphicDummy)) {
- if (context.ShouldWarn(common::LanguageFeature::
- PolymorphicActualAllocatableOrPointerToMonomorphicDummy)) {
- messages.Say(
- common::LanguageFeature::
- PolymorphicActualAllocatableOrPointerToMonomorphicDummy,
- "If a POINTER or ALLOCATABLE actual argument is polymorphic, the corresponding dummy argument should also be so"_port_en_US);
- }
+ foldingContext.Warn(
+ common::LanguageFeature::
+ PolymorphicActualAllocatableOrPointerToMonomorphicDummy,
+ "If a POINTER or ALLOCATABLE actual argument is polymorphic, the corresponding dummy argument should also be so"_port_en_US);
} else {
checkTypeCompatibility = false;
messages.Say(
@@ -916,11 +896,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
if (dummy.intent == common::Intent::In &&
context.IsEnabled(
common::LanguageFeature::RelaxedIntentInChecking)) {
- if (context.ShouldWarn(
- common::LanguageFeature::RelaxedIntentInChecking)) {
- messages.Say(common::LanguageFeature::RelaxedIntentInChecking,
- "POINTER or ALLOCATABLE dummy and actual arguments should have the same declared type and kind"_port_en_US);
- }
+ foldingContext.Warn(common::LanguageFeature::RelaxedIntentInChecking,
+ "POINTER or ALLOCATABLE dummy and actual arguments should have the same declared type and kind"_port_en_US);
} else {
messages.Say(
"POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type and kind"_err_en_US);
@@ -991,13 +968,13 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
bool actualIsTemp{
!actualIsVariable || HasVectorSubscript(actual) || actualCoarrayRef};
if (actualIsTemp) {
- messages.Say(common::UsageWarning::NonTargetPassedToTarget,
+ foldingContext.Warn(common::UsageWarning::NonTargetPassedToTarget,
"Any pointer associated with TARGET %s during this call will not be associated with the value of '%s' afterwards"_warn_en_US,
dummyName, actual.AsFortran());
} else {
auto actualSymbolVector{GetSymbolVector(actual)};
if (!evaluate::GetLastTarget(actualSymbolVector)) {
- messages.Say(common::UsageWarning::NonTargetPassedToTarget,
+ foldingContext.Warn(common::UsageWarning::NonTargetPassedToTarget,
"Any pointer associated with TARGET %s during this call must not be used afterwards, as '%s' is not a target"_warn_en_US,
dummyName, actual.AsFortran());
}
@@ -1126,9 +1103,8 @@ static void CheckProcedureArg(evaluate::ActualArgument &arg,
evaluate::SayWithDeclaration(messages, *argProcSymbol,
"Procedure binding '%s' passed as an actual argument"_err_en_US,
argProcSymbol->name());
- } else if (context.ShouldWarn(
- common::LanguageFeature::BindingAsProcedure)) {
- evaluate::SayWithDeclaration(messages, *argProcSymbol,
+ } else {
+ evaluate::WarnWithDeclaration(foldingContext, *argProcSymbol,
common::LanguageFeature::BindingAsProcedure,
"Procedure binding '%s' passed as an actual argument"_port_en_US,
argProcSymbol->name());
@@ -1180,15 +1156,14 @@ static void CheckProcedureArg(evaluate::ActualArgument &arg,
messages.Say(
"Actual procedure argument for %s of a PURE procedure must have an explicit interface"_err_en_US,
dummyName);
- } else if (context.ShouldWarn(
- common::UsageWarning::ImplicitInterfaceActual)) {
- messages.Say(common::UsageWarning::ImplicitInterfaceActual,
+ } else {
+ foldingContext.Warn(
+ common::UsageWarning::ImplicitInterfaceActual,
"Actual procedure argument has an implicit interface which is not known to be compatible with %s which has an explicit interface"_warn_en_US,
dummyName);
}
- } else if (warning &&
- context.ShouldWarn(common::UsageWarning::ProcDummyArgShapes)) {
- messages.Say(common::UsageWarning::ProcDummyArgShapes,
+ } else if (warning) {
+ foldingContext.Warn(common::UsageWarning::ProcDummyArgShapes,
"Actual procedure argument has possible interface incompatibility with %s: %s"_warn_en_US,
dummyName, std::move(*warning));
}
@@ -1363,16 +1338,14 @@ static void CheckExplicitInterfaceArg(evaluate::ActualArgument &arg,
messages.Say(
"NULL() actual argument '%s' may not be associated with allocatable dummy argument %s that is INTENT(OUT) or INTENT(IN OUT)"_err_en_US,
expr->AsFortran(), dummyName);
- } else if (object.intent == common::Intent::Default &&
- context.ShouldWarn(common::UsageWarning::
- NullActualForDefaultIntentAllocatable)) {
- messages.Say(common::UsageWarning::
- NullActualForDefaultIntentAllocatable,
+ } else if (object.intent == common::Intent::Default) {
+ foldingContext.Warn(
+ common::UsageWarning::
+ NullActualForDefaultIntentAllocatable,
"NULL() actual argument '%s' should not be associated with allocatable dummy argument %s without INTENT(IN)"_warn_en_US,
expr->AsFortran(), dummyName);
- } else if (context.ShouldWarn(common::LanguageFeature::
- NullActualForAllocatable)) {
- messages.Say(
+ } else {
+ foldingContext.Warn(
common::LanguageFeature::NullActualForAllocatable,
"Allocatable %s is associated with %s"_port_en_US,
dummyName, expr->AsFortran());
@@ -1562,7 +1535,7 @@ static void CheckAssociated(evaluate::ActualArguments &arguments,
if (semanticsContext.ShouldWarn(common::UsageWarning::Portability)) {
if (!evaluate::ExtractDataRef(*pointerExpr) &&
!evaluate::IsProcedurePointer(*pointerExpr)) {
- messages.Say(common::UsageWarning::Portability,
+ foldingContext.Warn(common::UsageWarning::Portability,
pointerArg->sourceLocation(),
"POINTER= argument of ASSOCIATED() is required by some other compilers to be a pointer"_port_en_US);
} else if (scope && !evaluate::UnwrapProcedureRef(*pointerExpr)) {
@@ -1573,7 +1546,8 @@ static void CheckAssociated(evaluate::ActualArguments &arguments,
DefinabilityFlag::DoNotNoteDefinition},
*pointerExpr)}) {
if (whyNot->IsFatal()) {
- if (auto *msg{messages.Say(common::UsageWarning::Portability,
+ if (auto *msg{foldingContext.Warn(
+ common::UsageWarning::Portability,
pointerArg->sourceLocation(),
"POINTER= argument of ASSOCIATED() is required by some other compilers to be a valid left-hand side of a pointer assignment statement"_port_en_US)}) {
msg->Attach(std::move(
@@ -2087,10 +2061,8 @@ static void CheckReduce(
// TRANSFER (16.9.193)
static void CheckTransferOperandType(SemanticsContext &context,
const evaluate::DynamicType &type, const char *which) {
- if (type.IsPolymorphic() &&
- context.ShouldWarn(common::UsageWarning::PolymorphicTransferArg)) {
- context.foldingContext().messages().Say(
- common::UsageWarning::PolymorphicTransferArg,
+ if (type.IsPolymorphic()) {
+ context.foldingContext().Warn(common::UsageWarning::PolymorphicTransferArg,
"%s of TRANSFER is polymorphic"_warn_en_US, which);
} else if (!type.IsUnlimitedPolymorphic() &&
type.category() == TypeCategory::Derived &&
@@ -2098,7 +2070,7 @@ static void CheckTransferOperandType(SemanticsContext &context,
DirectComponentIterator directs{type.GetDerivedTypeSpec()};
if (auto bad{std::find_if(directs.begin(), directs.end(), IsDescriptor)};
bad != directs.end()) {
- evaluate::SayWithDeclaration(context.foldingContext().messages(), *bad,
+ evaluate::WarnWithDeclaration(context.foldingContext(), *bad,
common::UsageWarning::PointerComponentTransferArg,
"%s of TRANSFER contains allocatable or pointer component %s"_warn_en_US,
which, bad.BuildResultDesignatorName());
@@ -2128,8 +2100,8 @@ static void CheckTransfer(evaluate::ActualArguments &arguments,
messages.Say(
"Element size of MOLD= array may not be zero when SOURCE= is not empty"_err_en_US);
}
- } else if (context.ShouldWarn(common::UsageWarning::VoidMold)) {
- messages.Say(common::UsageWarning::VoidMold,
+ } else {
+ foldingContext.Warn(common::UsageWarning::VoidMold,
"Element size of MOLD= array may not be zero unless SOURCE= is empty"_warn_en_US);
}
}
@@ -2145,7 +2117,7 @@ static void CheckTransfer(evaluate::ActualArguments &arguments,
} else if (context.ShouldWarn(
common::UsageWarning::TransferSizePresence) &&
IsAllocatableOrObjectPointer(whole)) {
- messages.Say(common::UsageWarning::TransferSizePresence,
+ foldingContext.Warn(common::UsageWarning::TransferSizePresence,
"SIZE= argument that is allocatable or pointer must be present at execution; parenthesize to silence this warning"_warn_en_US);
}
}
@@ -2368,13 +2340,10 @@ bool CheckArguments(const characteristics::Procedure &proc,
/*extentErrors=*/true, ignoreImplicitVsExplicit)};
if (!buffer.empty()) {
if (treatingExternalAsImplicit) {
- if (context.ShouldWarn(
- common::UsageWarning::KnownBadImplicitInterface)) {
- if (auto *msg{messages.Say(
- common::UsageWarning::KnownBadImplicitInterface,
- "If the procedure's interface were explicit, this reference would be in error"_warn_en_US)}) {
- buffer.AttachTo(*msg, parser::Severity::Because);
- }
+ if (auto *msg{foldingContext.Warn(
+ common::UsageWarning::KnownBadImplicitInterface,
+ "If the procedure's interface were explicit, this reference would be in error"_warn_en_US)}) {
+ buffer.AttachTo(*msg, parser::Severity::Because);
} else {
buffer.clear();
}
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index d769f221b1983..5e05e834937aa 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -130,21 +130,14 @@ class CheckHelper {
}
template <typename FeatureOrUsageWarning, typename... A>
parser::Message *Warn(FeatureOrUsageWarning warning, A &&...x) {
- if (!context_.ShouldWarn(warning) || InModuleFile()) {
- return nullptr;
- } else {
- return messages_.Say(warning, std::forward<A>(x)...);
- }
+ return messages_.Warn(InModuleFile(), context_.languageFeatures(), warning,
+ std::forward<A>(x)...);
}
template <typename FeatureOrUsageWarning, typename... A>
parser::Message *Warn(
FeatureOrUsageWarning warning, parser::CharBlock source, A &&...x) {
- if (!context_.ShouldWarn(warning) ||
- FindModuleFileContaining(context_.FindScope(source))) {
- return nullptr;
- } else {
- return messages_.Say(warning, source, std::forward<A>(x)...);
- }
+ return messages_.Warn(FindModuleFileContaining(context_.FindScope(source)),
+ context_.languageFeatures(), warning, source, std::forward<A>(x)...);
}
bool IsResultOkToDiffer(const FunctionResult &);
void CheckGlobalName(const Symbol &);
@@ -326,7 +319,7 @@ void CheckHelper::Check(const Symbol &symbol) {
!IsDummy(symbol)) {
if (context_.IsEnabled(
common::LanguageFeature::IgnoreIrrelevantAttributes)) {
- context_.Warn(common::LanguageFeature::IgnoreIrrelevantAttributes,
+ Warn(common::LanguageFeature::IgnoreIrrelevantAttributes,
"Only a dummy argument should have an INTENT, VALUE, or OPTIONAL attribute"_warn_en_US);
} else {
messages_.Say(
@@ -3141,16 +3134,14 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
*dyType, &context_.languageFeatures())
.value_or(false)) {
if (type->category() == DeclTypeSpec::Logical) {
- if (context_.ShouldWarn(common::UsageWarning::LogicalVsCBool)) {
- msgs.Say(common::UsageWarning::LogicalVsCBool, component.name(),
- "A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL"_port_en_US);
- }
+ msgs.AddWarning(common::UsageWarning::LogicalVsCBool,
+ component.name(),
+ "A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL"_port_en_US);
} else if (type->category() == DeclTypeSpec::Character && dyType &&
dyType->kind() == 1) {
- if (context_.ShouldWarn(common::UsageWarning::BindCCharLength)) {
- msgs.Say(common::UsageWarning::BindCCharLength, component.name(),
- "A CHARACTER component of an interoperable type should have length 1"_port_en_US);
- }
+ msgs.AddWarning(common::UsageWarning::BindCCharLength,
+ component.name(),
+ "A CHARACTER component of an interoperable type should have length 1"_port_en_US);
} else {
msgs.Say(component.name(),
"Each component of an interoperable derived type must have an interoperable type"_err_en_US);
@@ -3165,10 +3156,9 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
}
}
if (derived->componentNames().empty()) { // F'2023 C1805
- if (context_.ShouldWarn(common::LanguageFeature::EmptyBindCDerivedType)) {
- msgs.Say(common::LanguageFeature::EmptyBindCDerivedType, symbol.name(),
- "A derived type with the BIND attribute should not be empty"_warn_en_US);
- }
+ msgs.AddWarning(common::LanguageFeature::EmptyBindCDerivedType,
+ symbol.name(),
+ "A derived type with the BIND attribute should not be empty"_warn_en_US);
}
}
if (msgs.AnyFatalError()) {
@@ -3218,7 +3208,7 @@ parser::Messages CheckHelper::WhyNotInteroperableObject(
if (derived && !derived->typeSymbol().attrs().test(Attr::BIND_C)) {
if (allowNonInteroperableType) { // portability warning only
evaluate::AttachDeclaration(
- context_.Warn(common::UsageWarning::Portability, symbol.name(),
+ Warn(common::UsageWarning::Portability, symbol.name(),
"The derived type of this interoperable object should be BIND(C)"_port_en_US),
derived->typeSymbol());
} else if (!context_.IsEnabled(
@@ -3260,10 +3250,10 @@ parser::Messages CheckHelper::WhyNotInteroperableObject(
} else if (type->category() == DeclTypeSpec::Logical) {
if (context_.ShouldWarn(common::UsageWarning::LogicalVsCBool)) {
if (IsDummy(symbol)) {
- msgs.Say(common::UsageWarning::LogicalVsCBool, symbol.name(),
+ Warn(common::UsageWarning::LogicalVsCBool, symbol.name(),
"A BIND(C) LOGICAL dummy argument should have the interoperable KIND=C_BOOL"_port_en_US);
} else {
- msgs.Say(common::UsageWarning::LogicalVsCBool, symbol.name(),
+ Warn(common::UsageWarning::LogicalVsCBool, symbol.name(),
"A BIND(C) LOGICAL object should have the interoperable KIND=C_BOOL"_port_en_US);
}
}
diff --git a/flang/test/Semantics/spec-expr.f90 b/flang/test/Semantics/spec-expr.f90
index 4d79f2ca188fc..f18638c7e9b54 100644
--- a/flang/test/Semantics/spec-expr.f90
+++ b/flang/test/Semantics/spec-expr.f90
@@ -29,14 +29,14 @@ subroutine s2(inArg, inoutArg, outArg, optArg)
outArg = 3
block
- !PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg'
+ !PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg' [-Whost-associated-intent-out-in-spec-expr]
real a(outArg)
!ERROR: Invalid specification expression: reference to OPTIONAL dummy argument 'optarg'
real b(optArg)
end block
contains
subroutine s2inner
- !PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg'
+ !PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg' [-Whost-associated-intent-out-in-spec-expr]
real a(outArg)
!ERROR: Invalid specification expression: reference to OPTIONAL dummy argument 'optarg'
real b(optArg)
>From 5d373c7c85063a6d55ba9d3583b469b1ba9d60a1 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Mon, 18 Aug 2025 16:52:15 -0700
Subject: [PATCH 2/3] remove AddWarning
---
flang/include/flang/Parser/message.h | 24 +++++++++-------------
flang/lib/Semantics/check-declarations.cpp | 6 +++---
2 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h
index 46aec5bb3dc12..db6f4e3211bf2 100644
--- a/flang/include/flang/Parser/message.h
+++ b/flang/include/flang/Parser/message.h
@@ -335,24 +335,12 @@ class Messages {
return messages_.emplace_back(std::forward<A>(args)...);
}
- // AddWarning bypasses the language feature control, it is only exposed for
- // legacy code that cannot be easily refactored to use Warn().
- template <typename... A>
- Message &AddWarning(common::UsageWarning warning, A &&...args) {
- return messages_.emplace_back(warning, std::forward<A>(args)...);
- }
-
- template <typename... A>
- Message &AddWarning(common::LanguageFeature feature, A &&...args) {
- return messages_.emplace_back(feature, std::forward<A>(args)...);
- }
-
template <typename... A>
Message *Warn(bool isInModuleFile,
const common::LanguageFeatureControl &control,
common::LanguageFeature feature, A &&...args) {
if (!isInModuleFile && control.ShouldWarn(feature)) {
- return &AddWarning(feature, std::forward<A>(args)...);
+ return &addWarning(feature, std::forward<A>(args)...);
}
return nullptr;
}
@@ -362,7 +350,7 @@ class Messages {
const common::LanguageFeatureControl &control,
common::UsageWarning warning, A &&...args) {
if (!isInModuleFile && control.ShouldWarn(warning)) {
- return &AddWarning(warning, std::forward<A>(args)...);
+ return &addWarning(warning, std::forward<A>(args)...);
}
return nullptr;
}
@@ -383,6 +371,14 @@ class Messages {
bool AnyFatalError(bool warningsAreErrors = false) const;
private:
+ template <typename... A>
+ Message &addWarning(common::UsageWarning warning, A &&...args) {
+ return messages_.emplace_back(warning, std::forward<A>(args)...);
+ }
+ template <typename... A>
+ Message &addWarning(common::LanguageFeature feature, A &&...args) {
+ return messages_.emplace_back(feature, std::forward<A>(args)...);
+ }
std::list<Message> messages_;
};
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 5e05e834937aa..0e8e85dc836fd 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -3134,12 +3134,12 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
*dyType, &context_.languageFeatures())
.value_or(false)) {
if (type->category() == DeclTypeSpec::Logical) {
- msgs.AddWarning(common::UsageWarning::LogicalVsCBool,
+ context().Warn(msgs, common::UsageWarning::LogicalVsCBool,
component.name(),
"A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL"_port_en_US);
} else if (type->category() == DeclTypeSpec::Character && dyType &&
dyType->kind() == 1) {
- msgs.AddWarning(common::UsageWarning::BindCCharLength,
+ context().Warn(msgs, common::UsageWarning::BindCCharLength,
component.name(),
"A CHARACTER component of an interoperable type should have length 1"_port_en_US);
} else {
@@ -3156,7 +3156,7 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
}
}
if (derived->componentNames().empty()) { // F'2023 C1805
- msgs.AddWarning(common::LanguageFeature::EmptyBindCDerivedType,
+ context().Warn(msgs, common::LanguageFeature::EmptyBindCDerivedType,
symbol.name(),
"A derived type with the BIND attribute should not be empty"_warn_en_US);
}
>From f6f6186ddb5b500a9852ba2d3baae360387811af Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Mon, 18 Aug 2025 17:02:32 -0700
Subject: [PATCH 3/3] remove random include
---
flang/include/flang/Parser/message.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h
index db6f4e3211bf2..0eedd95a99f64 100644
--- a/flang/include/flang/Parser/message.h
+++ b/flang/include/flang/Parser/message.h
@@ -19,7 +19,6 @@
#include "flang/Common/reference-counted.h"
#include "flang/Common/restorer.h"
#include "flang/Support/Fortran-features.h"
-#include "llvm/Support/ErrorHandling.h"
#include <cstddef>
#include <cstring>
#include <forward_list>
More information about the flang-commits
mailing list