diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index bc0fd388b11cd..150b011ad8ba0 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -793,7 +793,7 @@ class ParseTreeDumper { template std::string AsFortran(const T &x) { std::string buf; llvm::raw_string_ostream ss{buf}; - if constexpr (std::is_same_v) { + if constexpr (HasTypedExpr::value) { if (asFortran_ && x.typedExpr) { asFortran_->expr(ss, *x.typedExpr); } diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index dcc38090a3a18..152c2c8c9076b 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -1836,6 +1836,7 @@ struct ArrayElement { // R933 allocate-object -> variable-name | structure-component struct AllocateObject { UNION_CLASS_BOILERPLATE(AllocateObject); + mutable TypedExpr typedExpr; std::variant u; }; @@ -1907,6 +1908,7 @@ struct AllocateStmt { // 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/Parser/tools.h b/flang/include/flang/Parser/tools.h index 66c8793399c93..ccd49d2a790e2 100644 --- a/flang/include/flang/Parser/tools.h +++ b/flang/include/flang/Parser/tools.h @@ -117,5 +117,10 @@ template struct HasSource(A::source), 0)> : std::true_type {}; +// Detects parse tree nodes with "typedExpr" members. +template struct HasTypedExpr : std::false_type {}; +template +struct HasTypedExpr(A::typedExpr), 0)> + : std::true_type {}; } // namespace Fortran::parser #endif // FORTRAN_PARSER_TOOLS_H_ diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h index f81d5199dc209..2f89820f4b0b1 100644 --- a/flang/include/flang/Semantics/expression.h +++ b/flang/include/flang/Semantics/expression.h @@ -74,14 +74,13 @@ struct SetExprHelper { x.Reset(new GenericExprWrapper{std::move(expr_)}, evaluate::GenericExprWrapper::Deleter); } - 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); } template void Set(const common::Indirection &x) { Set(x.value()); } template void Set(const T &x) { - if constexpr (ConstraintTrait) { + if constexpr (parser::HasTypedExpr::value) { + Set(x.typedExpr); + } else if constexpr (ConstraintTrait) { Set(x.thing); } else if constexpr (WrapperTrait) { Set(x.v); @@ -157,6 +156,8 @@ class ExpressionAnalyzer { MaybeExpr Analyze(const parser::Variable &); MaybeExpr Analyze(const parser::Designator &); MaybeExpr Analyze(const parser::DataStmtValue &); + MaybeExpr Analyze(const parser::AllocateObject &); + MaybeExpr Analyze(const parser::PointerObject &); template MaybeExpr Analyze(const common::Indirection &x) { return Analyze(x.value()); @@ -451,6 +452,14 @@ class ExprChecker { exprAnalyzer_.Analyze(x); return false; } + bool Pre(const parser::AllocateObject &x) { + exprAnalyzer_.Analyze(x); + return false; + } + bool Pre(const parser::PointerObject &x) { + exprAnalyzer_.Analyze(x); + return false; + } bool Pre(const parser::DataImpliedDo &); bool Pre(const parser::CallStmt &x) { diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h index 3e8d1993f9a04..550cc99f85efe 100644 --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -257,9 +257,13 @@ bool ExprTypeKindIsDefault( const SomeExpr &expr, const SemanticsContext &context); struct GetExprHelper { + // Specializations for parse tree nodes that have a typedExpr member. static const SomeExpr *Get(const parser::Expr &); static const SomeExpr *Get(const parser::Variable &); static const SomeExpr *Get(const parser::DataStmtConstant &); + static const SomeExpr *Get(const parser::AllocateObject &); + static const SomeExpr *Get(const parser::PointerObject &); + template static const SomeExpr *Get(const common::Indirection &x) { return Get(x.value()); @@ -268,6 +272,8 @@ struct GetExprHelper { return x ? Get(*x) : nullptr; } template static const SomeExpr *Get(const T &x) { + static_assert( + !parser::HasTypedExpr::value, "explicit Get overload must be added"); if constexpr (ConstraintTrait) { return Get(x.thing); } else if constexpr (WrapperTrait) { diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 8adcc32b87afc..eaa4c926068c3 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -16,6 +16,7 @@ #include "flang/Parser/characters.h" #include "flang/Parser/parse-tree-visitor.h" #include "flang/Parser/parse-tree.h" +#include "flang/Parser/tools.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -48,6 +49,14 @@ class UnparseVisitor { Unparse(x); Post(x); return false; // Walk() does not visit descendents + } else if constexpr (HasTypedExpr::value) { + // Format the expression representation from semantics + if (asFortran_ && x.typedExpr) { + asFortran_->expr(out_, *x.typedExpr); + return false; + } else { + return true; + } } else { Before(x); return true; // there's no Unparse() defined here, Walk() the descendents @@ -816,15 +825,6 @@ class UnparseVisitor { } // R1001 - R1022 - bool Pre(const Expr &x) { - if (asFortran_ && x.typedExpr) { - // Format the expression representation from semantics - asFortran_->expr(out_, *x.typedExpr); - return false; - } else { - return true; - } - } void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); } void Before(const Expr::UnaryPlus &) { Put("+"); } void Before(const Expr::Negate &) { Put("-"); } diff --git a/flang/lib/Semantics/check-deallocate.cpp b/flang/lib/Semantics/check-deallocate.cpp index 92e197bbb322e..03c2d6ebdddac 100644 --- a/flang/lib/Semantics/check-deallocate.cpp +++ b/flang/lib/Semantics/check-deallocate.cpp @@ -34,8 +34,9 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) { } }, [&](const parser::StructureComponent &structureComponent) { - evaluate::ExpressionAnalyzer analyzer{context_}; - if (MaybeExpr checked{analyzer.Analyze(structureComponent)}) { + // Only perform structureComponent checks it was successfully + // analyzed in expression analysis. + if (GetExpr(allocateObject)) { if (!IsAllocatableOrPointer( *structureComponent.component.symbol)) { // C932 context_.Say(structureComponent.component.source, diff --git a/flang/lib/Semantics/check-nullify.cpp b/flang/lib/Semantics/check-nullify.cpp index ff49a661e206e..4c6e78e7f7e3e 100644 --- a/flang/lib/Semantics/check-nullify.cpp +++ b/flang/lib/Semantics/check-nullify.cpp @@ -40,13 +40,12 @@ void NullifyChecker::Leave(const parser::NullifyStmt &nullifyStmt) { } }, [&](const parser::StructureComponent &structureComponent) { - evaluate::ExpressionAnalyzer analyzer{context_}; - if (MaybeExpr checked{analyzer.Analyze(structureComponent)}) { + if (const auto *checkedExpr{GetExpr(pointerObject)}) { if (!IsPointer(*structureComponent.component.symbol)) { // C951 messages.Say(structureComponent.component.source, "component in NULLIFY statement must have the POINTER attribute"_err_en_US); } else if (pure) { - if (const Symbol * symbol{GetFirstSymbol(checked)}) { + if (const Symbol * symbol{GetFirstSymbol(*checkedExpr)}) { CheckDefinabilityInPureScope( messages, *symbol, scope, *pure); } diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index 3413a7531759e..0b36de464129e 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2139,18 +2139,48 @@ template static const Symbol *AssumedTypeDummy(const A &x) { if (const auto *dataRef{ std::get_if(&designator->value().u)}) { if (const auto *name{std::get_if(&dataRef->u)}) { - if (const Symbol * symbol{name->symbol}) { - if (const auto *type{symbol->GetType()}) { - if (type->category() == semantics::DeclTypeSpec::TypeStar) { - return symbol; - } - } - } + return AssumedTypeDummy(*name); } } } return nullptr; } +template <> +const Symbol *AssumedTypeDummy(const parser::Name &name) { + if (const Symbol * symbol{name.symbol}) { + if (const auto *type{symbol->GetType()}) { + if (type->category() == semantics::DeclTypeSpec::TypeStar) { + return symbol; + } + } + } + return nullptr; +} +template +static const Symbol *AssumedTypePointerOrAllocatableDummy(const A &object) { + // It is illegal for allocatable of pointer objects to be TYPE(*), but at that + // point it is is not guaranteed that it has been checked the object has + // POINTER or ALLOCATABLE attribute, so do not assume nullptr can be directly + // returned. + return std::visit( + common::visitors{ + [&](const parser::StructureComponent &x) { + return AssumedTypeDummy(x.component); + }, + [&](const parser::Name &x) { return AssumedTypeDummy(x); }, + }, + object.u); +} +template <> +const Symbol *AssumedTypeDummy( + const parser::AllocateObject &x) { + return AssumedTypePointerOrAllocatableDummy(x); +} +template <> +const Symbol *AssumedTypeDummy( + const parser::PointerObject &x) { + return AssumedTypePointerOrAllocatableDummy(x); +} MaybeExpr ExpressionAnalyzer::Analyze(const parser::FunctionReference &funcRef, std::optional *structureConstructor) { @@ -2737,6 +2767,18 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtConstant &x) { return ExprOrVariable(x, x.source); } +MaybeExpr ExpressionAnalyzer::Analyze(const parser::AllocateObject &x) { + parser::CharBlock source{parser::FindSourceLocation(x)}; + auto restorer{GetContextualMessages().SetLocation(source)}; + return ExprOrVariable(x, source); +} + +MaybeExpr ExpressionAnalyzer::Analyze(const parser::PointerObject &x) { + parser::CharBlock source{parser::FindSourceLocation(x)}; + auto restorer{GetContextualMessages().SetLocation(source)}; + return ExprOrVariable(x, source); +} + Expr ExpressionAnalyzer::AnalyzeKindSelector( TypeCategory category, const std::optional &selector) { diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp index 2d7fa9de93922..256a5cc1d317f 100644 --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -374,17 +374,24 @@ static void CheckMissingAnalysis(bool absent, const T &x) { } } -const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { +template static const SomeExpr *GetTypedExpr(const T &x) { CheckMissingAnalysis(!x.typedExpr, x); return common::GetPtrFromOptional(x.typedExpr->v); } +const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { + return GetTypedExpr(x); +} const SomeExpr *GetExprHelper::Get(const parser::Variable &x) { - CheckMissingAnalysis(!x.typedExpr, x); - return common::GetPtrFromOptional(x.typedExpr->v); + return GetTypedExpr(x); } const SomeExpr *GetExprHelper::Get(const parser::DataStmtConstant &x) { - CheckMissingAnalysis(!x.typedExpr, x); - return common::GetPtrFromOptional(x.typedExpr->v); + return GetTypedExpr(x); +} +const SomeExpr *GetExprHelper::Get(const parser::AllocateObject &x) { + return GetTypedExpr(x); +} +const SomeExpr *GetExprHelper::Get(const parser::PointerObject &x) { + return GetTypedExpr(x); } const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) {