diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -123,6 +123,7 @@ bool HasIntrinsicTypeName(const Symbol &); bool IsSeparateModuleProcedureInterface(const Symbol *); bool HasAlternateReturns(const Symbol &); +bool IsAutomaticallyDestroyed(const Symbol &); // Return an ultimate component of type that matches predicate, or nullptr. const Symbol *FindUltimateComponent(const DerivedTypeSpec &type, @@ -167,11 +168,14 @@ return symbol.owner().kind() == Scope::Kind::ImpliedDos; } SymbolVector FinalsForDerivedTypeInstantiation(const DerivedTypeSpec &); -bool IsFinalizable( - const Symbol &, std::set * = nullptr); -bool IsFinalizable( - const DerivedTypeSpec &, std::set * = nullptr); -bool HasImpureFinal(const DerivedTypeSpec &); +// Returns a non-null pointer to a FINAL procedure, if any. +const Symbol *IsFinalizable(const Symbol &, + std::set * = nullptr, + bool withImpureFinalizer = false); +const Symbol *IsFinalizable(const DerivedTypeSpec &, + std::set * = nullptr, + bool withImpureFinalizer = false, std::optional rank = std::nullopt); +const Symbol *HasImpureFinal(const Symbol &); bool IsInBlankCommon(const Symbol &); inline bool IsAssumedSizeArray(const Symbol &symbol) { const auto *details{symbol.detailsIf()}; @@ -565,8 +569,6 @@ const DerivedTypeSpec &); UltimateComponentIterator::const_iterator FindPolymorphicAllocatableUltimateComponent(const DerivedTypeSpec &); -UltimateComponentIterator::const_iterator -FindPolymorphicAllocatableNonCoarrayUltimateComponent(const DerivedTypeSpec &); // The LabelEnforce class (given a set of labels) provides an error message if // there is a branch to a label which is not in the given set. diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -1454,8 +1454,6 @@ // 8.5.16p4 // In main programs, implied SAVE matters only for pointer // initialization targets and coarrays. - // BLOCK DATA entities must all be in COMMON, - // which was checked above. return true; } else if (scopeKind == Scope::Kind::MainProgram && (features.IsEnabled(common::LanguageFeature::SaveMainProgram) || diff --git a/flang/lib/Semantics/check-deallocate.h b/flang/lib/Semantics/check-deallocate.h --- a/flang/lib/Semantics/check-deallocate.h +++ b/flang/lib/Semantics/check-deallocate.h @@ -22,7 +22,6 @@ void Leave(const parser::DeallocateStmt &); private: - bool CheckPolymorphism(parser::CharBlock, const Symbol &); SemanticsContext &context_; }; } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/check-deallocate.cpp b/flang/lib/Semantics/check-deallocate.cpp --- a/flang/lib/Semantics/check-deallocate.cpp +++ b/flang/lib/Semantics/check-deallocate.cpp @@ -37,11 +37,21 @@ {DefinabilityFlag::PointerDefinition, DefinabilityFlag::AcceptAllocatable}, *symbol)}) { + // Catch problems with non-definability of the + // pointer/allocatable context_ .Say(name.source, "Name in DEALLOCATE statement is not definable"_err_en_US) .Attach(std::move(*whyNot)); - } else if (CheckPolymorphism(name.source, *symbol)) { + } else if (auto whyNot{WhyNotDefinable(name.source, + context_.FindScope(name.source), + DefinabilityFlags{}, *symbol)}) { + // Catch problems with non-definability of the dynamic object + context_ + .Say(name.source, + "Object in DEALLOCATE statement is not deallocatable"_err_en_US) + .Attach(std::move(*whyNot)); + } else { context_.CheckIndexVarRedefine(name); } }, @@ -63,8 +73,13 @@ .Say(source, "Name in DEALLOCATE statement is not definable"_err_en_US) .Attach(std::move(*whyNot)); - } else { - CheckPolymorphism(source, *symbol); + } else if (auto whyNot{WhyNotDefinable(source, + context_.FindScope(source), + DefinabilityFlags{}, *expr)}) { + context_ + .Say(source, + "Object in DEALLOCATE statement is not deallocatable"_err_en_US) + .Attach(std::move(*whyNot)); } } } @@ -96,28 +111,4 @@ } } -bool DeallocateChecker::CheckPolymorphism( - parser::CharBlock source, const Symbol &symbol) { - if (FindPureProcedureContaining(context_.FindScope(source))) { - if (auto type{evaluate::DynamicType::From(symbol)}) { - if (type->IsPolymorphic()) { - context_.Say(source, - "'%s' may not be deallocated in a pure procedure because it is polymorphic"_err_en_US, - source); - return false; - } - if (!type->IsUnlimitedPolymorphic() && - type->category() == TypeCategory::Derived) { - if (auto iter{FindPolymorphicAllocatableUltimateComponent( - type->GetDerivedTypeSpec())}) { - context_.Say(source, - "'%s' may not be deallocated in a pure procedure because its type has a polymorphic allocatable ultimate component '%s'"_err_en_US, - source, iter->name()); - return false; - } - } - } - } - return true; -} } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -9,6 +9,7 @@ // Static declaration checking #include "check-declarations.h" +#include "definable.h" #include "pointer-assignment.h" #include "flang/Evaluate/check-expression.h" #include "flang/Evaluate/fold.h" @@ -312,19 +313,6 @@ "A pure subprogram may not have a variable with the SAVE attribute"_err_en_US); } } - if (!IsDummy(symbol) && !IsFunctionResult(symbol)) { - if (IsPolymorphicAllocatable(symbol)) { - SayWithDeclaration(symbol, - "Deallocation of polymorphic object '%s' is not permitted in a pure subprogram"_err_en_US, - symbol.name()); - } else if (derived) { - if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { - SayWithDeclaration(*bad, - "Deallocation of polymorphic object '%s%s' is not permitted in a pure subprogram"_err_en_US, - symbol.name(), bad.BuildResultDesignatorName()); - } - } - } } if (symbol.attrs().test(Attr::VOLATILE) && (IsDummy(symbol) || !InInterface())) { @@ -359,15 +347,17 @@ Check(*type, canHaveAssumedParameter); } if (InPure() && InFunction() && IsFunctionResult(symbol)) { - if (derived && HasImpureFinal(*derived)) { // C1584 - messages_.Say( - "Result of pure function may not have an impure FINAL subroutine"_err_en_US); - } if (type->IsPolymorphic() && IsAllocatable(symbol)) { // C1585 messages_.Say( "Result of pure function may not be both polymorphic and ALLOCATABLE"_err_en_US); } if (derived) { + // These cases would be caught be the general validation of local + // variables in a pure context, but these messages are more specific. + if (HasImpureFinal(symbol)) { // C1584 + messages_.Say( + "Result of pure function may not have an impure FINAL subroutine"_err_en_US); + } if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { SayWithDeclaration(*bad, "Result of pure function may not have polymorphic ALLOCATABLE ultimate component '%s'"_err_en_US, @@ -656,6 +646,9 @@ } if (details.isDummy()) { if (IsIntentOut(symbol)) { + // Some of these errors would also be caught by the general check + // for definability of automatically deallocated local variables, + // but these messages are more specific. if (FindUltimateComponent(symbol, [](const Symbol &x) { return evaluate::IsCoarray(x) && IsAllocatable(x); })) { // C846 @@ -701,7 +694,7 @@ messages_.Say( "An INTENT(OUT) dummy argument of a pure subroutine may not have a polymorphic ultimate component"_err_en_US); } - if (HasImpureFinal(*derived)) { // C1587 + if (HasImpureFinal(symbol)) { // C1587 messages_.Say( "An INTENT(OUT) dummy argument of a pure subroutine may not have an impure FINAL subroutine"_err_en_US); } @@ -789,6 +782,21 @@ "ALLOCATABLE or POINTER attribute"_err_en_US, symbol.name()); } + if (derived && InPure() && !InInterface() && + IsAutomaticallyDestroyed(symbol) && + !IsIntentOut(symbol) /*has better messages*/ && + !IsFunctionResult(symbol) /*ditto*/) { + // Check automatically deallocated local variables for possible + // problems with finalization in PURE. + if (auto whyNot{ + WhyNotDefinable(symbol.name(), symbol.owner(), {}, symbol)}) { + if (auto *msg{messages_.Say( + "'%s' may not be a local variable in a pure subprogram"_err_en_US, + symbol.name())}) { + msg->Attach(std::move(*whyNot)); + } + } + } } void CheckHelper::CheckPointerInitialization(const Symbol &symbol) { @@ -1735,7 +1743,9 @@ void CheckHelper::WarnMissingFinal(const Symbol &symbol) { const auto *object{symbol.detailsIf()}; - if (!object || IsPointer(symbol)) { + if (!object || + (!IsAutomaticallyDestroyed(symbol) && + symbol.owner().kind() != Scope::Kind::DerivedType)) { return; } const DeclTypeSpec *type{object->type()}; diff --git a/flang/lib/Semantics/check-do-forall.cpp b/flang/lib/Semantics/check-do-forall.cpp --- a/flang/lib/Semantics/check-do-forall.cpp +++ b/flang/lib/Semantics/check-do-forall.cpp @@ -115,19 +115,6 @@ // invocation of an IMPURE final subroutine. (C1139) // - // Only to be called for symbols with ObjectEntityDetails - static bool HasImpureFinal(const Symbol &original) { - const Symbol &symbol{ResolveAssociations(original)}; - if (symbol.has()) { - if (const DeclTypeSpec * symType{symbol.GetType()}) { - if (const DerivedTypeSpec * derived{symType->AsDerived()}) { - return semantics::HasImpureFinal(*derived); - } - } - } - return false; - } - // Predicate for deallocations caused by block exit and direct deallocation static bool DeallocateAll(const Symbol &) { return true; } @@ -166,11 +153,11 @@ return false; } - void SayDeallocateWithImpureFinal(const Symbol &entity, const char *reason) { + void SayDeallocateWithImpureFinal( + const Symbol &entity, const char *reason, const Symbol &impure) { context_.SayWithDecl(entity, currentStatementSourcePosition_, - "Deallocation of an entity with an IMPURE FINAL procedure" - " caused by %s not allowed in DO CONCURRENT"_err_en_US, - reason); + "Deallocation of an entity with an IMPURE FINAL procedure '%s' caused by %s not allowed in DO CONCURRENT"_err_en_US, + impure.name(), reason); } void SayDeallocateOfPolymorph( @@ -199,8 +186,8 @@ MightDeallocatePolymorphic(entity, DeallocateAll)) { SayDeallocateOfPolymorph(endBlockStmt.source, entity, reason); } - if (HasImpureFinal(entity)) { - SayDeallocateWithImpureFinal(entity, reason); + if (const Symbol * impure{HasImpureFinal(entity)}) { + SayDeallocateWithImpureFinal(entity, reason, *impure); } } } @@ -215,8 +202,8 @@ if (MightDeallocatePolymorphic(*entity, DeallocateNonCoarray)) { SayDeallocateOfPolymorph(variable.GetSource(), *entity, reason); } - if (HasImpureFinal(*entity)) { - SayDeallocateWithImpureFinal(*entity, reason); + if (const Symbol * impure{HasImpureFinal(*entity)}) { + SayDeallocateWithImpureFinal(*entity, reason, *impure); } } if (const auto *assignment{GetAssignment(stmt)}) { @@ -248,8 +235,8 @@ SayDeallocateOfPolymorph( currentStatementSourcePosition_, entity, reason); } - if (HasImpureFinal(entity)) { - SayDeallocateWithImpureFinal(entity, reason); + if (const Symbol * impure{HasImpureFinal(entity)}) { + SayDeallocateWithImpureFinal(entity, reason, *impure); } } } diff --git a/flang/lib/Semantics/definable.cpp b/flang/lib/Semantics/definable.cpp --- a/flang/lib/Semantics/definable.cpp +++ b/flang/lib/Semantics/definable.cpp @@ -156,19 +156,27 @@ "'%s' is an entity with either an EVENT_TYPE or LOCK_TYPE"_en_US, original); } - if (!flags.test(DefinabilityFlag::PolymorphicOkInPure) && - FindPureProcedureContaining(scope)) { + if (FindPureProcedureContaining(scope)) { if (auto dyType{evaluate::DynamicType::From(ultimate)}) { - if (dyType->IsPolymorphic()) { // C1596 + if (!flags.test(DefinabilityFlag::PolymorphicOkInPure)) { + if (dyType->IsPolymorphic()) { // C1596 + return BlameSymbol(at, + "'%s' is polymorphic in a pure subprogram"_because_en_US, + original); + } + } + if (const Symbol * impure{HasImpureFinal(ultimate)}) { return BlameSymbol(at, - "'%s' is polymorphic in a pure subprogram"_because_en_US, original); + "'%s' has an impure FINAL procedure '%s'"_because_en_US, original, + impure->name()); } if (const DerivedTypeSpec * derived{GetDerivedTypeSpec(dyType)}) { - if (auto bad{FindPolymorphicAllocatableNonCoarrayUltimateComponent( - *derived)}) { - return BlameSymbol(at, - "'%s' has polymorphic non-coarray component '%s' in a pure subprogram"_because_en_US, - original, bad.BuildResultDesignatorName()); + if (!flags.test(DefinabilityFlag::PolymorphicOkInPure)) { + if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { + return BlameSymbol(at, + "'%s' has polymorphic component '%s' in a pure subprogram"_because_en_US, + original, bad.BuildResultDesignatorName()); + } } } } diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -729,52 +729,101 @@ return result; } -bool IsFinalizable( - const Symbol &symbol, std::set *inProgress) { - if (IsPointer(symbol)) { - return false; +const Symbol *IsFinalizable(const Symbol &symbol, + std::set *inProgress, bool withImpureFinalizer) { + if (IsPointer(symbol) || evaluate::IsAssumedRank(symbol)) { + return nullptr; } if (const auto *object{symbol.detailsIf()}) { if (object->isDummy() && !IsIntentOut(symbol)) { - return false; + return nullptr; } const DeclTypeSpec *type{object->type()}; - const DerivedTypeSpec *typeSpec{type ? type->AsDerived() : nullptr}; - return typeSpec && IsFinalizable(*typeSpec, inProgress); + if (const DerivedTypeSpec * typeSpec{type ? type->AsDerived() : nullptr}) { + return IsFinalizable( + *typeSpec, inProgress, withImpureFinalizer, symbol.Rank()); + } } - return false; + return nullptr; } -bool IsFinalizable(const DerivedTypeSpec &derived, - std::set *inProgress) { - if (!FinalsForDerivedTypeInstantiation(derived).empty()) { - return true; +const Symbol *IsFinalizable(const DerivedTypeSpec &derived, + std::set *inProgress, bool withImpureFinalizer, + std::optional rank) { + const Symbol *elemental{nullptr}; + for (auto ref : FinalsForDerivedTypeInstantiation(derived)) { + const Symbol *symbol{&ref->GetUltimate()}; + if (const auto *binding{symbol->detailsIf()}) { + symbol = &binding->symbol(); + } + if (const auto *proc{symbol->detailsIf()}) { + symbol = proc->procInterface(); + } + if (!symbol) { + } else if (IsElementalProcedure(*symbol)) { + elemental = symbol; + } else { + if (rank) { + if (const SubprogramDetails * + subp{symbol->detailsIf()}) { + if (const auto &args{subp->dummyArgs()}; !args.empty() && + args.at(0) && !evaluate::IsAssumedRank(*args.at(0)) && + args.at(0)->Rank() != *rank) { + continue; // not a finalizer for this rank + } + } + } + if (!withImpureFinalizer || !IsPureProcedure(*symbol)) { + return symbol; + } + // Found non-elemental pure finalizer of matching rank, but still + // need to check components for an impure finalizer. + elemental = nullptr; + break; + } } + if (elemental && (!withImpureFinalizer || !IsPureProcedure(*elemental))) { + return elemental; + } + // Check components (including ancestors) std::set basis; if (inProgress) { if (inProgress->find(&derived) != inProgress->end()) { - return false; // don't loop on recursive type + return nullptr; // don't loop on recursive type } } else { inProgress = &basis; } auto iterator{inProgress->insert(&derived).first}; - PotentialComponentIterator components{derived}; - bool result{bool{std::find_if( - components.begin(), components.end(), [=](const Symbol &component) { - return IsFinalizable(component, inProgress); - })}}; + const Symbol *result{nullptr}; + for (const Symbol &component : PotentialComponentIterator{derived}) { + result = IsFinalizable(component, inProgress, withImpureFinalizer); + if (result) { + break; + } + } inProgress->erase(iterator); return result; } -bool HasImpureFinal(const DerivedTypeSpec &derived) { - for (auto ref : FinalsForDerivedTypeInstantiation(derived)) { - if (!IsPureProcedure(*ref)) { - return true; +static const Symbol *HasImpureFinal( + const DerivedTypeSpec &derived, std::optional rank) { + return IsFinalizable(derived, nullptr, /*withImpureFinalizer=*/true, rank); +} + +const Symbol *HasImpureFinal(const Symbol &original) { + const Symbol &symbol{ResolveAssociations(original)}; + if (symbol.has()) { + if (const DeclTypeSpec * symType{symbol.GetType()}) { + if (const DerivedTypeSpec * derived{symType->AsDerived()}) { + // finalizable assumed-rank not allowed (C839) + return evaluate::IsAssumedRank(symbol) + ? nullptr + : HasImpureFinal(*derived, symbol.Rank()); + } } } - return false; + return nullptr; } bool IsAssumedLengthCharacter(const Symbol &symbol) { @@ -1298,15 +1347,6 @@ ultimates.begin(), ultimates.end(), IsPolymorphicAllocatable); } -UltimateComponentIterator::const_iterator -FindPolymorphicAllocatableNonCoarrayUltimateComponent( - const DerivedTypeSpec &derived) { - UltimateComponentIterator ultimates{derived}; - return std::find_if(ultimates.begin(), ultimates.end(), [](const Symbol &x) { - return IsPolymorphicAllocatable(x) && !evaluate::IsCoarray(x); - }); -} - const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived, const std::function &predicate) { UltimateComponentIterator ultimates{derived}; @@ -1450,6 +1490,14 @@ return false; } +bool IsAutomaticallyDestroyed(const Symbol &symbol) { + return symbol.has() && + (symbol.owner().kind() == Scope::Kind::Subprogram || + symbol.owner().kind() == Scope::Kind::BlockConstruct) && + (!IsDummy(symbol) || IsIntentOut(symbol)) && !IsPointer(symbol) && + !IsSaved(symbol) && !FindCommonBlockContaining(symbol); +} + const std::optional &MaybeGetNodeName( const ConstructNode &construct) { return common::visit( diff --git a/flang/module/__fortran_type_info.f90 b/flang/module/__fortran_type_info.f90 --- a/flang/module/__fortran_type_info.f90 +++ b/flang/module/__fortran_type_info.f90 @@ -44,7 +44,7 @@ integer(1) :: hasParent integer(1) :: noInitializationNeeded ! 1 if no component w/ init integer(1) :: noDestructionNeeded ! 1 if no component w/ dealloc/final - integer(1) :: noFinalizationNeeded ! 1 if nothing finalizaable + integer(1) :: noFinalizationNeeded ! 1 if nothing finalizeable integer(1) :: __padding0(4) end type diff --git a/flang/test/Semantics/call10.f90 b/flang/test/Semantics/call10.f90 --- a/flang/test/Semantics/call10.f90 +++ b/flang/test/Semantics/call10.f90 @@ -157,11 +157,12 @@ end subroutine pure subroutine s11(to) ! C1596 ! Implicit deallocation at the end of the subroutine - !ERROR: Deallocation of polymorphic object 'auto%a' is not permitted in a pure subprogram + !ERROR: 'auto' may not be a local variable in a pure subprogram + !BECAUSE: 'auto' has polymorphic component '%a' in a pure subprogram type(polyAlloc) :: auto type(polyAlloc), intent(in out) :: to !ERROR: Left-hand side of assignment is not definable - !BECAUSE: 'to' has polymorphic non-coarray component '%a' in a pure subprogram + !BECAUSE: 'to' has polymorphic component '%a' in a pure subprogram to = auto end subroutine pure subroutine s12 diff --git a/flang/test/Semantics/deallocate07.f90 b/flang/test/Semantics/deallocate07.f90 --- a/flang/test/Semantics/deallocate07.f90 +++ b/flang/test/Semantics/deallocate07.f90 @@ -6,16 +6,27 @@ type t2 class(t2), allocatable :: pc end type + class(t1), pointer :: mp1 + type(t2) :: mv1 contains pure subroutine subr(pp1, pp2, mp2) class(t1), intent(in out), pointer :: pp1 class(t2), intent(in out) :: pp2 type(t2), pointer :: mp2 - !ERROR: 'pp1' may not be deallocated in a pure procedure because it is polymorphic + !ERROR: Name in DEALLOCATE statement is not definable + !BECAUSE: 'mp1' may not be defined in pure subprogram 'subr' because it is host-associated + deallocate(mp1) + !ERROR: Name in DEALLOCATE statement is not definable + !BECAUSE: 'mv1' may not be defined in pure subprogram 'subr' because it is host-associated + deallocate(mv1%pc) + !ERROR: Object in DEALLOCATE statement is not deallocatable + !BECAUSE: 'pp1' is polymorphic in a pure subprogram deallocate(pp1) - !ERROR: 'pc' may not be deallocated in a pure procedure because it is polymorphic + !ERROR: Object in DEALLOCATE statement is not deallocatable + !BECAUSE: 'pc' is polymorphic in a pure subprogram deallocate(pp2%pc) - !ERROR: 'mp2' may not be deallocated in a pure procedure because its type has a polymorphic allocatable ultimate component 'pc' + !ERROR: Object in DEALLOCATE statement is not deallocatable + !BECAUSE: 'mp2' has polymorphic component '%pc' in a pure subprogram deallocate(mp2) end subroutine end module diff --git a/flang/test/Semantics/declarations05.f90 b/flang/test/Semantics/declarations05.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/declarations05.f90 @@ -0,0 +1,42 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 +! Other checks for declarations in PURE procedures +module m + type t0 + end type + type t1 + contains + final :: final + end type + type t2 + type(t1), allocatable :: c + end type + type t3 + class(t1), allocatable :: c + end type + type t4 + class(t0), allocatable :: c + end type + contains + impure subroutine final(x) + type(t1) x + end + pure subroutine test + !ERROR: 'x0' may not be a local variable in a pure subprogram + !BECAUSE: 'x0' is polymorphic in a pure subprogram + class(t0), allocatable :: x0 + !ERROR: 'x1' may not be a local variable in a pure subprogram + !BECAUSE: 'x1' has an impure FINAL procedure 'final' + type(t1) x1 + !WARNING: 'x1a' of derived type 't1' does not have a FINAL subroutine for its rank (1) + type(t1), allocatable :: x1a(:) + !ERROR: 'x2' may not be a local variable in a pure subprogram + !BECAUSE: 'x2' has an impure FINAL procedure 'final' + type(t2) x2 + !ERROR: 'x3' may not be a local variable in a pure subprogram + !BECAUSE: 'x3' has an impure FINAL procedure 'final' + type(t3) x3 + !ERROR: 'x4' may not be a local variable in a pure subprogram + !BECAUSE: 'x4' has polymorphic component '%c' in a pure subprogram + type(t4) x4 + end +end diff --git a/flang/test/Semantics/doconcurrent08.f90 b/flang/test/Semantics/doconcurrent08.f90 --- a/flang/test/Semantics/doconcurrent08.f90 +++ b/flang/test/Semantics/doconcurrent08.f90 @@ -247,7 +247,7 @@ ! Error to invoke an IMPURE FINAL procedure in a DO CONCURRENT do concurrent (i = 1:10) - !ERROR: Deallocation of an entity with an IMPURE FINAL procedure caused by a DEALLOCATE statement not allowed in DO CONCURRENT + !ERROR: Deallocation of an entity with an IMPURE FINAL procedure 'impuresub' caused by a DEALLOCATE statement not allowed in DO CONCURRENT if (i .eq. 1) deallocate(ifVar) end do @@ -256,18 +256,18 @@ block type(impureFinal), allocatable :: ifVar allocate(ifVar) - ! Error here because exiting this scope causes the finalization of - !ifvar which causes the invocation of an IMPURE FINAL procedure - !ERROR: Deallocation of an entity with an IMPURE FINAL procedure caused by block exit not allowed in DO CONCURRENT + ! Error here because exiting this scope causes the finalization of + ! ifvar which causes the invocation of an IMPURE FINAL procedure + !ERROR: Deallocation of an entity with an IMPURE FINAL procedure 'impuresub' caused by block exit not allowed in DO CONCURRENT end block end if end do do concurrent (i = 1:10) if (i .eq. 1) then - ! Error here because the assignment statement causes the finalization + ! Error here because the assignment statement causes the finalization ! of ifvar which causes the invocation of an IMPURE FINAL procedure -!ERROR: Deallocation of an entity with an IMPURE FINAL procedure caused by assignment not allowed in DO CONCURRENT + !ERROR: Deallocation of an entity with an IMPURE FINAL procedure 'impuresub' caused by assignment not allowed in DO CONCURRENT ifvar = ifvar1 end if end do