From: peter klausler Date: Tue, 19 Feb 2019 23:38:55 +0000 (-0800) Subject: [flang] Type checking on values in structure components X-Git-Tag: llvmorg-12-init~9537^2~1688 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=857da8cfe916ed4f44fe833825a4fc8015b494aa;p=platform%2Fupstream%2Fllvm.git [flang] Type checking on values in structure components Original-commit: flang-compiler/f18@bea98aeb9638b9d584488ae5faf72d53f1747a5f Reviewed-on: https://github.com/flang-compiler/f18/pull/311 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 5104ef9..637468c 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -43,15 +43,18 @@ template std::ostream &Convert::AsFortran(std::ostream &o) const { static_assert(TO::category == TypeCategory::Integer || TO::category == TypeCategory::Real || + TO::category == TypeCategory::Character || TO::category == TypeCategory::Logical || !"Convert<> to bad category!"); - if constexpr (TO::category == TypeCategory::Integer) { - o << "int"; + if constexpr (TO::category == TypeCategory::Character) { + this->left().AsFortran(o << "achar(iachar(") << ')'; + } else if constexpr (TO::category == TypeCategory::Integer) { + this->left().AsFortran(o << "int("); } else if constexpr (TO::category == TypeCategory::Real) { - o << "real"; - } else if constexpr (TO::category == TypeCategory::Logical) { - o << "logical"; + this->left().AsFortran(o << "real("); + } else { + this->left().AsFortran(o << "logical("); } - return this->left().AsFortran(o << '(') << ",kind=" << TO::kind << ')'; + return o << ",kind=" << TO::kind << ')'; } template std::ostream &Relational::Infix(std::ostream &o) const { @@ -160,6 +163,10 @@ Expr Expr>::LEN() const { }, [](const ArrayConstructor &a) { return a.LEN(); }, [](const Parentheses &x) { return x.left().LEN(); }, + [](const Convert &x) { + return std::visit( + [&](const auto &kx) { return kx.LEN(); }, x.left().u); + }, [](const Concat &c) { return c.left().LEN() + c.right().LEN(); }, diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 235fde2..3a626da 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -212,7 +212,7 @@ private: // Conversions to specific types from expressions of known category and // dynamic kind. -template +template struct Convert : public Operation, TO, SomeKind> { // Fortran doesn't have conversions between kinds of CHARACTER apart from // assignments, and in those the data must be convertible to/from 7-bit ASCII. @@ -221,6 +221,8 @@ struct Convert : public Operation, TO, SomeKind> { TO::category == TypeCategory::Real) && (FROMCAT == TypeCategory::Integer || FROMCAT == TypeCategory::Real)) || + (TO::category == TypeCategory::Character && + FROMCAT == TypeCategory::Character) || (TO::category == TypeCategory::Logical && FROMCAT == TypeCategory::Logical)); using Result = TO; @@ -572,7 +574,8 @@ public: Expr LEN() const; std::variant, ArrayConstructor, Designator, - FunctionRef, Parentheses, Concat, Extremum> + FunctionRef, Parentheses, Convert, Concat, + Extremum> u; }; @@ -641,8 +644,8 @@ public: explicit Expr(bool x) : u{Constant{x}} {} private: - using Operations = std::tuple, - Parentheses, Not, LogicalOperation>; + using Operations = std::tuple, Parentheses, Not, + LogicalOperation>; using Relations = std::conditional_t>, std::tuple<>>; using Others = std::tuple, ArrayConstructor, diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 1ca68e8..ca68247 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -366,6 +366,23 @@ Expr> FoldOperation( // Unary operations +template std::optional ConvertString(FROM &&s) { + if constexpr (std::is_same_v) { + return std::make_optional(std::move(s)); + } else { + // Fortran character conversion is well defined between distinct kinds + // only when the actual characters are valid 7-bit ASCII. + TO str; + for (auto iter{s.cbegin()}; iter != s.cend(); ++iter) { + if (static_cast(*iter) > 127) { + return std::nullopt; + } + str.push_back(*iter); + } + return std::make_optional(std::move(str)); + } +} + template Expr FoldOperation( FoldingContext &context, Convert &&convert) { @@ -383,7 +400,7 @@ Expr FoldOperation( "INTEGER(%d) to INTEGER(%d) conversion overflowed"_en_US, Operand::kind, TO::kind); } - return Expr{Constant{std::move(converted.value)}}; + return ScalarConstantToExpr(std::move(converted.value)); } else if constexpr (Operand::category == TypeCategory::Real) { auto converted{value->template ToInteger>()}; if (converted.flags.test(RealFlag::InvalidArgument)) { @@ -395,7 +412,7 @@ Expr FoldOperation( "REAL(%d) to INTEGER(%d) conversion overflowed"_en_US, Operand::kind, TO::kind); } - return Expr{Constant{std::move(converted.value)}}; + return ScalarConstantToExpr(std::move(converted.value)); } } else if constexpr (TO::category == TypeCategory::Real) { if constexpr (Operand::category == TypeCategory::Integer) { @@ -406,7 +423,7 @@ Expr FoldOperation( TO::kind); RealFlagWarnings(context, converted.flags, buffer); } - return Expr{Constant{std::move(converted.value)}}; + return ScalarConstantToExpr(std::move(converted.value)); } else if constexpr (Operand::category == TypeCategory::Real) { auto converted{Scalar::Convert(*value)}; if (!converted.flags.empty()) { @@ -417,11 +434,16 @@ Expr FoldOperation( if (context.flushSubnormalsToZero()) { converted.value = converted.value.FlushSubnormalToZero(); } - return Expr{Constant{std::move(converted.value)}}; + return ScalarConstantToExpr(std::move(converted.value)); + } + } else if constexpr (TO::category == TypeCategory::Character && + Operand::category == TypeCategory::Character) { + if (auto converted{ConvertString>(std::move(*value))}) { + return ScalarConstantToExpr(std::move(*converted)); } } else if constexpr (TO::category == TypeCategory::Logical && Operand::category == TypeCategory::Logical) { - return Expr{Constant{value->IsTrue()}}; + return Expr{value->IsTrue()}; } } return Expr{std::move(convert)}; diff --git a/flang/lib/evaluate/tools.cc b/flang/lib/evaluate/tools.cc index abb2061..4d93f23 100644 --- a/flang/lib/evaluate/tools.cc +++ b/flang/lib/evaluate/tools.cc @@ -522,12 +522,9 @@ std::optional> ConvertToType( case TypeCategory::Complex: return ConvertToNumeric(type.kind, std::move(x)); case TypeCategory::Character: - if (auto fromType{x.GetType()}) { - if (fromType->category == TypeCategory::Character && - fromType->kind == type.kind) { - // TODO pmk: adjusting CHARACTER length via conversion - return std::move(x); - } + if (auto *cx{UnwrapExpr>(x)}) { + return Expr{ + ConvertToKind(type.kind, std::move(*cx))}; } break; case TypeCategory::Logical: @@ -538,7 +535,7 @@ std::optional> ConvertToType( break; case TypeCategory::Derived: if (auto fromType{x.GetType()}) { - if (type == fromType) { + if (type == *fromType) { return std::move(x); } } @@ -549,6 +546,20 @@ std::optional> ConvertToType( } std::optional> ConvertToType( + const semantics::Symbol &symbol, Expr &&x) { + if (int xRank{x.Rank()}; xRank > 0) { + if (symbol.Rank() != xRank) { + return std::nullopt; + } + } + if (auto symType{GetSymbolType(symbol)}) { + // TODO pmk CHARACTER length + return ConvertToType(*symType, std::move(x)); + } + return std::nullopt; +} + +std::optional> ConvertToType( const DynamicType &type, std::optional> &&x) { if (x.has_value()) { return ConvertToType(type, std::move(*x)); diff --git a/flang/lib/evaluate/tools.h b/flang/lib/evaluate/tools.h index 2aa4718..4f9b99e 100644 --- a/flang/lib/evaluate/tools.h +++ b/flang/lib/evaluate/tools.h @@ -227,6 +227,8 @@ std::optional> ConvertToType( const DynamicType &, Expr &&); std::optional> ConvertToType( const DynamicType &, std::optional> &&); +std::optional> ConvertToType( + const semantics::Symbol &, Expr &&); // Conversions to the type of another expression template @@ -339,7 +341,7 @@ template Expr> ScalarConstantToExpr(const A &x) { using Ty = TypeOf; static_assert( std::is_same_v, std::decay_t> || !"TypeOf<> is broken"); - return {Constant{x}}; + return Expr>{Constant{x}}; } // Combine two expressions of the same specific numeric type with an operation diff --git a/flang/lib/evaluate/type.cc b/flang/lib/evaluate/type.cc index 0d71b34..6e92cfc 100644 --- a/flang/lib/evaluate/type.cc +++ b/flang/lib/evaluate/type.cc @@ -89,9 +89,14 @@ bool IsDescriptor(const Symbol &symbol) { namespace Fortran::evaluate { +template bool PointeeComparison(const A *x, const A *y) { + return x == y || (x != nullptr && y != nullptr && *x == *y); +} + bool DynamicType::operator==(const DynamicType &that) const { return category == that.category && kind == that.kind && - charLength == that.charLength && derived == that.derived; + PointeeComparison(charLength, that.charLength) && + PointeeComparison(derived, that.derived); } std::optional GetSymbolType(const semantics::Symbol *symbol) { @@ -117,6 +122,14 @@ std::optional GetSymbolType(const semantics::Symbol *symbol) { return std::nullopt; } +std::optional GetSymbolType(const semantics::Symbol *symbol) { + if (symbol != nullptr) { + return GetSymbolType(*symbol); + } else { + return std::nullopt; + } +} + std::string DynamicType::AsFortran() const { if (derived != nullptr) { CHECK(category == TypeCategory::Derived); @@ -191,7 +204,7 @@ DynamicType DynamicType::ResultTypeForMultiply(const DynamicType &that) const { bool SomeKind::operator==( const SomeKind &that) const { - return spec_ == that.spec_; + return PointeeComparison(spec_, that.spec_); } std::string SomeDerived::AsFortran() const { diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index fa83538..0ea3344 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -84,6 +84,7 @@ struct DynamicType { // Result will be missing when a symbol is absent or // has an erroneous type, e.g., REAL(KIND=666). +std::optional GetSymbolType(const semantics::Symbol &); std::optional GetSymbolType(const semantics::Symbol *); template struct TypeBase { diff --git a/flang/lib/evaluate/variable.cc b/flang/lib/evaluate/variable.cc index 779998b..a931f5b 100644 --- a/flang/lib/evaluate/variable.cc +++ b/flang/lib/evaluate/variable.cc @@ -638,10 +638,8 @@ template const Symbol *Designator::GetLastSymbol() const { template std::optional Designator::GetType() const { if constexpr (IsLengthlessIntrinsicType) { return {Result::GetType()}; - } else if (const Symbol * symbol{GetLastSymbol()}) { - return GetSymbolType(symbol); } else { - return std::nullopt; + return GetSymbolType(GetLastSymbol()); } } diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index b6b4654..666d089 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -325,11 +325,10 @@ MaybeExpr TypedWrapper(const DynamicType &dyType, WRAPPED &&x) { } // Wraps a data reference in a typed Designator<>. -static MaybeExpr Designate(DataRef &&dataRef) { - const Symbol &symbol{dataRef.GetLastSymbol()}; - if (std::optional dyType{GetSymbolType(&symbol)}) { +static MaybeExpr Designate(DataRef &&ref) { + if (std::optional dyType{GetSymbolType(ref.GetLastSymbol())}) { return TypedWrapper( - std::move(*dyType), std::move(dataRef)); + std::move(*dyType), std::move(ref)); } // TODO: graceful errors on CLASS(*) and TYPE(*) misusage return std::nullopt; @@ -339,8 +338,7 @@ static MaybeExpr Designate(DataRef &&dataRef) { // that looks like a 1-D array element or section. static MaybeExpr ResolveAmbiguousSubstring( ExpressionAnalysisContext &context, ArrayRef &&ref) { - const Symbol &symbol{ref.GetLastSymbol()}; - if (std::optional dyType{GetSymbolType(&symbol)}) { + if (std::optional dyType{GetSymbolType(ref.GetLastSymbol())}) { if (dyType->category == TypeCategory::Character && ref.size() == 1) { DataRef base{std::visit([](auto &&y) { return DataRef{std::move(y)}; }, std::move(ref.base()))}; @@ -855,7 +853,7 @@ static MaybeExpr AnalyzeExpr( std::optional> last{ GetSubstringBound(context, std::get<1>(range.t))}; const Symbol &symbol{checked->GetLastSymbol()}; - if (std::optional dynamicType{GetSymbolType(&symbol)}) { + if (std::optional dynamicType{GetSymbolType(symbol)}) { if (dynamicType->category == TypeCategory::Character) { return WrapperHelper(dynamicType->kind, @@ -1041,7 +1039,7 @@ static MaybeExpr AnalyzeExpr( } if (sym->detailsIf()) { if (auto *designator{UnwrapExpr>(*dtExpr)}) { - if (std::optional dyType{GetSymbolType(sym)}) { + if (std::optional dyType{GetSymbolType(*sym)}) { if (dyType->category == TypeCategory::Integer) { return AsMaybeExpr( common::SearchTypes(TypeParamInquiryVisitor{dyType->kind, @@ -1443,15 +1441,19 @@ static MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &context, if (symbol != nullptr) { if (symbol->has()) { context.Say(source, - "Type parameter '%s' cannot be a component of this structure constructor"_err_en_US, + "Type parameter '%s' cannot be a component of this structure " + "constructor"_err_en_US, symbol->name().ToString().data()); - } else if (checkConflicts) { + continue; + } + if (checkConflicts) { auto componentIter{ std::find(components.begin(), components.end(), symbol)}; if (unavailable.find(symbol->name()) != unavailable.cend()) { // C797, C798 context.Say(source, - "Component '%s' conflicts with another component earlier in this structure constructor"_err_en_US, + "Component '%s' conflicts with another component earlier in " + "this structure constructor"_err_en_US, symbol->name().ToString().data()); } else if (symbol->test(Symbol::Flag::ParentComp)) { // Make earlier components unavailable once a whole parent appears. @@ -1472,7 +1474,14 @@ static MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &context, if (MaybeExpr value{AnalyzeExpr(context, expr)}) { // TODO pmk: C7104, C7105 check that pointer components are // being initialized with data/procedure designators appropriately - result.Add(*symbol, std::move(*value)); + if (MaybeExpr converted{ConvertToType(*symbol, std::move(*value))}) { + result.Add(*symbol, std::move(*converted)); + } else { + if (auto *msg{context.Say(expr.source, + "Structure constructor value is incompatible with component"_err_en_US)}) { + msg->Attach(symbol->name(), "Component declaration"_en_US); + } + } } } } @@ -1488,7 +1497,8 @@ static MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &context, result.Add(*symbol, common::Clone(*details->init())); } else { // C799 if (auto *msg{context.Say(typeName, - "Structure constructor lacks a value for component '%s'"_err_en_US, + "Structure constructor lacks a value for " + "component '%s'"_err_en_US, symbol->name().ToString().data())}) { msg->Attach(symbol->name(), "Absent component"_en_US); } diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 27a5f16..0340a06 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -3291,6 +3291,7 @@ void DeclarationVisitor::Post(const parser::AllocateStmt &) { bool DeclarationVisitor::Pre(const parser::StructureConstructor &x) { auto &parsedType{std::get(x.t)}; const DeclTypeSpec *type{ProcessTypeSpec(parsedType)}; + if (type == nullptr) { return false; } diff --git a/flang/lib/semantics/scope.cc b/flang/lib/semantics/scope.cc index 9be1c55..4ad0e3e6 100644 --- a/flang/lib/semantics/scope.cc +++ b/flang/lib/semantics/scope.cc @@ -120,14 +120,6 @@ const DeclTypeSpec &Scope::MakeDerivedType( return MakeDerivedType(std::move(spec), category); } -const DeclTypeSpec &Scope::MakeDerivedType(DeclTypeSpec::Category category, - DerivedTypeSpec &&instance, SemanticsContext &semanticsContext) { - DeclTypeSpec &type{declTypeSpecs_.emplace_back( - category, DerivedTypeSpec{std::move(instance)})}; - type.derivedTypeSpec().Instantiate(*this, semanticsContext); - return type; -} - DeclTypeSpec &Scope::MakeDerivedType(const Symbol &typeSymbol) { CHECK(typeSymbol.has()); CHECK(typeSymbol.scope() != nullptr); @@ -250,7 +242,10 @@ const DeclTypeSpec *Scope::FindInstantiatedDerivedType( if (typeIter != declTypeSpecs_.end()) { return &*typeIter; } - return nullptr; + if (&parent_ == this) { + return nullptr; + } + return parent_.FindInstantiatedDerivedType(spec, category); } const DeclTypeSpec &Scope::FindOrInstantiateDerivedType(DerivedTypeSpec &&spec, diff --git a/flang/lib/semantics/scope.h b/flang/lib/semantics/scope.h index a04c9b2..cb107df 100644 --- a/flang/lib/semantics/scope.h +++ b/flang/lib/semantics/scope.h @@ -144,8 +144,6 @@ public: ParamValue &&length, KindExpr &&kind = KindExpr{0}); const DeclTypeSpec &MakeDerivedType( DeclTypeSpec::Category, DerivedTypeSpec &&); - const DeclTypeSpec &MakeDerivedType( - DeclTypeSpec::Category, DerivedTypeSpec &&, SemanticsContext &); DeclTypeSpec &MakeDerivedType(const Symbol &); DeclTypeSpec &MakeDerivedType(DerivedTypeSpec &&, DeclTypeSpec::Category); const DeclTypeSpec &MakeTypeStarType(); diff --git a/flang/lib/semantics/type.cc b/flang/lib/semantics/type.cc index 1bcbe9d..808674b 100644 --- a/flang/lib/semantics/type.cc +++ b/flang/lib/semantics/type.cc @@ -42,10 +42,6 @@ void DerivedTypeSpec::set_scope(const Scope &scope) { scope_ = &scope; } -bool DerivedTypeSpec::operator==(const DerivedTypeSpec &that) const { - return &typeSymbol_ == &that.typeSymbol_ && parameters_ == that.parameters_; -} - ParamValue &DerivedTypeSpec::AddParamValue( SourceName name, ParamValue &&value) { auto pair{parameters_.insert(std::make_pair(name, std::move(value)))}; @@ -227,10 +223,6 @@ void ParamValue::SetExplicit(SomeIntExpr &&x) { expr_ = std::move(x); } -bool ParamValue::operator==(const ParamValue &that) const { - return category_ == that.category_ && expr_ == that.expr_; -} - std::ostream &operator<<(std::ostream &o, const ParamValue &x) { if (x.isAssumed()) { o << '*'; diff --git a/flang/lib/semantics/type.h b/flang/lib/semantics/type.h index 2ded0c4..20bd3a3 100644 --- a/flang/lib/semantics/type.h +++ b/flang/lib/semantics/type.h @@ -101,7 +101,9 @@ public: bool isDeferred() const { return category_ == Category::Deferred; } const MaybeIntExpr &GetExplicit() const { return expr_; } void SetExplicit(SomeIntExpr &&); - bool operator==(const ParamValue &) const; + bool operator==(const ParamValue &that) const { + return category_ == that.category_ && expr_ == that.expr_; + } private: enum class Category { Explicit, Deferred, Assumed }; @@ -240,7 +242,9 @@ public: } void FoldParameterExpressions(evaluate::FoldingContext &); void Instantiate(Scope &, SemanticsContext &); - bool operator==(const DerivedTypeSpec &) const; // for std::find() + bool operator==(const DerivedTypeSpec &that) const { + return &typeSymbol_ == &that.typeSymbol_ && parameters_ == that.parameters_; + } private: const Symbol &typeSymbol_;