[flang-commits] [flang] 83dca19 - [flang] Fix a crash when a BOZ literal is used as a relational operator

Pete Steinfeld via flang-commits flang-commits at lists.llvm.org
Thu Jul 23 09:14:40 PDT 2020


Author: Pete Steinfeld
Date: 2020-07-23T09:14:10-07:00
New Revision: 83dca19c11236700d26ebd1ecff65e01876c1e9d

URL: https://github.com/llvm/llvm-project/commit/83dca19c11236700d26ebd1ecff65e01876c1e9d
DIFF: https://github.com/llvm/llvm-project/commit/83dca19c11236700d26ebd1ecff65e01876c1e9d.diff

LOG: [flang] Fix a crash when a BOZ literal is used as a relational operator

Summary:
Expressions like `iVar==z'fe'` were causing an assertion error  because
the `Relate()` function in `Evaluate/tools.cpp` that processes
relational operators didn't deal with BOZ literals, which are typeless.
I fixed this by checking to see if the operands are BOZ literals.  If
so, if the other operand is REAL, I convert them to REAL.  Otherwise, I convert
them to integers with default kind.

I also added a test to resolve63.f90 that triggers the problem.

Reviewers: tskeith, DavidTruby

Subscribers: llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D83917

Added: 
    

Modified: 
    flang/lib/Semantics/expression.cpp
    flang/test/Semantics/resolve63.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 4cb43a91ef09..e78c2d20edcf 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -123,6 +123,7 @@ class ArgumentAnalyzer {
   }
   void Analyze(const parser::Variable &);
   void Analyze(const parser::ActualArgSpec &, bool isSubroutine);
+  void ConvertBOZ(std::size_t i, std::optional<DynamicType> otherType);
 
   bool IsIntrinsicRelational(RelationalOperator) const;
   bool IsIntrinsicLogical() const;
@@ -141,6 +142,7 @@ class ArgumentAnalyzer {
   // Find and return a user-defined assignment
   std::optional<ProcedureRef> TryDefinedAssignment();
   std::optional<ProcedureRef> GetDefinedAssignmentProc();
+  std::optional<DynamicType> GetType(std::size_t) const;
   void Dump(llvm::raw_ostream &);
 
 private:
@@ -153,7 +155,6 @@ class ArgumentAnalyzer {
   void AddAssignmentConversion(
       const DynamicType &lhsType, const DynamicType &rhsType);
   bool OkLogicalIntegerAssignment(TypeCategory lhs, TypeCategory rhs);
-  std::optional<DynamicType> GetType(std::size_t) const;
   int GetRank(std::size_t) const;
   bool IsBOZLiteral(std::size_t i) const {
     return std::holds_alternative<BOZLiteralConstant>(GetExpr(i).u);
@@ -2337,12 +2338,16 @@ MaybeExpr RelationHelper(ExpressionAnalyzer &context, RelationalOperator opr,
   analyzer.Analyze(std::get<1>(x.t));
   if (analyzer.fatalErrors()) {
     return std::nullopt;
-  } else if (analyzer.IsIntrinsicRelational(opr)) {
-    return AsMaybeExpr(Relate(context.GetContextualMessages(), opr,
-        analyzer.MoveExpr(0), analyzer.MoveExpr(1)));
   } else {
-    return analyzer.TryDefinedOp(opr,
-        "Operands of %s must have comparable types; have %s and %s"_err_en_US);
+    analyzer.ConvertBOZ(0, analyzer.GetType(1));
+    analyzer.ConvertBOZ(1, analyzer.GetType(0));
+    if (analyzer.IsIntrinsicRelational(opr)) {
+      return AsMaybeExpr(Relate(context.GetContextualMessages(), opr,
+          analyzer.MoveExpr(0), analyzer.MoveExpr(1)));
+    } else {
+      return analyzer.TryDefinedOp(opr,
+          "Operands of %s must have comparable types; have %s and %s"_err_en_US);
+    }
   }
 }
 
@@ -3014,6 +3019,29 @@ int ArgumentAnalyzer::GetRank(std::size_t i) const {
   return i < actuals_.size() ? actuals_[i].value().Rank() : 0;
 }
 
+// If the argument at index i is a BOZ literal, convert its type to match the
+// otherType.  It it's REAL convert to REAL, otherwise convert to INTEGER.
+// Note that IBM supports comparing BOZ literals to CHARACTER operands.  That
+// is not currently supported.
+void ArgumentAnalyzer::ConvertBOZ(
+    std::size_t i, std::optional<DynamicType> otherType) {
+  if (IsBOZLiteral(i)) {
+    Expr<SomeType> &&argExpr{MoveExpr(i)};
+    auto *boz{std::get_if<BOZLiteralConstant>(&argExpr.u)};
+    if (otherType && otherType->category() == TypeCategory::Real) {
+      MaybeExpr realExpr{ConvertToKind<TypeCategory::Real>(
+          context_.context().GetDefaultKind(TypeCategory::Real),
+          std::move(*boz))};
+      actuals_[i] = std::move(*realExpr);
+    } else {
+      MaybeExpr intExpr{ConvertToKind<TypeCategory::Integer>(
+          context_.context().GetDefaultKind(TypeCategory::Integer),
+          std::move(*boz))};
+      actuals_[i] = std::move(*intExpr);
+    }
+  }
+}
+
 // Report error resolving opr when there is a user-defined one available
 void ArgumentAnalyzer::SayNoMatch(const std::string &opr, bool isAssignment) {
   std::string type0{TypeAsFortran(0)};

diff  --git a/flang/test/Semantics/resolve63.f90 b/flang/test/Semantics/resolve63.f90
index 50e1fd0ebdbc..bd4e1d14e195 100644
--- a/flang/test/Semantics/resolve63.f90
+++ b/flang/test/Semantics/resolve63.f90
@@ -44,12 +44,32 @@ logical function not_r(x)
   type(t) :: x, y
   real :: r
   logical :: l
+  integer :: iVar
+  complex :: cvar
+  character :: charVar
 contains
   subroutine test_relational()
     l = x == y  !OK
     l = x .eq. y  !OK
+    l = x .eq. y  !OK
+    l = iVar == z'fe' !OK
+    l = z'fe' == iVar !OK
+    l = r == z'fe' !OK
+    l = z'fe' == r !OK
+    l = cVar == z'fe' !OK
+    l = z'fe' == cVar !OK
+    !ERROR: No intrinsic or user-defined OPERATOR(==) matches operand types CHARACTER(KIND=1) and INTEGER(4)
+    l = charVar == z'fe'
+    !ERROR: No intrinsic or user-defined OPERATOR(==) matches operand types INTEGER(4) and CHARACTER(KIND=1)
+    l = z'fe' == charVar
+    !ERROR: No intrinsic or user-defined OPERATOR(==) matches operand types LOGICAL(4) and INTEGER(4)
+    l = l == z'fe' !OK
+    !ERROR: No intrinsic or user-defined OPERATOR(==) matches operand types INTEGER(4) and LOGICAL(4)
+    l = z'fe' == l !OK
     !ERROR: No intrinsic or user-defined OPERATOR(==) matches operand types TYPE(t) and REAL(4)
     l = x == r
+
+    lVar = z'a' == b'1010' !OK
   end
   subroutine test_numeric()
     l = x + r  !OK


        


More information about the flang-commits mailing list