llvm-project
718 строк · 28.2 Кб
1//===-- lib/Semantics/check-allocate.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "check-allocate.h"10#include "assignment.h"11#include "definable.h"12#include "flang/Evaluate/fold.h"13#include "flang/Evaluate/type.h"14#include "flang/Parser/parse-tree.h"15#include "flang/Parser/tools.h"16#include "flang/Semantics/attr.h"17#include "flang/Semantics/expression.h"18#include "flang/Semantics/tools.h"19#include "flang/Semantics/type.h"20
21namespace Fortran::semantics {22
23struct AllocateCheckerInfo {24const DeclTypeSpec *typeSpec{nullptr};25std::optional<evaluate::DynamicType> sourceExprType;26std::optional<parser::CharBlock> sourceExprLoc;27std::optional<parser::CharBlock> typeSpecLoc;28int sourceExprRank{0}; // only valid if gotMold || gotSource29bool gotStat{false};30bool gotMsg{false};31bool gotTypeSpec{false};32bool gotSource{false};33bool gotMold{false};34bool gotStream{false};35bool gotPinned{false};36};37
38class AllocationCheckerHelper {39public:40AllocationCheckerHelper(41const parser::Allocation &alloc, AllocateCheckerInfo &info)42: allocateInfo_{info}, allocateObject_{std::get<parser::AllocateObject>(43alloc.t)},44allocateShapeSpecRank_{ShapeSpecRank(alloc)}, allocateCoarraySpecRank_{45CoarraySpecRank(46alloc)} {}47
48bool RunChecks(SemanticsContext &context);49
50private:51bool hasAllocateShapeSpecList() const { return allocateShapeSpecRank_ != 0; }52bool hasAllocateCoarraySpec() const { return allocateCoarraySpecRank_ != 0; }53bool RunCoarrayRelatedChecks(SemanticsContext &) const;54
55static int ShapeSpecRank(const parser::Allocation &allocation) {56return static_cast<int>(57std::get<std::list<parser::AllocateShapeSpec>>(allocation.t).size());58}59
60static int CoarraySpecRank(const parser::Allocation &allocation) {61if (const auto &coarraySpec{62std::get<std::optional<parser::AllocateCoarraySpec>>(63allocation.t)}) {64return std::get<std::list<parser::AllocateCoshapeSpec>>(coarraySpec->t)65.size() +661;67} else {68return 0;69}70}71
72void GatherAllocationBasicInfo() {73if (type_->category() == DeclTypeSpec::Category::Character) {74hasDeferredTypeParameter_ =75type_->characterTypeSpec().length().isDeferred();76} else if (const DerivedTypeSpec * derivedTypeSpec{type_->AsDerived()}) {77for (const auto &pair : derivedTypeSpec->parameters()) {78hasDeferredTypeParameter_ |= pair.second.isDeferred();79}80isAbstract_ = derivedTypeSpec->typeSymbol().attrs().test(Attr::ABSTRACT);81}82isUnlimitedPolymorphic_ =83type_->category() == DeclTypeSpec::Category::ClassStar;84}85
86AllocateCheckerInfo &allocateInfo_;87const parser::AllocateObject &allocateObject_;88const int allocateShapeSpecRank_{0};89const int allocateCoarraySpecRank_{0};90const parser::Name &name_{parser::GetLastName(allocateObject_)};91// no USE or host association92const Symbol *ultimate_{93name_.symbol ? &name_.symbol->GetUltimate() : nullptr};94const DeclTypeSpec *type_{ultimate_ ? ultimate_->GetType() : nullptr};95const int rank_{ultimate_ ? ultimate_->Rank() : 0};96const int corank_{ultimate_ ? ultimate_->Corank() : 0};97bool hasDeferredTypeParameter_{false};98bool isUnlimitedPolymorphic_{false};99bool isAbstract_{false};100};101
102static std::optional<AllocateCheckerInfo> CheckAllocateOptions(103const parser::AllocateStmt &allocateStmt, SemanticsContext &context) {104AllocateCheckerInfo info;105bool stopCheckingAllocate{false}; // for errors that would lead to ambiguity106if (const auto &typeSpec{107std::get<std::optional<parser::TypeSpec>>(allocateStmt.t)}) {108info.typeSpec = typeSpec->declTypeSpec;109if (!info.typeSpec) {110CHECK(context.AnyFatalError());111return std::nullopt;112}113info.gotTypeSpec = true;114info.typeSpecLoc = parser::FindSourceLocation(*typeSpec);115if (const DerivedTypeSpec * derived{info.typeSpec->AsDerived()}) {116// C937117if (auto it{FindCoarrayUltimateComponent(*derived)}) {118context
119.Say("Type-spec in ALLOCATE must not specify a type with a coarray"120" ultimate component"_err_en_US)121.Attach(it->name(),122"Type '%s' has coarray ultimate component '%s' declared here"_en_US,123info.typeSpec->AsFortran(), it.BuildResultDesignatorName());124}125}126}127
128const parser::Expr *parserSourceExpr{nullptr};129for (const parser::AllocOpt &allocOpt :130std::get<std::list<parser::AllocOpt>>(allocateStmt.t)) {131common::visit(132common::visitors{133[&](const parser::StatOrErrmsg &statOrErr) {134common::visit(135common::visitors{136[&](const parser::StatVariable &) {137if (info.gotStat) { // C943138context.Say(139"STAT may not be duplicated in a ALLOCATE statement"_err_en_US);140}141info.gotStat = true;142},143[&](const parser::MsgVariable &var) {144WarnOnDeferredLengthCharacterScalar(context,145GetExpr(context, var),146var.v.thing.thing.GetSource(), "ERRMSG=");147if (info.gotMsg) { // C943148context.Say(149"ERRMSG may not be duplicated in a ALLOCATE statement"_err_en_US);150}151info.gotMsg = true;152},153},154statOrErr.u);155},156[&](const parser::AllocOpt::Source &source) {157if (info.gotSource) { // C943158context.Say(159"SOURCE may not be duplicated in a ALLOCATE statement"_err_en_US);160stopCheckingAllocate = true;161}162if (info.gotMold || info.gotTypeSpec) { // C944163context.Say(164"At most one of source-expr and type-spec may appear in a ALLOCATE statement"_err_en_US);165stopCheckingAllocate = true;166}167parserSourceExpr = &source.v.value();168info.gotSource = true;169},170[&](const parser::AllocOpt::Mold &mold) {171if (info.gotMold) { // C943172context.Say(173"MOLD may not be duplicated in a ALLOCATE statement"_err_en_US);174stopCheckingAllocate = true;175}176if (info.gotSource || info.gotTypeSpec) { // C944177context.Say(178"At most one of source-expr and type-spec may appear in a ALLOCATE statement"_err_en_US);179stopCheckingAllocate = true;180}181parserSourceExpr = &mold.v.value();182info.gotMold = true;183},184[&](const parser::AllocOpt::Stream &stream) { // CUDA185if (info.gotStream) {186context.Say(187"STREAM may not be duplicated in a ALLOCATE statement"_err_en_US);188stopCheckingAllocate = true;189}190info.gotStream = true;191},192[&](const parser::AllocOpt::Pinned &pinned) { // CUDA193if (info.gotPinned) {194context.Say(195"PINNED may not be duplicated in a ALLOCATE statement"_err_en_US);196stopCheckingAllocate = true;197}198info.gotPinned = true;199},200},201allocOpt.u);202}203
204if (stopCheckingAllocate) {205return std::nullopt;206}207
208if (info.gotSource || info.gotMold) {209if (const auto *expr{GetExpr(context, DEREF(parserSourceExpr))}) {210parser::CharBlock at{parserSourceExpr->source};211info.sourceExprType = expr->GetType();212if (!info.sourceExprType) {213context.Say(at,214"Typeless item not allowed as SOURCE or MOLD in ALLOCATE"_err_en_US);215return std::nullopt;216}217info.sourceExprRank = expr->Rank();218info.sourceExprLoc = parserSourceExpr->source;219if (const DerivedTypeSpec *220derived{evaluate::GetDerivedTypeSpec(info.sourceExprType)}) {221// C949222if (auto it{FindCoarrayUltimateComponent(*derived)}) {223context
224.Say(at,225"SOURCE or MOLD expression must not have a type with a coarray ultimate component"_err_en_US)226.Attach(it->name(),227"Type '%s' has coarray ultimate component '%s' declared here"_en_US,228info.sourceExprType.value().AsFortran(),229it.BuildResultDesignatorName());230}231if (info.gotSource) {232// C948233if (IsEventTypeOrLockType(derived)) {234context.Say(at,235"SOURCE expression type must not be EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US);236} else if (auto it{FindEventOrLockPotentialComponent(*derived)}) {237context
238.Say(at,239"SOURCE expression type must not have potential subobject "240"component"241" of type EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US)242.Attach(it->name(),243"Type '%s' has potential ultimate component '%s' declared here"_en_US,244info.sourceExprType.value().AsFortran(),245it.BuildResultDesignatorName());246}247}248}249if (info.gotSource) { // C1594(6) - SOURCE= restrictions when pure250const Scope &scope{context.FindScope(at)};251if (FindPureProcedureContaining(scope)) {252parser::ContextualMessages messages{at, &context.messages()};253CheckCopyabilityInPureScope(messages, *expr, scope);254}255}256} else {257// Error already reported on source expression.258// Do not continue allocate checks.259return std::nullopt;260}261}262
263return info;264}
265
266// Beware, type compatibility is not symmetric, IsTypeCompatible checks that
267// type1 is type compatible with type2. Note: type parameters are not considered
268// in this test.
269static bool IsTypeCompatible(270const DeclTypeSpec &type1, const DerivedTypeSpec &derivedType2) {271if (const DerivedTypeSpec * derivedType1{type1.AsDerived()}) {272if (type1.category() == DeclTypeSpec::Category::TypeDerived) {273return &derivedType1->typeSymbol() == &derivedType2.typeSymbol();274} else if (type1.category() == DeclTypeSpec::Category::ClassDerived) {275for (const DerivedTypeSpec *parent{&derivedType2}; parent;276parent = parent->typeSymbol().GetParentTypeSpec()) {277if (&derivedType1->typeSymbol() == &parent->typeSymbol()) {278return true;279}280}281}282}283return false;284}
285
286static bool IsTypeCompatible(287const DeclTypeSpec &type1, const DeclTypeSpec &type2) {288if (type1.category() == DeclTypeSpec::Category::ClassStar) {289// TypeStar does not make sense in allocate context because assumed type290// cannot be allocatable (C709)291return true;292}293if (const IntrinsicTypeSpec * intrinsicType2{type2.AsIntrinsic()}) {294if (const IntrinsicTypeSpec * intrinsicType1{type1.AsIntrinsic()}) {295return intrinsicType1->category() == intrinsicType2->category();296} else {297return false;298}299} else if (const DerivedTypeSpec * derivedType2{type2.AsDerived()}) {300return IsTypeCompatible(type1, *derivedType2);301}302return false;303}
304
305static bool IsTypeCompatible(306const DeclTypeSpec &type1, const evaluate::DynamicType &type2) {307if (type1.category() == DeclTypeSpec::Category::ClassStar) {308// TypeStar does not make sense in allocate context because assumed type309// cannot be allocatable (C709)310return true;311}312if (type2.category() != evaluate::TypeCategory::Derived) {313if (const IntrinsicTypeSpec * intrinsicType1{type1.AsIntrinsic()}) {314return intrinsicType1->category() == type2.category();315} else {316return false;317}318} else if (!type2.IsUnlimitedPolymorphic()) {319return IsTypeCompatible(type1, type2.GetDerivedTypeSpec());320}321return false;322}
323
324// Note: Check assumes type1 is compatible with type2. type2 may have more type
325// parameters than type1 but if a type2 type parameter is assumed, then this
326// check enforce that type1 has it. type1 can be unlimited polymorphic, but not
327// type2.
328static bool HaveSameAssumedTypeParameters(329const DeclTypeSpec &type1, const DeclTypeSpec &type2) {330if (type2.category() == DeclTypeSpec::Category::Character) {331bool type2LengthIsAssumed{type2.characterTypeSpec().length().isAssumed()};332if (type1.category() == DeclTypeSpec::Category::Character) {333return type1.characterTypeSpec().length().isAssumed() ==334type2LengthIsAssumed;335}336// It is possible to reach this if type1 is unlimited polymorphic337return !type2LengthIsAssumed;338} else if (const DerivedTypeSpec * derivedType2{type2.AsDerived()}) {339int type2AssumedParametersCount{0};340int type1AssumedParametersCount{0};341for (const auto &pair : derivedType2->parameters()) {342type2AssumedParametersCount += pair.second.isAssumed();343}344// type1 may be unlimited polymorphic345if (const DerivedTypeSpec * derivedType1{type1.AsDerived()}) {346for (auto it{derivedType1->parameters().begin()};347it != derivedType1->parameters().end(); ++it) {348if (it->second.isAssumed()) {349++type1AssumedParametersCount;350const ParamValue *param{derivedType2->FindParameter(it->first)};351if (!param || !param->isAssumed()) {352// type1 has an assumed parameter that is not a type parameter of353// type2 or not assumed in type2.354return false;355}356}357}358}359// Will return false if type2 has type parameters that are not assumed in360// type1 or do not exist in type1361return type1AssumedParametersCount == type2AssumedParametersCount;362}363return true; // other intrinsic types have no length type parameters364}
365
366static std::optional<std::int64_t> GetTypeParameterInt64Value(367const Symbol ¶meterSymbol, const DerivedTypeSpec &derivedType) {368if (const ParamValue *369paramValue{derivedType.FindParameter(parameterSymbol.name())}) {370return evaluate::ToInt64(paramValue->GetExplicit());371}372return std::nullopt;373}
374
375static bool HaveCompatibleTypeParameters(376const DerivedTypeSpec &derivedType1, const DerivedTypeSpec &derivedType2) {377for (const Symbol &symbol :378OrderParameterDeclarations(derivedType1.typeSymbol())) {379auto v1{GetTypeParameterInt64Value(symbol, derivedType1)};380auto v2{GetTypeParameterInt64Value(symbol, derivedType2)};381if (v1 && v2 && *v1 != *v2) {382return false;383}384}385return true;386}
387
388static bool HaveCompatibleTypeParameters(389const DeclTypeSpec &type1, const evaluate::DynamicType &type2) {390if (type1.category() == DeclTypeSpec::Category::ClassStar) {391return true;392}393if (const IntrinsicTypeSpec * intrinsicType1{type1.AsIntrinsic()}) {394return evaluate::ToInt64(intrinsicType1->kind()).value() == type2.kind();395} else if (type2.IsUnlimitedPolymorphic()) {396return false;397} else if (const DerivedTypeSpec * derivedType1{type1.AsDerived()}) {398return HaveCompatibleTypeParameters(399*derivedType1, type2.GetDerivedTypeSpec());400} else {401common::die("unexpected type1 category");402}403}
404
405static bool HaveCompatibleTypeParameters(406const DeclTypeSpec &type1, const DeclTypeSpec &type2) {407if (type1.category() == DeclTypeSpec::Category::ClassStar) {408return true;409} else if (const IntrinsicTypeSpec * intrinsicType1{type1.AsIntrinsic()}) {410const IntrinsicTypeSpec *intrinsicType2{type2.AsIntrinsic()};411return !intrinsicType2 || intrinsicType1->kind() == intrinsicType2->kind();412} else if (const DerivedTypeSpec * derivedType1{type1.AsDerived()}) {413const DerivedTypeSpec *derivedType2{type2.AsDerived()};414return !derivedType2 ||415HaveCompatibleTypeParameters(*derivedType1, *derivedType2);416} else {417common::die("unexpected type1 category");418}419}
420
421static bool HaveCompatibleLengths(422const DeclTypeSpec &type1, const DeclTypeSpec &type2) {423if (type1.category() == DeclTypeSpec::Character &&424type2.category() == DeclTypeSpec::Character) {425auto v1{426evaluate::ToInt64(type1.characterTypeSpec().length().GetExplicit())};427auto v2{428evaluate::ToInt64(type2.characterTypeSpec().length().GetExplicit())};429return !v1 || !v2 || *v1 == *v2;430} else {431return true;432}433}
434
435static bool HaveCompatibleLengths(436const DeclTypeSpec &type1, const evaluate::DynamicType &type2) {437if (type1.category() == DeclTypeSpec::Character &&438type2.category() == TypeCategory::Character) {439auto v1{440evaluate::ToInt64(type1.characterTypeSpec().length().GetExplicit())};441auto v2{type2.knownLength()};442return !v1 || !v2 || *v1 == *v2;443} else {444return true;445}446}
447
448bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {449if (!ultimate_) {450CHECK(context.AnyFatalError());451return false;452}453if (!IsVariableName(*ultimate_)) { // C932 pre-requisite454context.Say(name_.source,455"Name in ALLOCATE statement must be a variable name"_err_en_US);456return false;457}458if (!type_) {459// This is done after variable check because a user could have put460// a subroutine name in allocate for instance which is a symbol with461// no type.462CHECK(context.AnyFatalError());463return false;464}465GatherAllocationBasicInfo();466if (!IsAllocatableOrObjectPointer(ultimate_)) { // C932467context.Say(name_.source,468"Entity in ALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US);469return false;470}471bool gotSourceExprOrTypeSpec{allocateInfo_.gotMold ||472allocateInfo_.gotTypeSpec || allocateInfo_.gotSource};473if (hasDeferredTypeParameter_ && !gotSourceExprOrTypeSpec) {474// C933475context.Say(name_.source,476"Either type-spec or source-expr must appear in ALLOCATE when allocatable object has a deferred type parameters"_err_en_US);477return false;478}479if (isUnlimitedPolymorphic_ && !gotSourceExprOrTypeSpec) {480// C933481context.Say(name_.source,482"Either type-spec or source-expr must appear in ALLOCATE when allocatable object is unlimited polymorphic"_err_en_US);483return false;484}485if (isAbstract_ && !gotSourceExprOrTypeSpec) {486// C933487context.Say(name_.source,488"Either type-spec or source-expr must appear in ALLOCATE when allocatable object is of abstract type"_err_en_US);489return false;490}491if (allocateInfo_.gotTypeSpec) {492if (!IsTypeCompatible(*type_, *allocateInfo_.typeSpec)) {493// C934494context.Say(name_.source,495"Allocatable object in ALLOCATE must be type compatible with type-spec"_err_en_US);496return false;497}498if (!HaveCompatibleTypeParameters(*type_, *allocateInfo_.typeSpec)) {499context.Say(name_.source,500// C936501"Type parameters of allocatable object in ALLOCATE must be the same as the corresponding ones in type-spec"_err_en_US);502return false;503}504if (!HaveCompatibleLengths(*type_, *allocateInfo_.typeSpec)) { // C934505context.Say(name_.source,506"Character length of allocatable object in ALLOCATE must be the same as the type-spec"_err_en_US);507return false;508}509if (!HaveSameAssumedTypeParameters(*type_, *allocateInfo_.typeSpec)) {510// C935511context.Say(name_.source,512"Type parameters in type-spec must be assumed if and only if they are assumed for allocatable object in ALLOCATE"_err_en_US);513return false;514}515} else if (allocateInfo_.gotSource || allocateInfo_.gotMold) {516if (!IsTypeCompatible(*type_, allocateInfo_.sourceExprType.value())) {517// first part of C945518context.Say(name_.source,519"Allocatable object in ALLOCATE must be type compatible with source expression from MOLD or SOURCE"_err_en_US);520return false;521}522if (!HaveCompatibleTypeParameters(523*type_, allocateInfo_.sourceExprType.value())) {524// C946525context.Say(name_.source,526"Derived type parameters of allocatable object must be the same as the corresponding ones of SOURCE or MOLD expression"_err_en_US);527return false;528}529// Character length distinction is allowed, with a warning530if (!HaveCompatibleLengths(531*type_, allocateInfo_.sourceExprType.value())) { // F'2023 C950532if (context.ShouldWarn(common::LanguageFeature::AllocateToOtherLength)) {533context.Say(name_.source,534"Character length of allocatable object in ALLOCATE should be the same as the SOURCE or MOLD"_port_en_US);535}536return false;537}538}539// Shape related checks540if (ultimate_ && evaluate::IsAssumedRank(*ultimate_)) {541context.Say(name_.source,542"An assumed-rank dummy argument may not appear in an ALLOCATE statement"_err_en_US);543return false;544}545if (ultimate_ && IsAssumedSizeArray(*ultimate_) && context.AnyFatalError()) {546// An assumed-size dummy array or RANK(*) case of SELECT RANK will have547// already been diagnosed; don't pile on.548return false;549}550if (rank_ > 0) {551if (!hasAllocateShapeSpecList()) {552// C939553if (!(allocateInfo_.gotSource || allocateInfo_.gotMold)) {554context.Say(name_.source,555"Arrays in ALLOCATE must have a shape specification or an expression of the same rank must appear in SOURCE or MOLD"_err_en_US);556return false;557} else {558if (allocateInfo_.sourceExprRank != rank_) {559context
560.Say(name_.source,561"Arrays in ALLOCATE must have a shape specification or an expression of the same rank must appear in SOURCE or MOLD"_err_en_US)562.Attach(allocateInfo_.sourceExprLoc.value(),563"Expression in %s has rank %d but allocatable object has rank %d"_en_US,564allocateInfo_.gotSource ? "SOURCE" : "MOLD",565allocateInfo_.sourceExprRank, rank_);566return false;567}568}569} else {570// explicit shape-spec-list571if (allocateShapeSpecRank_ != rank_) {572context
573.Say(name_.source,574"The number of shape specifications, when they appear, must match the rank of allocatable object"_err_en_US)575.Attach(576ultimate_->name(), "Declared here with rank %d"_en_US, rank_);577return false;578}579}580} else { // allocating a scalar object581if (hasAllocateShapeSpecList()) {582context.Say(name_.source,583"Shape specifications must not appear when allocatable object is scalar"_err_en_US);584return false;585}586}587// second and last part of C945588if (allocateInfo_.gotSource && allocateInfo_.sourceExprRank &&589allocateInfo_.sourceExprRank != rank_) {590context
591.Say(name_.source,592"If SOURCE appears, the related expression must be scalar or have the same rank as each allocatable object in ALLOCATE"_err_en_US)593.Attach(allocateInfo_.sourceExprLoc.value(),594"SOURCE expression has rank %d"_en_US, allocateInfo_.sourceExprRank)595.Attach(ultimate_->name(),596"Allocatable object declared here with rank %d"_en_US, rank_);597return false;598}599context.CheckIndexVarRedefine(name_);600const Scope &subpScope{601GetProgramUnitContaining(context.FindScope(name_.source))};602if (allocateObject_.typedExpr && allocateObject_.typedExpr->v) {603if (auto whyNot{WhyNotDefinable(name_.source, subpScope,604{DefinabilityFlag::PointerDefinition,605DefinabilityFlag::AcceptAllocatable},606*allocateObject_.typedExpr->v)}) {607context
608.Say(name_.source,609"Name in ALLOCATE statement is not definable"_err_en_US)610.Attach(std::move(*whyNot));611return false;612}613}614if (allocateInfo_.gotPinned) {615std::optional<common::CUDADataAttr> cudaAttr{GetCUDADataAttr(ultimate_)};616if (!cudaAttr || *cudaAttr != common::CUDADataAttr::Pinned) {617context.Say(name_.source,618"Object in ALLOCATE must have PINNED attribute when PINNED option is specified"_err_en_US);619}620}621if (allocateInfo_.gotStream) {622std::optional<common::CUDADataAttr> cudaAttr{GetCUDADataAttr(ultimate_)};623if (!cudaAttr || *cudaAttr != common::CUDADataAttr::Device) {624context.Say(name_.source,625"Object in ALLOCATE must have DEVICE attribute when STREAM option is specified"_err_en_US);626}627}628return RunCoarrayRelatedChecks(context);629}
630
631bool AllocationCheckerHelper::RunCoarrayRelatedChecks(632SemanticsContext &context) const {633if (!ultimate_) {634CHECK(context.AnyFatalError());635return false;636}637if (evaluate::IsCoarray(*ultimate_)) {638if (allocateInfo_.gotTypeSpec) {639// C938640if (const DerivedTypeSpec *641derived{allocateInfo_.typeSpec->AsDerived()}) {642if (IsTeamType(derived)) {643context
644.Say(allocateInfo_.typeSpecLoc.value(),645"Type-Spec in ALLOCATE must not be TEAM_TYPE from ISO_FORTRAN_ENV when an allocatable object is a coarray"_err_en_US)646.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);647return false;648} else if (IsIsoCType(derived)) {649context
650.Say(allocateInfo_.typeSpecLoc.value(),651"Type-Spec in ALLOCATE must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray"_err_en_US)652.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);653return false;654}655}656} else if (allocateInfo_.gotSource || allocateInfo_.gotMold) {657// C948658const evaluate::DynamicType &sourceType{659allocateInfo_.sourceExprType.value()};660if (const auto *derived{evaluate::GetDerivedTypeSpec(sourceType)}) {661if (IsTeamType(derived)) {662context
663.Say(allocateInfo_.sourceExprLoc.value(),664"SOURCE or MOLD expression type must not be TEAM_TYPE from ISO_FORTRAN_ENV when an allocatable object is a coarray"_err_en_US)665.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);666return false;667} else if (IsIsoCType(derived)) {668context
669.Say(allocateInfo_.sourceExprLoc.value(),670"SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray"_err_en_US)671.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);672return false;673}674}675}676if (!hasAllocateCoarraySpec()) {677// C941678context.Say(name_.source,679"Coarray specification must appear in ALLOCATE when allocatable object is a coarray"_err_en_US);680return false;681} else {682if (allocateCoarraySpecRank_ != corank_) {683// Second and last part of C942684context
685.Say(name_.source,686"Corank of coarray specification in ALLOCATE must match corank of alloctable coarray"_err_en_US)687.Attach(ultimate_->name(), "Declared here with corank %d"_en_US,688corank_);689return false;690}691}692} else { // Not a coarray693if (hasAllocateCoarraySpec()) {694// C941695context.Say(name_.source,696"Coarray specification must not appear in ALLOCATE when allocatable object is not a coarray"_err_en_US);697return false;698}699}700if (const parser::CoindexedNamedObject *701coindexedObject{parser::GetCoindexedNamedObject(allocateObject_)}) {702// C950703context.Say(parser::FindSourceLocation(*coindexedObject),704"Allocatable object must not be coindexed in ALLOCATE"_err_en_US);705return false;706}707return true;708}
709
710void AllocateChecker::Leave(const parser::AllocateStmt &allocateStmt) {711if (auto info{CheckAllocateOptions(allocateStmt, context_)}) {712for (const parser::Allocation &allocation :713std::get<std::list<parser::Allocation>>(allocateStmt.t)) {714AllocationCheckerHelper{allocation, *info}.RunChecks(context_);715}716}717}
718} // namespace Fortran::semantics719