//===-- lib/Semantics/expression.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Semantics/expression.h" #include "check-call.h" #include "pointer-assignment.h" #include "resolve-names.h" #include "flang/Common/idioms.h" #include "flang/Evaluate/common.h" #include "flang/Evaluate/fold.h" #include "flang/Evaluate/tools.h" #include "flang/Parser/characters.h" #include "flang/Parser/dump-parse-tree.h" #include "flang/Parser/parse-tree-visitor.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/scope.h" #include "flang/Semantics/semantics.h" #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include // Typedef for optional generic expressions (ubiquitous in this file) using MaybeExpr = std::optional>; // 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::LanguageFeature; using common::NumericOperator; using common::TypeCategory; static inline std::string ToUpperCase(const std::string &str) { return parser::ToUpperCaseLetters(str); } struct DynamicTypeWithLength : public DynamicType { explicit DynamicTypeWithLength(const DynamicType &t) : DynamicType{t} {} std::optional> LEN() const; std::optional> length; }; std::optional> DynamicTypeWithLength::LEN() const { if (length) { return length; } if (auto *lengthParam{charLength()}) { if (const auto &len{lengthParam->GetExplicit()}) { return ConvertToType(common::Clone(*len)); } } return std::nullopt; // assumed or deferred length } static std::optional AnalyzeTypeSpec( const std::optional &spec) { if (spec) { if (const semantics::DeclTypeSpec * typeSpec{spec->declTypeSpec}) { // Name resolution sets TypeSpec::declTypeSpec only when it's valid // (viz., an intrinsic type with valid known kind or a non-polymorphic // & non-ABSTRACT derived type). if (const semantics::IntrinsicTypeSpec * intrinsic{typeSpec->AsIntrinsic()}) { TypeCategory category{intrinsic->category()}; if (auto optKind{ToInt64(intrinsic->kind())}) { int kind{static_cast(*optKind)}; if (category == TypeCategory::Character) { const semantics::CharacterTypeSpec &cts{ typeSpec->characterTypeSpec()}; const semantics::ParamValue &len{cts.length()}; // N.B. CHARACTER(LEN=*) is allowed in type-specs in ALLOCATE() & // type guards, but not in array constructors. return DynamicTypeWithLength{DynamicType{kind, len}}; } else { return DynamicTypeWithLength{DynamicType{category, kind}}; } } } else if (const semantics::DerivedTypeSpec * derived{typeSpec->AsDerived()}) { return DynamicTypeWithLength{DynamicType{*derived}}; } } } return std::nullopt; } // Wraps a object in an explicitly typed representation (e.g., Designator<> // or FunctionRef<>) that has been instantiated on a dynamically chosen type. template typename WRAPPER, typename WRAPPED> common::IfNoLvalue WrapperHelper(int kind, WRAPPED &&x) { return common::SearchTypes( TypeKindVisitor{kind, std::move(x)}); } template