forked from OSchip/llvm-project
[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
This commit is contained in:
parent
ccdb5b4bbe
commit
83dca19c11
|
@ -123,6 +123,7 @@ public:
|
|||
}
|
||||
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 @@ public:
|
|||
// 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 @@ private:
|
|||
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)};
|
||||
|
|
|
@ -44,12 +44,32 @@ module m1
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue