[flang] Warn on useless IOMSG= (#102250)

An I/O statement with IOMSG= but neither ERR= nor IOSTAT= deserves a
warning to the effect that it's not useful.
This commit is contained in:
Peter Klausler 2024-08-08 11:08:26 -07:00 committed by GitHub
parent 245eb0a716
commit b949a6f5e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 28 additions and 2 deletions

View File

@ -70,7 +70,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
IgnoredIntrinsicFunctionType, PreviousScalarUse,
RedeclaredInaccessibleComponent, ImplicitShared, IndexVarRedefinition,
IncompatibleImplicitInterfaces, BadTypeForTarget,
VectorSubscriptFinalization, UndefinedFunctionResult)
VectorSubscriptFinalization, UndefinedFunctionResult, UselessIomsg)
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
@ -145,6 +145,7 @@ public:
warnUsage_.set(UsageWarning::BadTypeForTarget);
warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
warnUsage_.set(UsageWarning::UndefinedFunctionResult);
warnUsage_.set(UsageWarning::UselessIomsg);
}
LanguageFeatureControl(const LanguageFeatureControl &) = default;

View File

@ -675,6 +675,7 @@ void IoChecker::Leave(const parser::BackspaceStmt &) {
CheckForPureSubprogram();
CheckForRequiredSpecifier(
flags_.test(Flag::NumberUnit), "UNIT number"); // C1240
CheckForUselessIomsg();
Done();
}
@ -682,6 +683,7 @@ void IoChecker::Leave(const parser::CloseStmt &) {
CheckForPureSubprogram();
CheckForRequiredSpecifier(
flags_.test(Flag::NumberUnit), "UNIT number"); // C1208
CheckForUselessIomsg();
Done();
}
@ -689,6 +691,7 @@ void IoChecker::Leave(const parser::EndfileStmt &) {
CheckForPureSubprogram();
CheckForRequiredSpecifier(
flags_.test(Flag::NumberUnit), "UNIT number"); // C1240
CheckForUselessIomsg();
Done();
}
@ -696,6 +699,7 @@ void IoChecker::Leave(const parser::FlushStmt &) {
CheckForPureSubprogram();
CheckForRequiredSpecifier(
flags_.test(Flag::NumberUnit), "UNIT number"); // C1243
CheckForUselessIomsg();
Done();
}
@ -708,6 +712,7 @@ void IoChecker::Leave(const parser::InquireStmt &stmt) {
"UNIT number or FILE"); // C1246
CheckForProhibitedSpecifier(IoSpecKind::File, IoSpecKind::Unit); // C1246
CheckForRequiredSpecifier(IoSpecKind::Id, IoSpecKind::Pending); // C1248
CheckForUselessIomsg();
}
Done();
}
@ -742,11 +747,13 @@ void IoChecker::Leave(const parser::OpenStmt &) {
CheckForProhibitedSpecifier(flags_.test(Flag::AccessStream),
"STATUS='STREAM'", IoSpecKind::Recl); // 12.5.6.15
}
CheckForUselessIomsg();
Done();
}
void IoChecker::Leave(const parser::PrintStmt &) {
CheckForPureSubprogram();
CheckForUselessIomsg();
Done();
}
@ -817,6 +824,7 @@ void IoChecker::Leave(const parser::RewindStmt &) {
CheckForRequiredSpecifier(
flags_.test(Flag::NumberUnit), "UNIT number"); // C1240
CheckForPureSubprogram();
CheckForUselessIomsg();
Done();
}
@ -824,6 +832,7 @@ void IoChecker::Leave(const parser::WaitStmt &) {
CheckForRequiredSpecifier(
flags_.test(Flag::NumberUnit), "UNIT number"); // C1237
CheckForPureSubprogram();
CheckForUselessIomsg();
Done();
}
@ -883,6 +892,7 @@ void IoChecker::LeaveReadWrite() const {
"FMT or NML"); // C1227
CheckForRequiredSpecifier(IoSpecKind::Round, flags_.test(Flag::FmtOrNml),
"FMT or NML"); // C1227
CheckForUselessIomsg();
}
void IoChecker::SetSpecifier(IoSpecKind specKind) {
@ -1057,6 +1067,15 @@ void IoChecker::CheckForPureSubprogram() const { // C1597
}
}
void IoChecker::CheckForUselessIomsg() const {
if (specifierSet_.test(IoSpecKind::Iomsg) &&
!specifierSet_.test(IoSpecKind::Err) &&
!specifierSet_.test(IoSpecKind::Iostat) &&
context_.ShouldWarn(common::UsageWarning::UselessIomsg)) {
context_.Say("IOMSG= is useless without either ERR= or IOSTAT="_warn_en_US);
}
}
// Seeks out an allocatable or pointer ultimate component that is not
// nested in a nonallocatable/nonpointer component with a specific
// defined I/O procedure.

View File

@ -125,6 +125,7 @@ private:
void CheckForDefinableVariable(const A &var, const std::string &s) const;
void CheckForPureSubprogram() const;
void CheckForUselessIomsg() const;
parser::Message *CheckForBadIoType(const evaluate::DynamicType &,
common::DefinedIo, parser::CharBlock) const;

View File

@ -221,10 +221,13 @@ static bool PerformStatementSemantics(
if (context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) {
SemanticsVisitor<CUDAChecker>{context}.Walk(program);
}
if (!context.AnyFatalError()) {
if (!context.messages().AnyFatalError()) {
// Do this if all messages are only warnings
if (context.ShouldWarn(common::UsageWarning::UndefinedFunctionResult)) {
WarnUndefinedFunctionResult(context, context.globalScope());
}
}
if (!context.AnyFatalError()) {
pass2.CompileDataInitializationsIntoInitializers();
}
return !context.AnyFatalError();

View File

@ -55,6 +55,7 @@
inquire(1, read=c(1), write=c(2), sign=c(3), sign=c(4), read=c(5), write=c(1))
!ERROR: Duplicate IOMSG specifier
!WARNING: IOMSG= is useless without either ERR= or IOSTAT=
inquire(10, iomsg=msg, pos=ipos, iomsg=msg)
!ERROR: If ID appears, PENDING must also appear

View File

@ -121,6 +121,7 @@ integer function defdBySize()
end
character(40) function defdByIomsg()
!WARNING: IOMSG= is useless without either ERR= or IOSTAT=
write(123,*,iomsg=defdByIomsg)
end