From 6c6234be9eedbb5bfa50fbc4679523a4f830ae4a Mon Sep 17 00:00:00 2001 From: peter klausler Date: Wed, 12 Sep 2018 11:20:30 -0700 Subject: [PATCH] [flang] clean up for review Original-commit: flang-compiler/f18@d3d81b1e6fdc394b8ba9607ce15f39988a3b8e23 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false --- flang/lib/evaluate/expression.cc | 4 +- flang/lib/evaluate/expression.h | 7 +- flang/lib/evaluate/type.h | 15 +- flang/lib/parser/grammar.h | 7 +- flang/lib/parser/parse-tree.h | 7 - flang/lib/semantics/expression.cc | 317 +++++++++++++++----------- flang/lib/semantics/expression.h | 13 +- flang/lib/semantics/resolve-labels.cc | 2 +- flang/tools/f18/f18.cc | 5 +- 9 files changed, 210 insertions(+), 167 deletions(-) diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index a40027e6e2b2..977e7494e680 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -543,7 +543,7 @@ auto ExpressionBase::ScalarValue() const Expr::~Expr() {} // Template instantiations to resolve the "extern template" declarations -// in expression.h. +// that appear in expression.h. template class Expr>; template class Expr>; @@ -605,6 +605,8 @@ template struct ExpressionBase>; template struct ExpressionBase>; template struct ExpressionBase>; template struct ExpressionBase>; +template struct ExpressionBase>; +template struct ExpressionBase>; template struct ExpressionBase>; template struct ExpressionBase>; template struct ExpressionBase>; diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index b7f51ca3d3d3..30cc75b8211c 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -17,8 +17,9 @@ // Represent Fortran expressions in a type-safe manner. // Expressions are the sole owners of their constituents; i.e., there is no -// context-independent hash table or sharing of common subexpressions. -// Both deep copy and move semantics are supported for expression construction. +// context-independent hash table or sharing of common subexpressions, and +// thus these are trees, not DAGs. Both deep copy and move semantics are +// supported for expression construction. #include "common.h" #include "type.h" @@ -721,6 +722,8 @@ extern template struct ExpressionBase>; extern template struct ExpressionBase>; extern template struct ExpressionBase>; extern template struct ExpressionBase>; +extern template struct ExpressionBase>; +extern template struct ExpressionBase>; extern template struct ExpressionBase>; extern template struct ExpressionBase>; extern template struct ExpressionBase>; diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 4e784d9605a7..de34d1e2676e 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -18,7 +18,9 @@ // These definitions map Fortran's intrinsic types, characterized by byte // sizes encoded in KIND type parameter values, to their value representation // types in the evaluation library, which are parameterized in terms of -// total bit width and real precision. +// total bit width and real precision. Instances of these class templates +// are suitable for use as template parameters to instantiate other class +// templates, like expressions, over the supported types and kinds. #include "complex.h" #include "integer.h" @@ -37,7 +39,7 @@ namespace Fortran::evaluate { using common::TypeCategory; // Specific intrinsic types are represented by specializations of -// the class template Type. +// this class template Type. template struct Type; template struct TypeBase { @@ -127,8 +129,8 @@ using SameKind = Type::kind>; // Default REAL just simply has to be IEEE-754 single precision today. // It occupies one numeric storage unit by definition. The default INTEGER // and default LOGICAL intrinsic types also have to occupy one numeric -// storage unit, so their kinds are also forced. Default COMPLEX occupies -// two numeric storage units. +// storage unit, so their kinds are also forced. Default COMPLEX must always +// comprise two default REAL components. // TODO: Support compile-time options to default reals, ints, or both to KIND=8 using DefaultReal = Type; @@ -143,8 +145,9 @@ using SubscriptInteger = Type; using LogicalResult = Type; using LargestReal = Type; -// For an intrinsic type category CAT, CategoryTypes is an instantiation -// of std::tuple> over each supported kind K in that category. +// For each intrinsic type category CAT, CategoryTypes is an instantiation +// of std::tuple> that comprises every kind value K in that +// category that could possibly be supported on any target. template using CategoryTypesTuple = std::tuple...>; diff --git a/flang/lib/parser/grammar.h b/flang/lib/parser/grammar.h index f2b4c4d56145..89686f538f74 100644 --- a/flang/lib/parser/grammar.h +++ b/flang/lib/parser/grammar.h @@ -1496,10 +1496,6 @@ constexpr auto complexPartDesignator{construct(dataRef)}; // Type parameter inquiries are initially recognized as structure components. TYPE_PARSER(construct(structureComponent)) -// R918 array-section -> -// data-ref [( substring-range )] | complex-part-designator -constexpr auto arraySection{construct(designator)}; - // R919 subscript -> scalar-int-expr constexpr auto subscript{scalarIntExpr}; @@ -3480,6 +3476,9 @@ TYPE_CONTEXT_PARSER("PAUSE statement"_en_US, // is used only via scalar-default-char-variable // R907 int-variable -> variable // is used only via scalar-int-variable +// R918 array-section -> +// data-ref [( substring-range )] | complex-part-designator +// is not used because parsing is not sensitive to rank // R1030 default-char-constant-expr -> default-char-expr // is only used via scalar-default-char-constant-expr } // namespace Fortran::parser diff --git a/flang/lib/parser/parse-tree.h b/flang/lib/parser/parse-tree.h index 8a5b14947147..35b393b04aaa 100644 --- a/flang/lib/parser/parse-tree.h +++ b/flang/lib/parser/parse-tree.h @@ -1823,13 +1823,6 @@ struct ArrayElement { std::list subscripts; }; -// R918 array-section -> -// data-ref [( substring-range )] | complex-part-designator -struct ArraySection { - WRAPPER_CLASS_BOILERPLATE(ArraySection, Designator); - // at least one vector-valued or triplet subscript -}; - // R933 allocate-object -> variable-name | structure-component struct AllocateObject { UNION_CLASS_BOILERPLATE(AllocateObject); diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 5d4eb5041f83..416f45a4f4f1 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -13,7 +13,7 @@ // limitations under the License. #include "expression.h" -#include "dump-parse-tree.h" // TODO pmk temporary +#include "dump-parse-tree.h" // TODO temporary #include "symbol.h" #include "../common/idioms.h" #include "../evaluate/common.h" @@ -21,17 +21,22 @@ #include "../parser/parse-tree-visitor.h" #include "../parser/parse-tree.h" #include +#include // TODO remove soon #include using namespace Fortran::parser::literals; +// Much of the code that implements semantic analysis of expressions is +// tightly coupled with their typed representations in lib/evaluate, +// and appears here in namespace Fortran::evaluate for convenience. namespace Fortran::evaluate { using common::TypeCategory; using MaybeExpr = std::optional>; -// A utility subroutine to repackage optional values as MaybeExpr values. +// A utility subroutine to repackage optional expressions of various levels +// of type specificity as fully general MaybeExpr values. template MaybeExpr AsMaybeExpr(std::optional &&x) { if (x.has_value()) { return {AsGenericExpr(AsCategoryExpr(AsExpr(std::move(*x))))}; @@ -55,19 +60,14 @@ MaybeExpr AsMaybeExpr(std::optional>> &&x) { return std::nullopt; } -// This local class wraps some state and a highly overloaded -// Analyze() member function that converts parse trees into generic +// This local class wraps some state and a highly overloaded Analyze() +// member function that converts parse trees into (usually) generic // expressions. struct ExprAnalyzer { - using MaybeIntExpr = std::optional>; - ExprAnalyzer( FoldingContext &ctx, const semantics::IntrinsicTypeDefaultKinds &dfts) : context{ctx}, defaults{dfts} {} - int Analyze( - const std::optional &, int defaultKind, int kanjiKind); - MaybeExpr Analyze(const parser::Expr &); MaybeExpr Analyze(const parser::CharLiteralConstantSubstring &); MaybeExpr Analyze(const parser::LiteralConstant &); @@ -78,14 +78,23 @@ struct ExprAnalyzer { MaybeExpr Analyze(const parser::ComplexLiteralConstant &); MaybeExpr Analyze(const parser::CharLiteralConstant &); MaybeExpr Analyze(const parser::LogicalLiteralConstant &); + MaybeExpr Analyze(const parser::HollerithLiteralConstant &); + MaybeExpr Analyze(const parser::BOZLiteralConstant &); MaybeExpr Analyze(const parser::Name &); + MaybeExpr Analyze(const parser::NamedConstant &); MaybeExpr Analyze(const parser::Substring &); MaybeExpr Analyze(const parser::ArrayElement &); MaybeExpr Analyze(const parser::StructureComponent &); + MaybeExpr Analyze(const parser::TypeParamInquiry &); MaybeExpr Analyze(const parser::CoindexedNamedObject &); MaybeExpr Analyze(const parser::ComplexPart &); - MaybeExpr Analyze(const parser::AcSpec &); + MaybeExpr Analyze(const parser::ArrayConstructor &); MaybeExpr Analyze(const parser::StructureConstructor &); + MaybeExpr Analyze(const parser::Expr::Parentheses &); + MaybeExpr Analyze(const parser::Expr::UnaryPlus &); + MaybeExpr Analyze(const parser::Expr::Negate &); + MaybeExpr Analyze(const parser::Expr::NOT &); + MaybeExpr Analyze(const parser::Expr::PercentLoc &); MaybeExpr Analyze(const parser::Expr::DefinedUnary &); MaybeExpr Analyze(const parser::Expr::Power &); MaybeExpr Analyze(const parser::Expr::Multiply &); @@ -106,13 +115,18 @@ struct ExprAnalyzer { MaybeExpr Analyze(const parser::Expr::XOR &); MaybeExpr Analyze(const parser::Expr::ComplexConstructor &); MaybeExpr Analyze(const parser::Expr::DefinedBinary &); - MaybeExpr Analyze(const parser::Call &); + MaybeExpr Analyze(const parser::FunctionReference &); + + // Kind parameter analysis always returns a valid kind value. + int Analyze( + const std::optional &, int defaultKind, int kanjiKind); + + std::optional Analyze(const parser::SectionSubscript &); + std::vector Analyze(const std::list &); std::optional> AsSubscript(MaybeExpr &&); std::optional> TripletPart( const std::optional &); - std::optional Analyze(const parser::SectionSubscript &); - std::vector Analyze(const std::list &); FoldingContext &context; const semantics::IntrinsicTypeDefaultKinds &defaults; @@ -120,13 +134,11 @@ struct ExprAnalyzer { // This helper template function handles the Scalar<>, Integer<>, and // Constant<> wrappers in the parse tree, as well as default behavior -// for wrappers and unions. -// (C++ doesn't allow template specialization in a class, so this helper -// template function must be outside ExprAnalyzer and reflect back into it.) +// for unions. (C++ doesn't allow template specialization in +// a class, so this helper template function must be outside ExprAnalyzer +// and reflect back into it.) template MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const A &x) { - if constexpr (WrapperTrait) { - return AnalyzeHelper(ea, x.v); - } else if constexpr (UnionTrait) { + if constexpr (UnionTrait) { return AnalyzeHelper(ea, x.u); } else { return ea.Analyze(x); @@ -171,97 +183,8 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const common::Indirection &x) { return AnalyzeHelper(ea, *x); } -template<> -MaybeExpr AnalyzeHelper( - ExprAnalyzer &ea, const parser::HollerithLiteralConstant &x) { - return common::SearchDynamicTypes( - TypeKindVisitor{ - ea.defaults.defaultCharacterKind, x.v}); -} - -template<> -MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::BOZLiteralConstant &x) { - const char *p{x.v.data()}; - std::uint64_t base{16}; - switch (*p++) { - case 'b': base = 2; break; - case 'o': base = 8; break; - case 'z': break; - case 'x': break; - default: CRASH_NO_CASE; - } - CHECK(*p == '"'); - auto value{BOZLiteralConstant::ReadUnsigned(++p, base)}; - if (*p != '"') { - ea.context.messages.Say( - "invalid digit ('%c') in BOZ literal %s"_err_en_US, *p, x.v.data()); - return std::nullopt; - } - if (value.overflow) { - ea.context.messages.Say("BOZ literal %s too large"_err_en_US, x.v.data()); - return std::nullopt; - } - return {AsGenericExpr(value.value)}; -} - -template<> -MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::Parentheses &x) { - if (MaybeExpr operand{AnalyzeHelper(ea, *x.v)}) { - return std::visit( - common::visitors{ - [&](BOZLiteralConstant &&boz) { - return operand; // ignore parentheses around typeless - }, - [](auto &&catExpr) { - return std::visit( - [](auto &&expr) -> MaybeExpr { - using Ty = ResultType; - if constexpr (common::HasMember, - decltype(expr.u)>) { - return {AsGenericExpr( - AsExpr(Parentheses{std::move(expr)}))}; - } - // TODO: support Parentheses in all Expr specializations - return std::nullopt; - }, - std::move(catExpr.u)); - }}, - std::move(operand->u)); - } - return std::nullopt; -} - -template<> -MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::Negate &x) { - if (MaybeExpr operand{AnalyzeHelper(ea, *x.v)}) { - return Negation(ea.context.messages, std::move(operand->u)); - } - return std::nullopt; -} - -template<> -MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::NOT &x) { - if (MaybeExpr operand{AnalyzeHelper(ea, *x.v)}) { - return std::visit(common::visitors{[](Expr &&lx) -> MaybeExpr { - return {AsGenericExpr( - LogicalNegation(std::move(lx)))}; - }, - [=](auto &&) -> MaybeExpr { - // TODO pmk: INTEGER operand for bitwise extension? - ea.context.messages.Say( - "Operand of .NOT. must be LOGICAL"_err_en_US); - return std::nullopt; - }}, - std::move(operand->u)); - } - return std::nullopt; -} - -template<> -MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::PercentLoc &) { - ea.context.messages.Say("TODO: %LOC unimplemented\n"_err_en_US); - return std::nullopt; -} +// Implementations of ExprAnalyzer::Analyze follow for various parse tree +// node types. MaybeExpr ExprAnalyzer::Analyze(const parser::Expr &x) { return AnalyzeHelper(*this, x); @@ -311,7 +234,7 @@ MaybeExpr IntLiteralConstant(ExprAnalyzer &ea, const PARSED &x) { TypeKindVisitor{ kind, static_cast(value)})}; if (!result.has_value()) { - ea.context.messages.Say("unsupported INTEGER(KIND=%u)"_err_en_US, kind); + ea.context.messages.Say("unsupported INTEGER(KIND=%d)"_err_en_US, kind); } return result; } @@ -393,7 +316,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::RealLiteralConstant &x) { auto result{common::SearchDynamicTypes( RealTypeVisitor{kind, x.real.source, context})}; if (!result.has_value()) { - ctxMsgs.Say("unsupported REAL(KIND=%u)"_err_en_US, kind); + ctxMsgs.Say("unsupported REAL(KIND=%d)"_err_en_US, kind); } return AsMaybeExpr(std::move(result)); } @@ -426,7 +349,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstant &x) { TypeKindVisitor{ kind, std::move(value)})}; if (!result.has_value()) { - context.messages.Say("unsupported CHARACTER(KIND=%u)"_err_en_US, kind); + context.messages.Say("unsupported CHARACTER(KIND=%d)"_err_en_US, kind); } return result; } @@ -439,11 +362,41 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) { TypeKindVisitor{ kind, std::move(value)})}; if (!result.has_value()) { - context.messages.Say("unsupported LOGICAL(KIND=%u)"_err_en_US, kind); + context.messages.Say("unsupported LOGICAL(KIND=%d)"_err_en_US, kind); } return result; } +MaybeExpr ExprAnalyzer::Analyze(const parser::HollerithLiteralConstant &x) { + return common::SearchDynamicTypes( + TypeKindVisitor{ + defaults.defaultCharacterKind, x.v}); +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::BOZLiteralConstant &x) { + const char *p{x.v.data()}; + std::uint64_t base{16}; + switch (*p++) { + case 'b': base = 2; break; + case 'o': base = 8; break; + case 'z': break; + case 'x': break; + default: CRASH_NO_CASE; + } + CHECK(*p == '"'); + auto value{BOZLiteralConstant::ReadUnsigned(++p, base)}; + if (*p != '"') { + context.messages.Say( + "invalid digit ('%c') in BOZ literal %s"_err_en_US, *p, x.v.data()); + return std::nullopt; + } + if (value.overflow) { + context.messages.Say("BOZ literal %s too large"_err_en_US, x.v.data()); + return std::nullopt; + } + return {AsGenericExpr(value.value)}; +} + template MaybeExpr DataRefIfType( const semantics::Symbol &symbol, int defaultKind, DataRef &&dataRef) { @@ -511,7 +464,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) { if (n.symbol == nullptr) { // TODO: convert this to a CHECK later context.messages.Say( - "TODO: name (%s) is not resolved to an object"_err_en_US, + "TODO: name '%s' is not resolved to an object"_err_en_US, n.ToString().data()); } else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) { context.messages.Say( @@ -522,12 +475,23 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) { TypedDataRef(*n.symbol, defaults, DataRef{*n.symbol})}) { return result; } - context.messages.Say("%s is not of a supported type and kind"_err_en_US, + context.messages.Say("'%s' is not of a supported type and kind"_err_en_US, n.ToString().data()); } return std::nullopt; } +MaybeExpr ExprAnalyzer::Analyze(const parser::NamedConstant &n) { + if (MaybeExpr value{Analyze(n.v)}) { + if (std::optional> folded{value->Fold(context)}) { + return {AsGenericExpr(std::move(*folded))}; + } + context.messages.Say( + "'%s' must be a constant"_err_en_US, n.v.ToString().data()); + } + return std::nullopt; +} + MaybeExpr ExprAnalyzer::Analyze(const parser::Substring &ss) { context.messages.Say("TODO: Substring unimplemented\n"_err_en_US); return std::nullopt; @@ -604,7 +568,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayElement &ae) { } else if (const auto *component{ std::get_if>( &ae.base.u)}) { - // pmk continue + // pmk continue development here } else { CHECK(!"parser::ArrayRef base DataRef is neither Name nor " "StructureComponent"); @@ -613,38 +577,117 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayElement &ae) { } MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) { - context.messages.Say("pmk: StructureComponent unimplemented\n"_err_en_US); + context.messages.Say("TODO: StructureComponent unimplemented\n"_err_en_US); + return std::nullopt; +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::TypeParamInquiry &tpi) { + context.messages.Say("TODO: TypeParamInquiry unimplemented\n"_err_en_US); return std::nullopt; } MaybeExpr ExprAnalyzer::Analyze(const parser::CoindexedNamedObject &co) { - context.messages.Say("pmk: CoindexedNamedObject unimplemented\n"_err_en_US); + context.messages.Say("TODO: CoindexedNamedObject unimplemented\n"_err_en_US); return std::nullopt; } MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstantSubstring &) { context.messages.Say( - "pmk: CharLiteralConstantSubstring unimplemented\n"_err_en_US); + "TODO: CharLiteralConstantSubstring unimplemented\n"_err_en_US); return std::nullopt; } -MaybeExpr ExprAnalyzer::Analyze(const parser::AcSpec &) { - context.messages.Say("pmk: AcSpec unimplemented\n"_err_en_US); +MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayConstructor &) { + context.messages.Say("TODO: ArrayConstructor unimplemented\n"_err_en_US); return std::nullopt; } MaybeExpr ExprAnalyzer::Analyze(const parser::StructureConstructor &) { - context.messages.Say("pmk: StructureConstructor unimplemented\n"_err_en_US); + context.messages.Say("TODO: StructureConstructor unimplemented\n"_err_en_US); return std::nullopt; } -MaybeExpr ExprAnalyzer::Analyze(const parser::Call &) { - context.messages.Say("pmk: Call unimplemented\n"_err_en_US); +MaybeExpr ExprAnalyzer::Analyze(const parser::FunctionReference &) { + context.messages.Say("TODO: FunctionReference unimplemented\n"_err_en_US); + return std::nullopt; +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Parentheses &x) { + if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) { + return std::visit( + common::visitors{ + [&](BOZLiteralConstant &&boz) { + return operand; // ignore parentheses around typeless + }, + [](auto &&catExpr) { + return std::visit( + [](auto &&expr) -> MaybeExpr { + using Ty = ResultType; + if constexpr (common::HasMember, + decltype(expr.u)>) { + return {AsGenericExpr( + AsExpr(Parentheses{std::move(expr)}))}; + } + // TODO: support Parentheses in all Expr specializations + return std::nullopt; + }, + std::move(catExpr.u)); + }}, + std::move(operand->u)); + } + return std::nullopt; +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) { + MaybeExpr value{AnalyzeHelper(*this, *x.v)}; + if (value.has_value()) { + std::visit( + common::visitors{ + [](const BOZLiteralConstant &) {}, // allow +Z'1', it's harmless + [&](const auto &catExpr) { + TypeCategory cat{ResultType::category}; + if (cat != TypeCategory::Integer && cat != TypeCategory::Real && + cat != TypeCategory::Complex) { + context.messages.Say( + "operand of unary + must be of a numeric type"_err_en_US); + } + }}, + value->u); + } + return value; +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Negate &x) { + if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) { + return Negation(context.messages, std::move(operand->u)); + } + return std::nullopt; +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::NOT &x) { + if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) { + return std::visit(common::visitors{[](Expr &&lx) -> MaybeExpr { + return {AsGenericExpr( + LogicalNegation(std::move(lx)))}; + }, + [=](auto &&) -> MaybeExpr { + // TODO: accept INTEGER operand if not overridden + context.messages.Say( + "Operand of .NOT. must be LOGICAL"_err_en_US); + return std::nullopt; + }}, + std::move(operand->u)); + } + return std::nullopt; +} + +MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::PercentLoc &) { + context.messages.Say("TODO: %LOC unimplemented\n"_err_en_US); return std::nullopt; } MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedUnary &) { - context.messages.Say("pmk: DefinedUnary unimplemented\n"_err_en_US); + context.messages.Say("TODO: DefinedUnary unimplemented\n"_err_en_US); return std::nullopt; } @@ -766,7 +809,8 @@ MaybeExpr LogicalHelper( BinaryLogicalOperation(opr, std::move(lx), std::move(ly)))}; }, [&](auto &&, auto &&) -> MaybeExpr { - // TODO pmk: extensions: INTEGER and typeless operands + // TODO: extension: INTEGER and typeless operands + // ifort and PGI accept them if not overridden ea.context.messages.Say( "operands to LOGICAL operation must be LOGICAL"_err_en_US); return {}; @@ -797,7 +841,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::XOR &x) { } MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedBinary &) { - context.messages.Say("pmk: DefinedBinary unimplemented\n"_err_en_US); + context.messages.Say("TODO: DefinedBinary unimplemented\n"_err_en_US); return std::nullopt; } @@ -805,7 +849,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedBinary &) { namespace Fortran::semantics { -MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context, +evaluate::MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context, const IntrinsicTypeDefaultKinds &defaults, const parser::Expr &expr) { return evaluate::ExprAnalyzer{context, defaults}.Analyze(expr); } @@ -813,8 +857,8 @@ MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context, class Mutator { public: Mutator(evaluate::FoldingContext &context, - const IntrinsicTypeDefaultKinds &defaults, std::ostream &o) - : context_{context}, defaults_{defaults}, out_{o} {} + const IntrinsicTypeDefaultKinds &defaults) + : context_{context}, defaults_{defaults} {} template bool Pre(A &) { return true /* visit children */; } template void Post(A &) {} @@ -822,12 +866,12 @@ public: bool Pre(parser::Expr &expr) { if (expr.typedExpr.get() == nullptr) { if (MaybeExpr checked{AnalyzeExpr(context_, defaults_, expr)}) { - checked->Dump(out_ << "pmk checked: ") << '\n'; + checked->Dump(std::cout << "checked expression: ") << '\n'; expr.typedExpr.reset( new evaluate::GenericExprWrapper{std::move(*checked)}); } else { - out_ << "pmk: expression analysis failed for an expression: "; - DumpTree(out_, expr); + std::cout << "expression analysis failed for this expression: "; + DumpTree(std::cout, expr); } } return false; @@ -836,13 +880,12 @@ public: private: evaluate::FoldingContext &context_; const IntrinsicTypeDefaultKinds &defaults_; - std::ostream &out_; }; void AnalyzeExpressions(parser::Program &program, evaluate::FoldingContext &context, - const IntrinsicTypeDefaultKinds &defaults, std::ostream &o) { - Mutator mutator{context, defaults, o}; + const IntrinsicTypeDefaultKinds &defaults) { + Mutator mutator{context, defaults}; parser::Walk(program, mutator); } diff --git a/flang/lib/semantics/expression.h b/flang/lib/semantics/expression.h index 9b18b7e8b940..ce9352897d5b 100644 --- a/flang/lib/semantics/expression.h +++ b/flang/lib/semantics/expression.h @@ -17,11 +17,8 @@ #include "../evaluate/expression.h" #include "../evaluate/type.h" -#include "../parser/message.h" #include "../parser/parse-tree.h" -#include #include -#include // TODO pmk namespace Fortran::semantics { @@ -36,11 +33,15 @@ struct IntrinsicTypeDefaultKinds { int defaultLogicalKind{evaluate::DefaultLogical::kind}; }; -MaybeExpr AnalyzeExpr(evaluate::FoldingContext &, - const IntrinsicTypeDefaultKinds &, const parser::Expr &); +// Semantic analysis of one expression. +std::optional> AnalyzeExpr( + evaluate::FoldingContext &, const IntrinsicTypeDefaultKinds &, + const parser::Expr &); +// Semantic analysis of all expressions in a parse tree, which is +// decorated with typed representations for top-level expressions. void AnalyzeExpressions(parser::Program &, evaluate::FoldingContext &, - const IntrinsicTypeDefaultKinds &, std::ostream &); + const IntrinsicTypeDefaultKinds &); } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_EXPRESSION_H_ diff --git a/flang/lib/semantics/resolve-labels.cc b/flang/lib/semantics/resolve-labels.cc index 54ee29e50c68..f17e4d2d1536 100644 --- a/flang/lib/semantics/resolve-labels.cc +++ b/flang/lib/semantics/resolve-labels.cc @@ -64,7 +64,7 @@ template constexpr Legality IsLegalDoTerm(const parser::Statement &) { if (std::is_same_v> || std::is_same_v) { - return Legality::always; + return Legality::always; } else { return Legality::never; } diff --git a/flang/tools/f18/f18.cc b/flang/tools/f18/f18.cc index 1a19f5e3a710..5c8ff4b31448 100644 --- a/flang/tools/f18/f18.cc +++ b/flang/tools/f18/f18.cc @@ -218,7 +218,7 @@ std::string CompileFortran( } Fortran::semantics::ResolveNames(Fortran::semantics::Scope::globalScope, parseTree, parsing.cooked(), directories); - const auto& Cook = parsing.cooked(); + const auto &Cook = parsing.cooked(); bool Pass = Fortran::semantics::ValidateLabels(parseTree, Cook); if (!Pass) { std::cerr << "Semantic error(s), aborting\n"; @@ -244,8 +244,7 @@ std::string CompileFortran( Fortran::parser::ContextualMessages contextualMessages{whole, &messages}; Fortran::evaluate::FoldingContext context{contextualMessages}; Fortran::semantics::IntrinsicTypeDefaultKinds defaults; - Fortran::semantics::AnalyzeExpressions( - parseTree, context, defaults, std::cout); + Fortran::semantics::AnalyzeExpressions(parseTree, context, defaults); messages.Emit(std::cerr, parsing.cooked()); if (!messages.empty() && (driver.warningsAreErrors || messages.AnyFatalError())) {