From cbcaae2b5c33ef316f25538bc5cb4c88b71d2f22 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Thu, 26 Feb 2026 06:59:49 -0800 Subject: [PATCH] [flang] Warn about assumed-rank items in I/O lists (#182957) An assumed-rank dummy argument is not a conforming I/O list or NAMELIST group item. Add a -pedantic warning and some documentation. --- flang/docs/Extensions.md | 1 + .../include/flang/Support/Fortran-features.h | 2 +- flang/lib/Semantics/check-io.cpp | 26 +++++++++++++++---- flang/lib/Semantics/check-io.h | 1 + flang/lib/Semantics/resolve-names.cpp | 7 +++++ flang/test/Semantics/io16.f90 | 15 +++++++++++ 6 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 flang/test/Semantics/io16.f90 diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 79e6213f7f3c..028e3ea80623 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -483,6 +483,7 @@ end are to the same value. Distinct initializations remain errors. * A pointer component that has no default initialization or explicit value in a structure constructor is defaulted to `NULL()`. +* An assumed-rank entity is an acceptable `NAMELIST` group item. ### Extensions supported when enabled by options diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h index f6c963d05fd5..e5cf915e9f78 100644 --- a/flang/include/flang/Support/Fortran-features.h +++ b/flang/include/flang/Support/Fortran-features.h @@ -57,7 +57,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, ForwardRefExplicitTypeDummy, InaccessibleDeferredOverride, CudaWarpMatchFunction, DoConcurrentOffload, TransferBOZ, Coarray, PointerPassObject, MultipleIdenticalDATA, - DefaultStructConstructorNullPointer) + DefaultStructConstructorNullPointer, AssumedRankIoItem) // Portability and suspicious usage warnings ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, diff --git a/flang/lib/Semantics/check-io.cpp b/flang/lib/Semantics/check-io.cpp index 19059ad1b122..2d7e419e76ce 100644 --- a/flang/lib/Semantics/check-io.cpp +++ b/flang/lib/Semantics/check-io.cpp @@ -327,10 +327,12 @@ void IoChecker::Enter(const parser::InputItem &spec) { } CheckForDefinableVariable(*var, "Input"); if (auto expr{AnalyzeExpr(context_, *var)}) { + auto at{var->GetSource()}; + CheckForAssumedRank(UnwrapWholeSymbolDataRef(*expr), at); CheckForBadIoType(*expr, flags_.test(Flag::FmtOrNml) ? common::DefinedIo::ReadFormatted : common::DefinedIo::ReadUnformatted, - var->GetSource()); + at); } } @@ -651,11 +653,14 @@ void IoChecker::Enter(const parser::OutputItem &item) { } else if (IsProcedure(*expr)) { context_.Say(parser::FindSourceLocation(*x), "Output item must not be a procedure"_err_en_US); // C1233 + } else { + auto at{parser::FindSourceLocation(item)}; + CheckForAssumedRank(UnwrapWholeSymbolDataRef(*expr), at); + CheckForBadIoType(*expr, + flags_.test(Flag::FmtOrNml) ? common::DefinedIo::WriteFormatted + : common::DefinedIo::WriteUnformatted, + at); } - CheckForBadIoType(*expr, - flags_.test(Flag::FmtOrNml) ? common::DefinedIo::WriteFormatted - : common::DefinedIo::WriteUnformatted, - parser::FindSourceLocation(item)); } } } @@ -1228,6 +1233,17 @@ parser::Message *IoChecker::CheckForBadIoType(const Symbol &symbol, return nullptr; } +void IoChecker::CheckForAssumedRank( + const Symbol *symbol, parser::CharBlock namelistLocation) const { + if (symbol && IsAssumedRank(*symbol)) { + evaluate::AttachDeclaration( + context_.Say(namelistLocation, + "Assumed-rank object '%s' may not be an I/O list item"_err_en_US, + symbol->name()), + *symbol); + } +} + void IoChecker::CheckNamelist(const Symbol &namelist, common::DefinedIo which, parser::CharBlock namelistLocation) const { if (!context_.HasError(namelist)) { diff --git a/flang/lib/Semantics/check-io.h b/flang/lib/Semantics/check-io.h index 2fb03c63afe3..96a07ce13f7b 100644 --- a/flang/lib/Semantics/check-io.h +++ b/flang/lib/Semantics/check-io.h @@ -133,6 +133,7 @@ private: const SomeExpr &, common::DefinedIo, parser::CharBlock) const; parser::Message *CheckForBadIoType( const Symbol &, common::DefinedIo, parser::CharBlock) const; + void CheckForAssumedRank(const Symbol *, parser::CharBlock) const; void CheckNamelist( const Symbol &, common::DefinedIo, parser::CharBlock) const; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 9036defa0c71..35b1cc282fdd 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -7228,6 +7228,13 @@ void DeclarationVisitor::FinishNamelists() { } else if (!ConvertToObjectEntity(symbol->GetUltimate())) { SayWithDecl(name, *symbol, "'%s' is not a variable"_err_en_US); context().SetError(*groupSymbol); + } else if (IsAssumedRank(*symbol)) { + evaluate::AttachDeclaration( + context().Warn(common::LanguageFeature::AssumedRankIoItem, + name.source, + "Assumed-rank object '%s' should not be a namelist group item"_port_en_US, + symbol->name()), + *symbol); } symbol->GetUltimate().set(Symbol::Flag::InNamelist); details->add_object(*symbol); diff --git a/flang/test/Semantics/io16.f90 b/flang/test/Semantics/io16.f90 new file mode 100644 index 000000000000..7d721d2ba40d --- /dev/null +++ b/flang/test/Semantics/io16.f90 @@ -0,0 +1,15 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic +subroutine assumedRank(x, y) + real x(..), y(*) + !PORTABILITY: Assumed-rank object 'x' should not be a namelist group item [-Wassumed-rank-io-item] + !ERROR: A namelist group object 'y' must not be assumed-size + namelist /nml/x, y + !ERROR: Assumed-rank object 'x' may not be an I/O list item + !ERROR: Whole assumed-size array 'y' may not appear here without subscripts + read *, x, y + !ERROR: Assumed-rank object 'x' may not be an I/O list item + !ERROR: Whole assumed-size array 'y' may not appear here without subscripts + print *, x, y + read(*,nml=nml) + write(*,nml=nml) +end