From 8ae55f79bcd0a134f1b9ea02606e761674a1104f Mon Sep 17 00:00:00 2001 From: Tim Keith Date: Thu, 6 Dec 2018 06:59:37 -0800 Subject: [PATCH] [flang] Rework when symbol table expressions are evaluated It's not good enough to evaluate expressions in the symbol table after name resolution has completed. This is because we need the values of constant expressions for types, for example, we need to evaluate `k` in `integer(k) :: x` to know the type of `x`. So, eliminate `LazyExpr` and call `EvaluateExpr()` on expressions that we need in the symbol table. The latter evaluates and folds an expression in the current context. This is now possible because symbols are added to `parser::Name` as soon as possible rather than in a pass after name resolution. Along with `LazyExpr` we can eliminate the whole `ResolveSymbolExprs` pass that used to resolve them. In resolve-names.cc, many `Pre` functions are changed to `Post` so that names are resolved before doing the associated processing. For example, with intrinsic type specs, names in the kind expression must be resolved before attempting to evaluate that expression. In `GetSymbolType()` in type.cc, handle both `ObjectEntityDetails` and `EntityDetails` by using `Symbol::GetType()`. Add explicit declarations in label01.F90 because we can't handle implicitly typed array bounds yet. Original-commit: flang-compiler/f18@d67716640baeedca150205f9f3845ceb5d2f6402 Reviewed-on: https://github.com/flang-compiler/f18/pull/238 --- flang/lib/evaluate/type.cc | 29 +++--- flang/lib/semantics/expression.cc | 5 +- flang/lib/semantics/mod-file.cc | 18 ++-- flang/lib/semantics/resolve-names.cc | 188 ++++++++++++++++------------------- flang/lib/semantics/semantics.cc | 1 - flang/lib/semantics/symbol.cc | 16 +-- flang/lib/semantics/symbol.h | 18 ++-- flang/lib/semantics/type.cc | 109 ++------------------ flang/lib/semantics/type.h | 48 ++------- flang/test/semantics/CMakeLists.txt | 1 + flang/test/semantics/label01.F90 | 10 ++ flang/test/semantics/modfile12.f90 | 12 ++- flang/test/semantics/resolve37.f90 | 32 ++++++ 13 files changed, 191 insertions(+), 296 deletions(-) create mode 100644 flang/test/semantics/resolve37.f90 diff --git a/flang/lib/evaluate/type.cc b/flang/lib/evaluate/type.cc index 00b1ed3..e20001b 100644 --- a/flang/lib/evaluate/type.cc +++ b/flang/lib/evaluate/type.cc @@ -25,23 +25,20 @@ using namespace std::literals::string_literals; namespace Fortran::evaluate { std::optional GetSymbolType(const semantics::Symbol &symbol) { - if (auto *details{symbol.detailsIf()}) { - if (details->type().has_value()) { - switch (details->type()->category()) { - case semantics::DeclTypeSpec::Category::Intrinsic: { - TypeCategory category{details->type()->intrinsicTypeSpec().category()}; - int kind{details->type()->intrinsicTypeSpec().kind()}; - if (IsValidKindOfIntrinsicType(category, kind)) { - return std::make_optional(DynamicType{category, kind}); - } - break; - } - case semantics::DeclTypeSpec::Category::TypeDerived: - case semantics::DeclTypeSpec::Category::ClassDerived: - return std::make_optional(DynamicType{ - TypeCategory::Derived, 0, &details->type()->derivedTypeSpec()}); - default:; + if (const auto *type{symbol.GetType()}) { + switch (type->category()) { + case semantics::DeclTypeSpec::Category::Intrinsic: { + TypeCategory category{type->intrinsicTypeSpec().category()}; + int kind{type->intrinsicTypeSpec().kind()}; + if (IsValidKindOfIntrinsicType(category, kind)) { + return DynamicType{category, kind}; } + break; + } + case semantics::DeclTypeSpec::Category::TypeDerived: + case semantics::DeclTypeSpec::Category::ClassDerived: + return DynamicType{TypeCategory::Derived, 0, &type->derivedTypeSpec()}; + default:; } } return std::nullopt; diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 9d068c4b..1013e32 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -742,9 +742,8 @@ MaybeExpr AnalyzeExpr( n.ToString().data()); } else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) { if (auto *details{n.symbol->detailsIf()}) { - auto &init{details->init()}; - if (init.Resolve(context.context())) { - return init.Get(); + if (auto &init{details->init()}) { + return init; } } context.Say(n.source, "parameter '%s' does not have a value"_err_en_US, diff --git a/flang/lib/semantics/mod-file.cc b/flang/lib/semantics/mod-file.cc index bcacf5a..452ab1c 100644 --- a/flang/lib/semantics/mod-file.cc +++ b/flang/lib/semantics/mod-file.cc @@ -43,9 +43,9 @@ static void PutObjectEntity(std::ostream &, const Symbol &); static void PutProcEntity(std::ostream &, const Symbol &); static void PutTypeParam(std::ostream &, const Symbol &); static void PutEntity(std::ostream &, const Symbol &, std::function); -static void PutInit(std::ostream &, const LazyExpr &); +static void PutInit(std::ostream &, const MaybeExpr &); static void PutBound(std::ostream &, const Bound &); -static void PutExpr(std::ostream &, const LazyExpr &); +static void PutExpr(std::ostream &, const SomeExpr &); static std::ostream &PutAttrs( std::ostream &, Attrs, std::string before = ","s, std::string after = ""s); static std::ostream &PutLower(std::ostream &, const Symbol &); @@ -372,9 +372,9 @@ void PutTypeParam(std::ostream &os, const Symbol &symbol) { PutInit(os, details.init()); } -void PutInit(std::ostream &os, const LazyExpr &init) { - if (init.Get()) { - PutExpr(os << '=', init); +void PutInit(std::ostream &os, const MaybeExpr &init) { + if (init) { + PutExpr(os << '=', *init); } } @@ -384,15 +384,11 @@ void PutBound(std::ostream &os, const Bound &x) { } else if (x.isDeferred()) { os << ':'; } else { - PutExpr(os, x.GetExplicit()); + x.GetExplicit()->AsFortran(os); } } -void PutExpr(std::ostream &os, const LazyExpr &expr) { - if (auto x{expr.Get()}) { - x->AsFortran(os); - } -} +void PutExpr(std::ostream &os, const SomeExpr &expr) { expr.AsFortran(os); } // Write an entity (object or procedure) declaration. // writeType is called to write out the type. diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 6e7a427..5dec603 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -15,6 +15,7 @@ #include "resolve-names.h" #include "attr.h" #include "default-kinds.h" +#include "expression.h" #include "mod-file.h" #include "rewrite-parse-tree.h" #include "scope.h" @@ -22,6 +23,9 @@ #include "symbol.h" #include "type.h" #include "../common/indirection.h" +#include "../evaluate/common.h" +#include "../evaluate/fold.h" +#include "../evaluate/tools.h" #include "../parser/parse-tree-visitor.h" #include "../parser/parse-tree.h" #include @@ -41,11 +45,6 @@ using MessageFormattedText = parser::MessageFormattedText; class ResolveNamesVisitor; static const parser::Name *GetGenericSpecName(const parser::GenericSpec &); -static const parser::Expr &GetExpr(const parser::ConstantExpr &); -static const parser::Expr &GetExpr(const parser::IntConstantExpr &); -static const parser::Expr &GetExpr(const parser::IntExpr &); -static const parser::Expr &GetExpr(const parser::ScalarIntExpr &); -static const parser::Expr &GetExpr(const parser::ScalarIntConstantExpr &); // ImplicitRules maps initial character of identifier to the DeclTypeSpec // representing the implicit type; std::nullopt if none. @@ -121,9 +120,16 @@ public: SemanticsContext &context() const { return *context_; } void set_context(SemanticsContext &); - template - Message &Say(const parser::Name &name, MessageFixedText &&msg, A... args) { - return Say(name.source, std::move(msg), std::forward(args)...); + template MaybeExpr EvaluateExpr(const T &expr) { + if (auto maybeExpr{AnalyzeExpr(*context_, expr)}) { + return evaluate::Fold(context_->foldingContext(), std::move(*maybeExpr)); + } else { + return std::nullopt; + } + } + + template Message &Say(const parser::Name &name, A... args) { + return messageHandler_.Say(name.source, std::forward(args)...); } template Message &Say(A... args) { return messageHandler_.Say(std::forward(args)...); @@ -205,12 +211,12 @@ public: explicit DeclTypeSpecVisitor() {} using AttrsVisitor::Post; using AttrsVisitor::Pre; - bool Pre(const parser::IntegerTypeSpec &); - bool Pre(const parser::IntrinsicTypeSpec::Logical &); - bool Pre(const parser::IntrinsicTypeSpec::Real &); - bool Pre(const parser::IntrinsicTypeSpec::Complex &); - bool Pre(const parser::IntrinsicTypeSpec::DoublePrecision &); - bool Pre(const parser::IntrinsicTypeSpec::DoubleComplex &); + void Post(const parser::IntegerTypeSpec &); + void Post(const parser::IntrinsicTypeSpec::Logical &); + void Post(const parser::IntrinsicTypeSpec::Real &); + void Post(const parser::IntrinsicTypeSpec::Complex &); + void Post(const parser::IntrinsicTypeSpec::DoublePrecision &); + void Post(const parser::IntrinsicTypeSpec::DoubleComplex &); void Post(const parser::IntrinsicTypeSpec::Character &); bool Pre(const parser::DeclarationTypeSpec::ClassStar &); bool Pre(const parser::DeclarationTypeSpec::TypeStar &); @@ -234,8 +240,10 @@ private: const parser::Name *derivedTypeName_{nullptr}; void SetDeclTypeSpec(const DeclTypeSpec &declTypeSpec); - void MakeIntrinsic(TypeCategory, int); - static int GetKindParamValue(const std::optional &kind); + void MakeIntrinsic(TypeCategory, const std::optional &); + void MakeIntrinsic(TypeCategory, int kind); + int GetKindParamValue( + TypeCategory, const std::optional &); ParamValue GetParamValue(const parser::TypeParamValue &); }; @@ -290,11 +298,11 @@ public: bool Pre(const parser::ArraySpec &); void Post(const parser::AttrSpec &) { PostAttrSpec(); } void Post(const parser::ComponentAttrSpec &) { PostAttrSpec(); } - bool Pre(const parser::DeferredShapeSpecList &); - bool Pre(const parser::AssumedShapeSpec &); - bool Pre(const parser::ExplicitShapeSpec &); - bool Pre(const parser::AssumedImpliedSpec &); - bool Pre(const parser::AssumedRankSpec &); + void Post(const parser::DeferredShapeSpecList &); + void Post(const parser::AssumedShapeSpec &); + void Post(const parser::ExplicitShapeSpec &); + void Post(const parser::AssumedImpliedSpec &); + void Post(const parser::AssumedRankSpec &); protected: const ArraySpec &arraySpec(); @@ -553,7 +561,7 @@ public: bool Pre(const parser::BindStmt &) { return BeginAttrs(); } void Post(const parser::BindStmt &) { EndAttrs(); } bool Pre(const parser::BindEntity &); - bool Pre(const parser::NamedConstantDef &); + void Post(const parser::NamedConstantDef &); bool Pre(const parser::AsynchronousStmt &); bool Pre(const parser::ContiguousStmt &); bool Pre(const parser::ExternalStmt &); @@ -1002,7 +1010,9 @@ void DeclTypeSpecVisitor::Post(const parser::TypeParamSpec &x) { ParamValue DeclTypeSpecVisitor::GetParamValue(const parser::TypeParamValue &x) { return std::visit( common::visitors{ - [](const parser::ScalarIntExpr &x) { return ParamValue{GetExpr(x)}; }, + [=](const parser::ScalarIntExpr &x) { + return ParamValue{EvaluateExpr(x)}; + }, [](const parser::Star &) { return ParamValue::Assumed(); }, [](const parser::TypeParamValue::Deferred &) { return ParamValue::Deferred(); @@ -1027,36 +1037,34 @@ void DeclTypeSpecVisitor::Post(const parser::TypeGuardStmt &) { derivedTypeName_ = nullptr; } -bool DeclTypeSpecVisitor::Pre(const parser::IntegerTypeSpec &x) { - MakeIntrinsic(TypeCategory::Integer, GetKindParamValue(x.v)); - return false; +void DeclTypeSpecVisitor::Post(const parser::IntegerTypeSpec &x) { + MakeIntrinsic(TypeCategory::Integer, x.v); } void DeclTypeSpecVisitor::Post(const parser::IntrinsicTypeSpec::Character &x) { CHECK(!"TODO: character"); } -bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Logical &x) { - MakeIntrinsic(TypeCategory::Logical, GetKindParamValue(x.kind)); - return false; +void DeclTypeSpecVisitor::Post(const parser::IntrinsicTypeSpec::Logical &x) { + MakeIntrinsic(TypeCategory::Logical, x.kind); } -bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Real &x) { - MakeIntrinsic(TypeCategory::Real, GetKindParamValue(x.kind)); - return false; +void DeclTypeSpecVisitor::Post(const parser::IntrinsicTypeSpec::Real &x) { + MakeIntrinsic(TypeCategory::Real, x.kind); } -bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Complex &x) { - MakeIntrinsic(TypeCategory::Complex, GetKindParamValue(x.kind)); - return false; +void DeclTypeSpecVisitor::Post(const parser::IntrinsicTypeSpec::Complex &x) { + MakeIntrinsic(TypeCategory::Complex, x.kind); } -bool DeclTypeSpecVisitor::Pre( +void DeclTypeSpecVisitor::Post( const parser::IntrinsicTypeSpec::DoublePrecision &) { MakeIntrinsic( TypeCategory::Real, context().defaultKinds().doublePrecisionKind()); - return false; } -bool DeclTypeSpecVisitor::Pre( +void DeclTypeSpecVisitor::Post( const parser::IntrinsicTypeSpec::DoubleComplex &) { MakeIntrinsic( TypeCategory::Complex, context().defaultKinds().doublePrecisionKind()); - return false; +} +void DeclTypeSpecVisitor::MakeIntrinsic( + TypeCategory category, const std::optional &kind) { + MakeIntrinsic(category, GetKindParamValue(category, kind)); } void DeclTypeSpecVisitor::MakeIntrinsic(TypeCategory category, int kind) { if (kind == 0) { @@ -1088,21 +1096,29 @@ void DeclTypeSpecVisitor::SetDeclTypeSpec(const DeclTypeSpec &declTypeSpec) { } int DeclTypeSpecVisitor::GetKindParamValue( - const std::optional &kind) { - if (kind) { - if (auto *intExpr{std::get_if(&kind->u)}) { - const auto &expr{GetExpr(*intExpr)}; - if (auto *lit{std::get_if(&expr.u)}) { - if (auto *intLit{std::get_if(&lit->u)}) { - return std::get(intLit->t); - } - } - CHECK(!"TODO: constant evaluation"); - } else { - CHECK(!"TODO: translate star-size to kind"); - } + TypeCategory category, const std::optional &kind) { + if (!kind) { + return 0; } - return 0; + // TODO: check that we get a valid kind + return std::visit( + common::visitors{ + [&](const parser::ScalarIntConstantExpr &x) -> int { + if (auto maybeExpr{EvaluateExpr(x)}) { + return evaluate::ToInt64(*maybeExpr).value(); + } else { + return 0; + } + }, + [&](const parser::KindSelector::StarSize &x) -> int { + std::uint64_t size{x.v}; + if (category == TypeCategory::Complex) { + size /= 2; + } + return size; + }, + }, + kind->u); } // MessageHandler implementation @@ -1249,40 +1265,35 @@ bool ArraySpecVisitor::Pre(const parser::ArraySpec &x) { return true; } -bool ArraySpecVisitor::Pre(const parser::DeferredShapeSpecList &x) { +void ArraySpecVisitor::Post(const parser::DeferredShapeSpecList &x) { for (int i = 0; i < x.v; ++i) { arraySpec_.push_back(ShapeSpec::MakeDeferred()); } - return false; } -bool ArraySpecVisitor::Pre(const parser::AssumedShapeSpec &x) { +void ArraySpecVisitor::Post(const parser::AssumedShapeSpec &x) { const auto &lb{x.v}; arraySpec_.push_back( lb ? ShapeSpec::MakeAssumed(GetBound(*lb)) : ShapeSpec::MakeAssumed()); - return true; } -bool ArraySpecVisitor::Pre(const parser::ExplicitShapeSpec &x) { +void ArraySpecVisitor::Post(const parser::ExplicitShapeSpec &x) { auto &&ub{GetBound(std::get(x.t))}; if (const auto &lb{std::get>(x.t)}) { arraySpec_.push_back(ShapeSpec::MakeExplicit(GetBound(*lb), std::move(ub))); } else { arraySpec_.push_back(ShapeSpec::MakeExplicit(Bound{1}, std::move(ub))); } - return true; } -bool ArraySpecVisitor::Pre(const parser::AssumedImpliedSpec &x) { +void ArraySpecVisitor::Post(const parser::AssumedImpliedSpec &x) { const auto &lb{x.v}; arraySpec_.push_back( lb ? ShapeSpec::MakeImplied(GetBound(*lb)) : ShapeSpec::MakeImplied()); - return false; } -bool ArraySpecVisitor::Pre(const parser::AssumedRankSpec &) { +void ArraySpecVisitor::Post(const parser::AssumedRankSpec &) { arraySpec_.push_back(ShapeSpec::MakeAssumedRank()); - return false; } const ArraySpec &ArraySpecVisitor::arraySpec() { @@ -1307,7 +1318,7 @@ void ArraySpecVisitor::PostAttrSpec() { } Bound ArraySpecVisitor::GetBound(const parser::SpecificationExpr &x) { - return Bound{GetExpr(x.v)}; + return Bound{EvaluateExpr(x.v)}; } // ScopeHandler implementation @@ -1749,6 +1760,7 @@ bool InterfaceVisitor::Pre(const parser::GenericSpec &x) { const Symbol &ultimate{genericSymbol->GetUltimate()}; EraseSymbol(*genericName_); genericSymbol = &CopySymbol(ultimate); + genericName_->symbol = genericSymbol; if (const auto *details{ultimate.detailsIf()}) { genericSymbol->set_details(GenericDetails{details->specificProcs()}); } else if (const auto *details{ultimate.detailsIf()}) { @@ -1766,20 +1778,13 @@ bool InterfaceVisitor::Pre(const parser::GenericSpec &x) { // okay } else if (genericSymbol->has() || genericSymbol->has()) { - Details details; - if (auto *d{genericSymbol->detailsIf()}) { - details = *d; - } else if (auto *d{genericSymbol->detailsIf()}) { - details = *d; - } else { - common::die("unexpected kind of symbol"); - } GenericDetails genericDetails; genericDetails.set_specific(*genericSymbol); EraseSymbol(*genericName_); genericSymbol = &MakeSymbol(*genericName_, genericDetails); + } else { + common::die("unexpected kind of symbol"); } - CHECK(genericSymbol->has()); CHECK(genericName_->symbol == genericSymbol); return false; } @@ -1815,6 +1820,7 @@ void InterfaceVisitor::Post(const parser::GenericStmt &x) { GenericDetails &InterfaceVisitor::GetGenericDetails() { CHECK(genericName_); + CHECK(genericName_->symbol); return genericName_->symbol->get(); } @@ -2202,8 +2208,8 @@ void DeclarationVisitor::Post(const parser::EntityDecl &x) { Symbol &symbol{DeclareUnknownEntity(name, attrs)}; if (auto &init{std::get>(x.t)}) { if (ConvertToObjectEntity(symbol)) { - if (auto *initExpr{std::get_if(&init->u)}) { - symbol.get().set_init(GetExpr(*initExpr)); + if (auto *expr{std::get_if(&init->u)}) { + symbol.get().set_init(EvaluateExpr(*expr)); } } } @@ -2224,18 +2230,17 @@ bool DeclarationVisitor::Pre(const parser::BindEntity &x) { } return false; } -bool DeclarationVisitor::Pre(const parser::NamedConstantDef &x) { +void DeclarationVisitor::Post(const parser::NamedConstantDef &x) { auto &name{std::get(x.t).v}; auto &symbol{HandleAttributeStmt(Attr::PARAMETER, name)}; if (!ConvertToObjectEntity(symbol)) { Say2(name, "PARAMETER attribute not allowed on '%s'"_err_en_US, symbol, "Declaration of '%s'"_en_US); - return false; + return; } const auto &expr{std::get(x.t)}; - symbol.get().set_init(GetExpr(expr)); + symbol.get().set_init(EvaluateExpr(expr)); ApplyImplicitRules(symbol); - return false; } bool DeclarationVisitor::Pre(const parser::AsynchronousStmt &x) { return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v); @@ -2453,7 +2458,7 @@ void DeclarationVisitor::Post(const parser::TypeParamDefStmt &x) { auto details{TypeParamDetails{attr}}; if (auto &init{ std::get>(decl.t)}) { - details.set_init(GetExpr(*init)); + details.set_init(EvaluateExpr(*init)); } MakeTypeSymbol(name, std::move(details)); SetType(name, *type); @@ -2495,7 +2500,7 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) { if (auto *details{symbol.detailsIf()}) { if (auto &init{std::get>(x.t)}) { if (auto *initExpr{std::get_if(&init->u)}) { - details->set_init(GetExpr(*initExpr)); + details->set_init(EvaluateExpr(*initExpr)); } } } @@ -2816,7 +2821,7 @@ bool ConstructVisitor::Pre(const parser::DataImpliedDo &x) { std::get>(x.t)}; if (type) { BeginDeclTypeSpec(); - DeclTypeSpecVisitor::Pre(*type); + DeclTypeSpecVisitor::Post(*type); } if (auto *symbol{DeclareConstructEntity(bounds.name.thing.thing)}) { CheckIntegerType(*symbol); @@ -3162,8 +3167,7 @@ void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) { // OK } else if (symbol->has()) { // OK: type constructor - } else if (auto *details{symbol->detailsIf()}; - details && details->isArray()) { + } else if (symbol->has()) { // OK: array mis-parsed as a call } else if (symbol->test(Symbol::Flag::Implicit)) { Say(*name, @@ -3399,20 +3403,4 @@ static const parser::Name *GetGenericSpecName(const parser::GenericSpec &x) { return nullptr; } } - -static const parser::Expr &GetExpr(const parser::ConstantExpr &x) { - return *x.thing; -} -static const parser::Expr &GetExpr(const parser::IntExpr &x) { - return *x.thing; -} -static const parser::Expr &GetExpr(const parser::IntConstantExpr &x) { - return GetExpr(x.thing); -} -static const parser::Expr &GetExpr(const parser::ScalarIntExpr &x) { - return GetExpr(x.thing); -} -static const parser::Expr &GetExpr(const parser::ScalarIntConstantExpr &x) { - return GetExpr(x.thing); -} } diff --git a/flang/lib/semantics/semantics.cc b/flang/lib/semantics/semantics.cc index 3708961..20a8782 100644 --- a/flang/lib/semantics/semantics.cc +++ b/flang/lib/semantics/semantics.cc @@ -56,7 +56,6 @@ bool Semantics::Perform() { if (AnyFatalError()) { return false; } - ResolveSymbolExprs(context_); if (AnyFatalError()) { return false; } diff --git a/flang/lib/semantics/symbol.cc b/flang/lib/semantics/symbol.cc index 1bda42d..16dd363 100644 --- a/flang/lib/semantics/symbol.cc +++ b/flang/lib/semantics/symbol.cc @@ -69,10 +69,6 @@ ProcEntityDetails::ProcEntityDetails(const EntityDetails &d) { } } -void TypeParamDetails::set_init(const parser::Expr &expr) { - init_ = LazyExpr{expr}; -} - const Symbol &UseDetails::module() const { // owner is a module so it must have a symbol: return *symbol_->owner().symbol(); @@ -277,10 +273,6 @@ int Symbol::Rank() const { ObjectEntityDetails::ObjectEntityDetails(const EntityDetails &d) : isDummy_{d.isDummy()}, type_{d.type()} {} -void ObjectEntityDetails::set_init(const parser::Expr &x) { - init_ = LazyExpr{x}; -} - std::ostream &operator<<(std::ostream &os, const EntityDetails &x) { if (x.type()) { os << " type: " << *x.type(); @@ -298,8 +290,8 @@ std::ostream &operator<<(std::ostream &os, const ObjectEntityDetails &x) { os << ' ' << s; } } - if (x.init_.Get()) { - os << " init:" << x.init_; + if (x.init_) { + x.init_->AsFortran(os << " init:"); } return os; } @@ -409,8 +401,8 @@ std::ostream &operator<<(std::ostream &os, const Details &details) { os << ' ' << *x.type(); } os << ' ' << common::EnumToString(x.attr()); - if (x.init().Get()) { - os << " init:" << x.init(); + if (x.init()) { + x.init()->AsFortran(os << " init:"); } }, [&](const MiscDetails &x) { diff --git a/flang/lib/semantics/symbol.h b/flang/lib/semantics/symbol.h index 7ed9a24..ac16c6f 100644 --- a/flang/lib/semantics/symbol.h +++ b/flang/lib/semantics/symbol.h @@ -115,9 +115,9 @@ class ObjectEntityDetails { public: ObjectEntityDetails(const EntityDetails &); ObjectEntityDetails(bool isDummy = false) : isDummy_{isDummy} {} - LazyExpr &init() { return init_; } - const LazyExpr &init() const { return init_; } - void set_init(const parser::Expr &); + MaybeExpr &init() { return init_; } + const MaybeExpr &init() const { return init_; } + void set_init(MaybeExpr &&expr) { init_ = std::move(expr); } const std::optional &type() const { return type_; } void set_type(const DeclTypeSpec &type); ArraySpec &shape() { return shape_; } @@ -136,7 +136,7 @@ public: private: bool isDummy_; - LazyExpr init_; + MaybeExpr init_; std::optional type_; ArraySpec shape_; friend std::ostream &operator<<(std::ostream &, const ObjectEntityDetails &); @@ -200,11 +200,9 @@ class TypeParamDetails { public: TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {} common::TypeParamAttr attr() const { return attr_; } - // std::optional &init() { return init_; } - // const std::optional &init() const { return init_; } - LazyExpr &init() { return init_; } - const LazyExpr &init() const { return init_; } - void set_init(const parser::Expr &); + MaybeExpr &init() { return init_; } + const MaybeExpr &init() const { return init_; } + void set_init(MaybeExpr &&expr) { init_ = std::move(expr); } const std::optional &type() const { return type_; } void set_type(const DeclTypeSpec &type) { CHECK(!type_); @@ -213,7 +211,7 @@ public: private: common::TypeParamAttr attr_; - LazyExpr init_; + MaybeExpr init_; std::optional type_; }; diff --git a/flang/lib/semantics/type.cc b/flang/lib/semantics/type.cc index 9d9242c..28382a9 100644 --- a/flang/lib/semantics/type.cc +++ b/flang/lib/semantics/type.cc @@ -24,43 +24,6 @@ namespace Fortran::semantics { -LazyExpr::LazyExpr(SomeExpr &&expr) : u_{CopyableExprPtr{std::move(expr)}} {} - -MaybeExpr LazyExpr::Get() { return static_cast(this)->Get(); } - -const MaybeExpr LazyExpr::Get() const { - if (auto *ptr{std::get_if(&u_)}) { - return **ptr; - } else { - return std::nullopt; - } -} - -bool LazyExpr::Resolve(SemanticsContext &context) { - if (auto *expr{std::get_if(&u_)}) { - if (!*expr) { - u_ = ErrorInExpr{}; - } else if (MaybeExpr maybeExpr{AnalyzeExpr(context, **expr)}) { - u_ = CopyableExprPtr{ - evaluate::Fold(context.foldingContext(), std::move(*maybeExpr))}; - } else { - u_ = ErrorInExpr{}; - } - } - return std::holds_alternative(u_); -} - -std::ostream &operator<<(std::ostream &o, const LazyExpr &x) { - std::visit( - common::visitors{ - [&](const parser::Expr *x) { o << (x ? "UNRESOLVED" : "EMPTY"); }, - [&](const LazyExpr::ErrorInExpr &) { o << "ERROR"; }, - [&](const LazyExpr::CopyableExprPtr &x) { x->AsFortran(o); }, - }, - x.u_); - return o; -} - void DerivedTypeSpec::set_scope(const Scope &scope) { CHECK(!scope_); CHECK(scope.kind() == Scope::Kind::DerivedType); @@ -101,19 +64,17 @@ Bound::Bound(int bound) expr_{SomeExpr{evaluate::AsExpr( evaluate::Constant{bound})}} {} -void Bound::Resolve(SemanticsContext &context) { - if (isExplicit()) { - expr_.Resolve(context); - } -} +Bound Bound::Clone() const { return Bound(category_, MaybeExpr{expr_}); } std::ostream &operator<<(std::ostream &o, const Bound &x) { if (x.isAssumed()) { o << '*'; } else if (x.isDeferred()) { o << ':'; + } else if (x.expr_) { + x.expr_->AsFortran(o); } else { - o << x.expr_; + o << ""; } return o; } @@ -134,21 +95,15 @@ std::ostream &operator<<(std::ostream &o, const ShapeSpec &x) { return o; } -ParamValue::ParamValue(const parser::Expr &expr) - : category_{Category::Explicit}, expr_{expr} {} - -void ParamValue::ResolveExplicit(SemanticsContext &context) { - CHECK(isExplicit()); - expr_.Resolve(context); -} - std::ostream &operator<<(std::ostream &o, const ParamValue &x) { if (x.isAssumed()) { o << '*'; } else if (x.isDeferred()) { o << ':'; + } else if (!x.GetExplicit()) { + o << ""; } else { - o << x.GetExplicit(); + x.GetExplicit()->AsFortran(o); } return o; } @@ -220,54 +175,4 @@ void ProcInterface::set_type(const DeclTypeSpec &type) { CHECK(!symbol_); type_ = type; } - -class ExprResolver { -public: - ExprResolver(SemanticsContext &context) : context_{context} {} - void Resolve() { Resolve(context_.globalScope()); } - -private: - SemanticsContext &context_; - - void Resolve(Scope &); - void Resolve(Symbol &); - void Resolve(Bound &bound) { bound.Resolve(context_); } - void Resolve(LazyExpr &expr) { expr.Resolve(context_); } -}; - -void ExprResolver::Resolve(Scope &scope) { - for (auto &pair : scope) { - Resolve(*pair.second); - } - for (auto &child : scope.children()) { - Resolve(child); - } -} -void ExprResolver::Resolve(Symbol &symbol) { - if (auto *type{symbol.GetType()}) { - if (type->category() == DeclTypeSpec::TypeDerived) { - DerivedTypeSpec &dts{type->derivedTypeSpec()}; - for (auto &nameAndValue : dts.paramValues()) { - // &[name, value] elicits "unused variable" warnings - auto &value{nameAndValue.second}; - if (value.isExplicit()) { - value.ResolveExplicit(context_); - } - } - } - } - if (auto *details{symbol.detailsIf()}) { - Resolve(details->init()); - for (ShapeSpec &shapeSpec : details->shape()) { - Resolve(shapeSpec.lb_); - Resolve(shapeSpec.ub_); - } - } else if (auto *details{symbol.detailsIf()}) { - Resolve(details->init()); - } -} - -void ResolveSymbolExprs(SemanticsContext &context) { - ExprResolver(context).Resolve(); -} } diff --git a/flang/lib/semantics/type.h b/flang/lib/semantics/type.h index 3331faa..b95f522 100644 --- a/flang/lib/semantics/type.h +++ b/flang/lib/semantics/type.h @@ -47,54 +47,29 @@ using TypeCategory = common::TypeCategory; using SomeExpr = evaluate::Expr; using MaybeExpr = std::optional; -// An expression that starts out as a parser::Expr and gets resolved to -// a MaybeExpr. Resolve should not be called until after names are resolved. -// An unresolved LazyExpr should not be used after the parse tree is deleted. -class LazyExpr { -public: - LazyExpr() : u_{nullptr} {} - LazyExpr(const parser::Expr &expr) : u_{&expr} {} - LazyExpr(SomeExpr &&); - LazyExpr(LazyExpr &&) = default; - LazyExpr &operator=(LazyExpr &&) = default; - LazyExpr Clone() const { return LazyExpr(*this); } - const MaybeExpr Get() const; - MaybeExpr Get(); - bool Resolve(SemanticsContext &); - -private: - using CopyableExprPtr = common::Indirection; - struct ErrorInExpr {}; // marks an expr with an error in evaluation - std::variant u_; - - LazyExpr(const LazyExpr &) = default; - friend std::ostream &operator<<(std::ostream &, const LazyExpr &); -}; - // An array spec bound: an explicit integer expression or ASSUMED or DEFERRED class Bound { public: static Bound Assumed() { return Bound(Category::Assumed); } static Bound Deferred() { return Bound(Category::Deferred); } - Bound(const parser::Expr &expr) - : category_{Category::Explicit}, expr_{expr} {} + Bound(MaybeExpr &&expr) + : category_{Category::Explicit}, expr_{std::move(expr)} {} Bound(int bound); Bound(Bound &&) = default; Bound &operator=(Bound &&) = default; - Bound Clone() const { return Bound(category_, expr_.Clone()); } + Bound Clone() const; bool isExplicit() const { return category_ == Category::Explicit; } bool isAssumed() const { return category_ == Category::Assumed; } bool isDeferred() const { return category_ == Category::Deferred; } - const LazyExpr &GetExplicit() const { return expr_; } - void Resolve(SemanticsContext &); + const MaybeExpr &GetExplicit() const { return expr_; } private: enum class Category { Explicit, Deferred, Assumed }; Bound(Category category) : category_{category} {} - Bound(Category category, LazyExpr &&expr) + Bound(Category category, MaybeExpr &&expr) : category_{category}, expr_{std::move(expr)} {} Category category_; - LazyExpr expr_; + MaybeExpr expr_; friend std::ostream &operator<<(std::ostream &, const Bound &); }; @@ -174,18 +149,18 @@ class ParamValue { public: static const ParamValue Assumed() { return Category::Assumed; } static const ParamValue Deferred() { return Category::Deferred; } - ParamValue(const parser::Expr &); + ParamValue(MaybeExpr &&expr) + : category_{Category::Explicit}, expr_{std::move(expr)} {} bool isExplicit() const { return category_ == Category::Explicit; } bool isAssumed() const { return category_ == Category::Assumed; } bool isDeferred() const { return category_ == Category::Deferred; } - const LazyExpr &GetExplicit() const { return expr_; } - void ResolveExplicit(SemanticsContext &); + const MaybeExpr &GetExplicit() const { return expr_; } private: enum class Category { Explicit, Deferred, Assumed }; ParamValue(Category category) : category_{category} {} Category category_; - LazyExpr expr_; + MaybeExpr expr_; friend std::ostream &operator<<(std::ostream &, const ParamValue &); }; @@ -256,9 +231,6 @@ private: const Symbol *symbol_{nullptr}; std::optional type_; }; - -// Resolve expressions in symbols. -void ResolveSymbolExprs(SemanticsContext &); } #endif // FORTRAN_SEMANTICS_TYPE_H_ diff --git a/flang/test/semantics/CMakeLists.txt b/flang/test/semantics/CMakeLists.txt index fe0c010..95a6c3c 100644 --- a/flang/test/semantics/CMakeLists.txt +++ b/flang/test/semantics/CMakeLists.txt @@ -61,6 +61,7 @@ set(ERROR_TESTS resolve34.f90 resolve35.f90 resolve36.f90 + resolve37.f90 ) # These test files have expected symbols in the source diff --git a/flang/test/semantics/label01.F90 b/flang/test/semantics/label01.F90 index b243f61..5765222 100644 --- a/flang/test/semantics/label01.F90 +++ b/flang/test/semantics/label01.F90 @@ -24,6 +24,7 @@ subroutine sub00(a,b,n,m) + integer :: n, m real a(n) real :: b(m) 1 print *, n, m @@ -32,6 +33,7 @@ subroutine sub00(a,b,n,m) end subroutine sub00 subroutine do_loop01(a,n) + integer :: n real, dimension(n) :: a do 10 i = 1, n print *, i, a(i) @@ -39,6 +41,7 @@ subroutine do_loop01(a,n) end subroutine do_loop01 subroutine do_loop02(a,n) + integer :: n real, dimension(n,n) :: a do 10 j = 1, n do 10 i = 1, n @@ -48,12 +51,14 @@ end subroutine do_loop02 #ifndef STRICT_F18 subroutine do_loop03(a,n) + integer :: n real, dimension(n) :: a do 10 i = 1, n 10 print *, i, a(i) ! extension (not f18) end subroutine do_loop03 subroutine do_loop04(a,n) + integer :: n real :: a(n,n) do 10 j = 1, n do 10 i = 1, n @@ -61,6 +66,7 @@ subroutine do_loop04(a,n) end subroutine do_loop04 subroutine do_loop05(a,n) + integer :: n real a(n,n,n) do 10 k = 1, n do 10 j = 1, n @@ -70,6 +76,7 @@ end subroutine do_loop05 #endif subroutine do_loop06(a,n) + integer :: n real, dimension(n) :: a loopname: do i = 1, n print *, i, a(i) @@ -80,6 +87,7 @@ subroutine do_loop06(a,n) end subroutine do_loop06 subroutine do_loop07(a,n) + integer :: n real, dimension(n,n) :: a loopone: do j = 1, n looptwo: do i = 1, n @@ -89,6 +97,7 @@ subroutine do_loop07(a,n) end subroutine do_loop07 subroutine do_loop08(a,b,n,m,nn) + integer :: n, m, nn real, dimension(n,n) :: a real b(m,nn) loopone: do j = 1, n @@ -122,6 +131,7 @@ end subroutine do_loop08 #ifndef STRICT_F18 ! extended ranges supported by PGI, gfortran gives warnings subroutine do_loop09(a,n,j) + integer :: n real a(n) goto 400 200 print *, "found the index", j diff --git a/flang/test/semantics/modfile12.f90 b/flang/test/semantics/modfile12.f90 index f1df3e0..8534ab8 100644 --- a/flang/test/semantics/modfile12.f90 +++ b/flang/test/semantics/modfile12.f90 @@ -14,14 +14,16 @@ module m integer(8), parameter :: a = 1, b = 2_8 - parameter(n=3) + parameter(n=3,l=-3,e=1.0/3.0) real :: x(a:2*(a+b*n)-1) real, dimension(8) :: y type t(c, d) integer, kind :: c = 1 integer, len :: d = a + b end type - type(t(3,:)), allocatable :: z + type(t(a+3,:)), allocatable :: z + real*2 :: f + complex*32 :: g contains subroutine foo(x) real :: x(2:) @@ -36,13 +38,17 @@ end ! integer(8),parameter::a=1_4 ! integer(8),parameter::b=2_8 ! integer(4),parameter::n=3_4 +! integer(4),parameter::l=-3_4 +! real(4),parameter::e=3.333333432674407958984375e-1_4 ! real(4)::x(1_4:13_8) ! real(4)::y(1_8:8_4) ! type::t(c,d) ! integer(4),kind::c=1_4 ! integer(4),len::d=3_8 ! end type -! type(t(3_4,:)),allocatable::z +! type(t(4_4,:)),allocatable::z +! real(2)::f +! complex(16)::g !contains ! subroutine foo(x) ! real(4)::x(2_4:) diff --git a/flang/test/semantics/resolve37.f90 b/flang/test/semantics/resolve37.f90 new file mode 100644 index 0000000..e859454 --- /dev/null +++ b/flang/test/semantics/resolve37.f90 @@ -0,0 +1,32 @@ +! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. + +integer, parameter :: k = 8 +real, parameter :: l = 8.0 +integer :: n = 2 +!ERROR: expression must be constant +parameter(m=n) +integer(k) :: x +!ERROR: expression must be INTEGER +integer(l) :: y +!ERROR: expression must be constant +integer(n) :: z +type t(k) + integer, kind :: k +end type +!ERROR: expression must be INTEGER +type(t(.true.)) :: w +!ERROR: expression must be INTEGER +real :: w(l*2) +end -- 2.7.4