Skip to content

Commit c649d31

Browse files
authored
[flang][warnings] systematically guard warnings (#154234)
This change modifies the messages API to make it impossible to forget to call ShouldWarn by moving the call inside of the API. The low level API should be avoided and developers should call Warn on a SemanticContext or FoldingContext.
1 parent 6bd8448 commit c649d31

23 files changed

+449
-574
lines changed

flang/include/flang/Evaluate/common.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,24 @@ class FoldingContext {
255255
const common::LanguageFeatureControl &languageFeatures() const {
256256
return languageFeatures_;
257257
}
258+
template <typename... A>
259+
parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
260+
return messages_.Warn(
261+
IsInModuleFile(), languageFeatures_, feature, std::forward<A>(args)...);
262+
}
263+
template <typename... A>
264+
parser::Message *Warn(common::UsageWarning warning, A &&...args) {
265+
return messages_.Warn(
266+
IsInModuleFile(), languageFeatures_, warning, std::forward<A>(args)...);
267+
}
258268
std::optional<parser::CharBlock> moduleFileName() const {
259269
return moduleFileName_;
260270
}
261271
FoldingContext &set_moduleFileName(std::optional<parser::CharBlock> n) {
262272
moduleFileName_ = n;
263273
return *this;
264274
}
275+
bool IsInModuleFile() const { return moduleFileName_.has_value(); }
265276

266277
ConstantSubscript &StartImpliedDo(parser::CharBlock, ConstantSubscript = 1);
267278
std::optional<ConstantSubscript> GetImpliedDo(parser::CharBlock) const;

flang/include/flang/Evaluate/tools.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,18 @@ parser::Message *SayWithDeclaration(
11161116
MESSAGES &messages, const Symbol &symbol, A &&...x) {
11171117
return AttachDeclaration(messages.Say(std::forward<A>(x)...), symbol);
11181118
}
1119+
template <typename... A>
1120+
parser::Message *WarnWithDeclaration(FoldingContext context,
1121+
const Symbol &symbol, common::LanguageFeature feature, A &&...x) {
1122+
return AttachDeclaration(
1123+
context.Warn(feature, std::forward<A>(x)...), symbol);
1124+
}
1125+
template <typename... A>
1126+
parser::Message *WarnWithDeclaration(FoldingContext &context,
1127+
const Symbol &symbol, common::UsageWarning warning, A &&...x) {
1128+
return AttachDeclaration(
1129+
context.Warn(warning, std::forward<A>(x)...), symbol);
1130+
}
11191131

11201132
// Check for references to impure procedures; returns the name
11211133
// of one to complain about, if any exist.

flang/include/flang/Parser/message.h

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,23 @@ class Messages {
335335
}
336336

337337
template <typename... A>
338-
Message &Say(common::LanguageFeature feature, A &&...args) {
339-
return Say(std::forward<A>(args)...).set_languageFeature(feature);
338+
Message *Warn(bool isInModuleFile,
339+
const common::LanguageFeatureControl &control,
340+
common::LanguageFeature feature, A &&...args) {
341+
if (!isInModuleFile && control.ShouldWarn(feature)) {
342+
return &AddWarning(feature, std::forward<A>(args)...);
343+
}
344+
return nullptr;
340345
}
341346

342347
template <typename... A>
343-
Message &Say(common::UsageWarning warning, A &&...args) {
344-
return Say(std::forward<A>(args)...).set_usageWarning(warning);
348+
Message *Warn(bool isInModuleFile,
349+
const common::LanguageFeatureControl &control,
350+
common::UsageWarning warning, A &&...args) {
351+
if (!isInModuleFile && control.ShouldWarn(warning)) {
352+
return &AddWarning(warning, std::forward<A>(args)...);
353+
}
354+
return nullptr;
345355
}
346356

347357
void Annex(Messages &&that) {
@@ -360,6 +370,14 @@ class Messages {
360370
bool AnyFatalError(bool warningsAreErrors = false) const;
361371

362372
private:
373+
template <typename... A>
374+
Message &AddWarning(common::UsageWarning warning, A &&...args) {
375+
return messages_.emplace_back(warning, std::forward<A>(args)...);
376+
}
377+
template <typename... A>
378+
Message &AddWarning(common::LanguageFeature feature, A &&...args) {
379+
return messages_.emplace_back(feature, std::forward<A>(args)...);
380+
}
363381
std::list<Message> messages_;
364382
};
365383

@@ -422,24 +440,6 @@ class ContextualMessages {
422440
return Say(at.value_or(at_), std::forward<A>(args)...);
423441
}
424442

425-
template <typename... A>
426-
Message *Say(common::LanguageFeature feature, A &&...args) {
427-
Message *msg{Say(std::forward<A>(args)...)};
428-
if (msg) {
429-
msg->set_languageFeature(feature);
430-
}
431-
return msg;
432-
}
433-
434-
template <typename... A>
435-
Message *Say(common::UsageWarning warning, A &&...args) {
436-
Message *msg{Say(std::forward<A>(args)...)};
437-
if (msg) {
438-
msg->set_usageWarning(warning);
439-
}
440-
return msg;
441-
}
442-
443443
Message *Say(Message &&msg) {
444444
if (messages_ != nullptr) {
445445
if (contextMessage_) {
@@ -451,6 +451,39 @@ class ContextualMessages {
451451
}
452452
}
453453

454+
template <typename FeatureOrUsageWarning, typename... A>
455+
Message *Warn(bool isInModuleFile,
456+
const common::LanguageFeatureControl &control,
457+
FeatureOrUsageWarning feature, CharBlock at, A &&...args) {
458+
if (messages_ != nullptr) {
459+
if (Message *
460+
msg{messages_->Warn(isInModuleFile, control, feature, at,
461+
std::forward<A>(args)...)}) {
462+
if (contextMessage_) {
463+
msg->SetContext(contextMessage_.get());
464+
}
465+
return msg;
466+
}
467+
}
468+
return nullptr;
469+
}
470+
471+
template <typename FeatureOrUsageWarning, typename... A>
472+
Message *Warn(bool isInModuleFile,
473+
const common::LanguageFeatureControl &control,
474+
FeatureOrUsageWarning feature, A &&...args) {
475+
return Warn(
476+
isInModuleFile, control, feature, at_, std::forward<A>(args)...);
477+
}
478+
479+
template <typename FeatureOrUsageWarning, typename... A>
480+
Message *Warn(bool isInModuleFile,
481+
const common::LanguageFeatureControl &control,
482+
FeatureOrUsageWarning feature, std::optional<CharBlock> at, A &&...args) {
483+
return Warn(isInModuleFile, control, feature, at.value_or(at_),
484+
std::forward<A>(args)...);
485+
}
486+
454487
private:
455488
CharBlock at_;
456489
Messages *messages_{nullptr};

flang/include/flang/Semantics/semantics.h

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,59 @@ class SemanticsContext {
200200
return message;
201201
}
202202

203-
template <typename FeatureOrUsageWarning, typename... A>
203+
template <typename... A>
204+
parser::Message *Warn(parser::Messages &messages,
205+
common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
206+
return messages.Warn(IsInModuleFile(at), languageFeatures_, feature, at,
207+
std::forward<A>(args)...);
208+
}
209+
template <typename... A>
210+
parser::Message *Warn(parser::Messages &messages,
211+
common::UsageWarning warning, parser::CharBlock at, A &&...args) {
212+
return messages.Warn(IsInModuleFile(at), languageFeatures_, warning, at,
213+
std::forward<A>(args)...);
214+
}
215+
template <typename... A>
216+
parser::Message *Warn(parser::ContextualMessages &messages,
217+
common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
218+
return messages.Warn(IsInModuleFile(at), languageFeatures_, feature, at,
219+
std::forward<A>(args)...);
220+
}
221+
template <typename... A>
222+
parser::Message *Warn(parser::ContextualMessages &messages,
223+
common::UsageWarning warning, parser::CharBlock at, A &&...args) {
224+
return messages.Warn(IsInModuleFile(at), languageFeatures_, warning, at,
225+
std::forward<A>(args)...);
226+
}
227+
template <typename... A>
228+
parser::Message *Warn(parser::ContextualMessages &messages,
229+
common::LanguageFeature feature, A &&...args) {
230+
return messages.Warn(IsInModuleFile(messages.at()), languageFeatures_,
231+
feature, messages.at(), std::forward<A>(args)...);
232+
}
233+
template <typename... A>
234+
parser::Message *Warn(parser::ContextualMessages &messages,
235+
common::UsageWarning warning, A &&...args) {
236+
return messages.Warn(IsInModuleFile(messages.at()), languageFeatures_,
237+
warning, messages.at(), std::forward<A>(args)...);
238+
}
239+
template <typename... A>
240+
parser::Message *Warn(
241+
common::LanguageFeature feature, parser::CharBlock at, A &&...args) {
242+
return Warn(messages_, feature, at, std::forward<A>(args)...);
243+
}
244+
template <typename... A>
204245
parser::Message *Warn(
205-
FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
206-
if (languageFeatures_.ShouldWarn(warning) && !IsInModuleFile(at)) {
207-
parser::Message &msg{
208-
messages_.Say(warning, at, std::forward<A>(args)...)};
209-
return &msg;
210-
} else {
211-
return nullptr;
212-
}
213-
}
214-
215-
template <typename FeatureOrUsageWarning, typename... A>
216-
parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
246+
common::UsageWarning warning, parser::CharBlock at, A &&...args) {
247+
return Warn(messages_, warning, at, std::forward<A>(args)...);
248+
}
249+
template <typename... A>
250+
parser::Message *Warn(common::LanguageFeature feature, A &&...args) {
251+
CHECK(location_);
252+
return Warn(feature, *location_, std::forward<A>(args)...);
253+
}
254+
template <typename... A>
255+
parser::Message *Warn(common::UsageWarning warning, A &&...args) {
217256
CHECK(location_);
218257
return Warn(warning, *location_, std::forward<A>(args)...);
219258
}

flang/lib/Evaluate/check-expression.cpp

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ class SuspiciousRealLiteralFinder
415415
template <int KIND>
416416
bool operator()(const Constant<Type<TypeCategory::Real, KIND>> &x) const {
417417
if (kind_ > KIND && x.result().isFromInexactLiteralConversion()) {
418-
context_.messages().Say(common::UsageWarning::RealConstantWidening,
418+
context_.Warn(common::UsageWarning::RealConstantWidening,
419419
"Default real literal in REAL(%d) context might need a kind suffix, as its rounded value %s is inexact"_warn_en_US,
420420
kind_, x.AsFortran());
421421
return true;
@@ -426,7 +426,7 @@ class SuspiciousRealLiteralFinder
426426
template <int KIND>
427427
bool operator()(const Constant<Type<TypeCategory::Complex, KIND>> &x) const {
428428
if (kind_ > KIND && x.result().isFromInexactLiteralConversion()) {
429-
context_.messages().Say(common::UsageWarning::RealConstantWidening,
429+
context_.Warn(common::UsageWarning::RealConstantWidening,
430430
"Default real literal in COMPLEX(%d) context might need a kind suffix, as its rounded value %s is inexact"_warn_en_US,
431431
kind_, x.AsFortran());
432432
return true;
@@ -504,11 +504,8 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
504504
symbol.owner().context().IsEnabled(
505505
common::LanguageFeature::LogicalIntegerAssignment)) {
506506
converted = DataConstantConversionExtension(context, symTS->type(), x);
507-
if (converted &&
508-
symbol.owner().context().ShouldWarn(
509-
common::LanguageFeature::LogicalIntegerAssignment)) {
510-
context.messages().Say(
511-
common::LanguageFeature::LogicalIntegerAssignment,
507+
if (converted) {
508+
context.Warn(common::LanguageFeature::LogicalIntegerAssignment,
512509
"nonstandard usage: initialization of %s with %s"_port_en_US,
513510
symTS->type().AsFortran(), x.GetType().value().AsFortran());
514511
}
@@ -663,10 +660,8 @@ class CheckSpecificationExprHelper
663660
// host-associated dummy argument, and that doesn't seem like a
664661
// good idea.
665662
if (!inInquiry_ && hasHostAssociation &&
666-
ultimate.attrs().test(semantics::Attr::INTENT_OUT) &&
667-
context_.languageFeatures().ShouldWarn(
668-
common::UsageWarning::HostAssociatedIntentOutInSpecExpr)) {
669-
context_.messages().Say(
663+
ultimate.attrs().test(semantics::Attr::INTENT_OUT)) {
664+
context_.Warn(common::UsageWarning::HostAssociatedIntentOutInSpecExpr,
670665
"specification expression refers to host-associated INTENT(OUT) dummy argument '%s'"_port_en_US,
671666
ultimate.name());
672667
}
@@ -677,13 +672,9 @@ class CheckSpecificationExprHelper
677672
} else if (isInitialized &&
678673
context_.languageFeatures().IsEnabled(
679674
common::LanguageFeature::SavedLocalInSpecExpr)) {
680-
if (!scope_.IsModuleFile() &&
681-
context_.languageFeatures().ShouldWarn(
682-
common::LanguageFeature::SavedLocalInSpecExpr)) {
683-
context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
684-
"specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
685-
ultimate.name());
686-
}
675+
context_.Warn(common::LanguageFeature::SavedLocalInSpecExpr,
676+
"specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
677+
ultimate.name());
687678
return std::nullopt;
688679
} else if (const auto *object{
689680
ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {

flang/lib/Evaluate/common.cpp

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,22 @@ namespace Fortran::evaluate {
1616
void RealFlagWarnings(
1717
FoldingContext &context, const RealFlags &flags, const char *operation) {
1818
static constexpr auto warning{common::UsageWarning::FoldingException};
19-
if (context.languageFeatures().ShouldWarn(warning)) {
20-
if (flags.test(RealFlag::Overflow)) {
21-
context.messages().Say(warning, "overflow on %s"_warn_en_US, operation);
22-
}
23-
if (flags.test(RealFlag::DivideByZero)) {
24-
if (std::strcmp(operation, "division") == 0) {
25-
context.messages().Say(warning, "division by zero"_warn_en_US);
26-
} else {
27-
context.messages().Say(
28-
warning, "division by zero on %s"_warn_en_US, operation);
29-
}
30-
}
31-
if (flags.test(RealFlag::InvalidArgument)) {
32-
context.messages().Say(
33-
warning, "invalid argument on %s"_warn_en_US, operation);
34-
}
35-
if (flags.test(RealFlag::Underflow)) {
36-
context.messages().Say(warning, "underflow on %s"_warn_en_US, operation);
19+
if (flags.test(RealFlag::Overflow)) {
20+
context.Warn(warning, "overflow on %s"_warn_en_US, operation);
21+
}
22+
if (flags.test(RealFlag::DivideByZero)) {
23+
if (std::strcmp(operation, "division") == 0) {
24+
context.Warn(warning, "division by zero"_warn_en_US);
25+
} else {
26+
context.Warn(warning, "division by zero on %s"_warn_en_US, operation);
3727
}
3828
}
29+
if (flags.test(RealFlag::InvalidArgument)) {
30+
context.Warn(warning, "invalid argument on %s"_warn_en_US, operation);
31+
}
32+
if (flags.test(RealFlag::Underflow)) {
33+
context.Warn(warning, "underflow on %s"_warn_en_US, operation);
34+
}
3935
}
4036

4137
ConstantSubscript &FoldingContext::StartImpliedDo(

flang/lib/Evaluate/fold-character.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,10 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
5858
return FoldElementalIntrinsic<T, IntT>(context, std::move(funcRef),
5959
ScalarFunc<T, IntT>([&](const Scalar<IntT> &i) {
6060
if (i.IsNegative() || i.BGE(Scalar<IntT>{0}.IBSET(8 * KIND))) {
61-
if (context.languageFeatures().ShouldWarn(
62-
common::UsageWarning::FoldingValueChecks)) {
63-
context.messages().Say(common::UsageWarning::FoldingValueChecks,
64-
"%s(I=%jd) is out of range for CHARACTER(KIND=%d)"_warn_en_US,
65-
parser::ToUpperCaseLetters(name),
66-
static_cast<std::intmax_t>(i.ToInt64()), KIND);
67-
}
61+
context.Warn(common::UsageWarning::FoldingValueChecks,
62+
"%s(I=%jd) is out of range for CHARACTER(KIND=%d)"_warn_en_US,
63+
parser::ToUpperCaseLetters(name),
64+
static_cast<std::intmax_t>(i.ToInt64()), KIND);
6865
}
6966
return CharacterUtils<KIND>::CHAR(i.ToUInt64());
7067
}));
@@ -106,12 +103,9 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
106103
static_cast<std::intmax_t>(n));
107104
} else if (static_cast<double>(n) * str.size() >
108105
(1 << 20)) { // sanity limit of 1MiB
109-
if (context.languageFeatures().ShouldWarn(
110-
common::UsageWarning::FoldingLimit)) {
111-
context.messages().Say(common::UsageWarning::FoldingLimit,
112-
"Result of REPEAT() is too large to compute at compilation time (%g characters)"_port_en_US,
113-
static_cast<double>(n) * str.size());
114-
}
106+
context.Warn(common::UsageWarning::FoldingLimit,
107+
"Result of REPEAT() is too large to compute at compilation time (%g characters)"_port_en_US,
108+
static_cast<double>(n) * str.size());
115109
} else {
116110
return Expr<T>{Constant<T>{CharacterUtils<KIND>::REPEAT(str, n)}};
117111
}

flang/lib/Evaluate/fold-complex.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldIntrinsicFunction(
2929
if (auto callable{GetHostRuntimeWrapper<T, T>(name)}) {
3030
return FoldElementalIntrinsic<T, T>(
3131
context, std::move(funcRef), *callable);
32-
} else if (context.languageFeatures().ShouldWarn(
33-
common::UsageWarning::FoldingFailure)) {
34-
context.messages().Say(common::UsageWarning::FoldingFailure,
32+
} else {
33+
context.Warn(common::UsageWarning::FoldingFailure,
3534
"%s(complex(kind=%d)) cannot be folded on host"_warn_en_US, name,
3635
KIND);
3736
}

0 commit comments

Comments
 (0)