diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index d3cb2f142c54b..bb9c0ebe84a16 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -283,6 +283,8 @@ end * When a name is brought into a scope by multiple ways, such as USE-association as well as an `IMPORT` from its host, it's an error only if the resolution is ambiguous. +* An entity may appear in a `DATA` statement before its explicit + type declaration under `IMPLICIT NONE(TYPE)`. ### Extensions supported when enabled by options diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h index 3539c9aeab576..5cbe1d6e157f2 100644 --- a/flang/include/flang/Common/Fortran-features.h +++ b/flang/include/flang/Common/Fortran-features.h @@ -36,7 +36,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, ForwardRefImplicitNone, OpenAccessAppend, BOZAsDefaultInteger, DistinguishableSpecifics, DefaultSave, PointerInSeqType, NonCharacterFormat, SaveMainProgram, SaveBigMainProgramVariables, - DistinctArrayConstructorLengths, PPCVector, RelaxedIntentInChecking) + DistinctArrayConstructorLengths, PPCVector, RelaxedIntentInChecking, + ForwardRefImplicitNoneData) // Portability and suspicious usage warnings for conforming code ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index dfff0458fec45..3afba79781a05 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -697,6 +697,7 @@ class ScopeHandler : public ImplicitRulesVisitor { bool CheckPossibleBadForwardRef(const Symbol &); bool inSpecificationPart_{false}; + bool inDataStmtObject_{false}; bool inEquivalenceStmt_{false}; // Some information is collected from a specification part for deferred @@ -2481,6 +2482,9 @@ void ScopeHandler::ApplyImplicitRules( // or object, it'll be caught later. return; } + if (inDataStmtObject_) { + return; + } if (!context().HasError(symbol)) { Say(symbol.name(), "No explicit type declared for '%s'"_err_en_US); context().SetError(symbol); @@ -2654,7 +2658,7 @@ const DeclTypeSpec &ScopeHandler::MakeLogicalType(int kind) { } void ScopeHandler::NotePossibleBadForwardRef(const parser::Name &name) { - if (inSpecificationPart_ && name.symbol) { + if (inSpecificationPart_ && !inDataStmtObject_ && name.symbol) { auto kind{currScope().kind()}; if ((kind == Scope::Kind::Subprogram && !currScope().IsStmtFunction()) || kind == Scope::Kind::BlockConstruct) { @@ -6281,6 +6285,12 @@ void DeclarationVisitor::SetType( } auto *prevType{symbol.GetType()}; if (!prevType) { + if (symbol.test(Symbol::Flag::InDataStmt) && isImplicitNoneType() && + context().ShouldWarn( + common::LanguageFeature::ForwardRefImplicitNoneData)) { + Say(name, + "'%s' appeared in a DATA statement before its type was declared under IMPLICIT NONE(TYPE)"_port_en_US); + } symbol.SetType(type); } else if (symbol.has()) { // error recovery case, redeclaration of use-associated name @@ -6642,6 +6652,7 @@ bool ConstructVisitor::Pre(const parser::DataStmtObject &x) { auto flagRestorer{common::ScopedSet(inSpecificationPart_, false)}; common::visit(common::visitors{ [&](const Indirection &y) { + auto restorer{common::ScopedSet(inDataStmtObject_, true)}; Walk(y.value()); const parser::Name &first{ parser::GetFirstName(y.value())}; @@ -7199,7 +7210,7 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) { } return &name; } - if (isImplicitNoneType()) { + if (isImplicitNoneType() && !inDataStmtObject_) { Say(name, "No explicit type declared for '%s'"_err_en_US); return nullptr; } diff --git a/flang/test/Semantics/resolve30.f90 b/flang/test/Semantics/resolve30.f90 index c594cceef15b1..32108e89cdefe 100644 --- a/flang/test/Semantics/resolve30.f90 +++ b/flang/test/Semantics/resolve30.f90 @@ -1,4 +1,4 @@ -! RUN: %python %S/test_errors.py %s %flang_fc1 +! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic subroutine s1 integer x block @@ -37,3 +37,10 @@ subroutine s4 !ERROR: Must have INTEGER type, but is REAL(4) data(b(j), j=1, 16) / 16 * 0.0 / end + +subroutine s5 + implicit none + data x/1./ + !PORTABILITY: 'x' appeared in a DATA statement before its type was declared under IMPLICIT NONE(TYPE) + real x +end