diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -1836,6 +1836,7 @@ // R933 allocate-object -> variable-name | structure-component struct AllocateObject { UNION_CLASS_BOILERPLATE(AllocateObject); + mutable TypedExpr typedExpr; std::variant u; }; @@ -1907,6 +1908,7 @@ // variable-name | structure-component | proc-pointer-name struct PointerObject { UNION_CLASS_BOILERPLATE(PointerObject); + mutable TypedExpr typedExpr; std::variant u; }; diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h --- a/flang/include/flang/Semantics/expression.h +++ b/flang/include/flang/Semantics/expression.h @@ -77,6 +77,8 @@ void Set(const parser::Expr &x) { Set(x.typedExpr); } void Set(const parser::Variable &x) { Set(x.typedExpr); } void Set(const parser::DataStmtConstant &x) { Set(x.typedExpr); } + void Set(const parser::AllocateObject &x) { Set(x.typedExpr); } + void Set(const parser::PointerObject &x) { Set(x.typedExpr); } template void Set(const common::Indirection &x) { Set(x.value()); } diff --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp --- a/flang/lib/Semantics/check-allocate.cpp +++ b/flang/lib/Semantics/check-allocate.cpp @@ -421,6 +421,16 @@ CHECK(context.AnyFatalError()); return false; } + // Analyze and save AllocateObject Name or StructureComponent as a typed + // expression. + std::visit( + [&](const auto &x) { + evaluate::ExpressionAnalyzer analyzer{context}; + if (MaybeExpr checked{analyzer.Analyze(x)}) { + evaluate::SetExpr(allocateObject_, std::move(*checked)); + } + }, + allocateObject_.u); GatherAllocationBasicInfo(); if (!IsAllocatableOrPointer(*symbol_)) { // C932 context.Say(name_.source, 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 @@ -17,12 +17,13 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) { for (const parser::AllocateObject &allocateObject : std::get>(deallocateStmt.t)) { - std::visit( + MaybeExpr expr{std::visit( common::visitors{ - [&](const parser::Name &name) { + [&](const parser::Name &name) -> MaybeExpr { auto const *symbol{name.symbol}; if (context_.HasError(symbol)) { // already reported an error + return {}; } else if (!IsVariableName(*symbol)) { context_.Say(name.source, "name in DEALLOCATE statement must be a variable name"_err_en_US); @@ -32,8 +33,10 @@ } else { context_.CheckIndexVarRedefine(name); } + return evaluate::ExpressionAnalyzer{context_}.Analyze(name); }, - [&](const parser::StructureComponent &structureComponent) { + [&](const parser::StructureComponent &structureComponent) + -> MaybeExpr { evaluate::ExpressionAnalyzer analyzer{context_}; if (MaybeExpr checked{analyzer.Analyze(structureComponent)}) { if (!IsAllocatableOrPointer( @@ -41,10 +44,15 @@ context_.Say(structureComponent.component.source, "component in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US); } + return checked; } + return {}; }, }, - allocateObject.u); + allocateObject.u)}; + if (expr) { + evaluate::SetExpr(allocateObject, std::move(*expr)); + } } bool gotStat{false}, gotMsg{false}; for (const parser::StatOrErrmsg &deallocOpt : diff --git a/flang/lib/Semantics/check-nullify.cpp b/flang/lib/Semantics/check-nullify.cpp --- a/flang/lib/Semantics/check-nullify.cpp +++ b/flang/lib/Semantics/check-nullify.cpp @@ -23,12 +23,13 @@ parser::ContextualMessages messages{ *context_.location(), &context_.messages()}; for (const parser::PointerObject &pointerObject : nullifyStmt.v) { - std::visit( + MaybeExpr expr{std::visit( common::visitors{ - [&](const parser::Name &name) { + [&](const parser::Name &name) -> MaybeExpr { const Symbol *symbol{name.symbol}; if (context_.HasError(symbol)) { // already reported an error + return {}; } else if (!IsVariableName(*symbol) && !IsProcName(*symbol)) { messages.Say(name.source, "name in NULLIFY statement must be a variable or procedure pointer name"_err_en_US); @@ -38,8 +39,10 @@ } else if (pure) { CheckDefinabilityInPureScope(messages, *symbol, scope, *pure); } + return evaluate::ExpressionAnalyzer{context_}.Analyze(name); }, - [&](const parser::StructureComponent &structureComponent) { + [&](const parser::StructureComponent &structureComponent) + -> MaybeExpr { evaluate::ExpressionAnalyzer analyzer{context_}; if (MaybeExpr checked{analyzer.Analyze(structureComponent)}) { if (!IsPointer(*structureComponent.component.symbol)) { // C951 @@ -51,10 +54,15 @@ messages, *symbol, scope, *pure); } } + return checked; } + return {}; }, }, - pointerObject.u); + pointerObject.u)}; + if (expr) { + evaluate::SetExpr(pointerObject, std::move(*expr)); + } } // From 9.7.3.1(1) // A pointer-object shall not depend on the value,