diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -460,6 +460,10 @@ } } +template bool IsBozLiteral(const Expr &expr) { + return std::holds_alternative(expr.u); +} + // Conversions to dynamic types std::optional> ConvertToType( const DynamicType &, Expr &&); diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -1247,7 +1247,7 @@ if (!type) { CHECK(arg->Rank() == 0); const Expr &expr{DEREF(arg->UnwrapExpr())}; - if (std::holds_alternative(expr.u)) { + if (IsBozLiteral(expr)) { if (d.typePattern.kindCode == KindCode::typeless || d.rank == Rank::elementalOrBOZ) { continue; diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -46,7 +46,7 @@ } } if (const auto *expr{arg.UnwrapExpr()}) { - if (std::holds_alternative(expr->u)) { + if (IsBozLiteral(*expr)) { messages.Say("BOZ argument requires an explicit interface"_err_en_US); } if (auto named{evaluate::ExtractNamedEntity(*expr)}) { @@ -632,8 +632,7 @@ CheckExplicitDataArg(object, dummyName, *expr, *type, isElemental, context, scope, intrinsic); } else if (object.type.type().IsTypelessIntrinsicArgument() && - std::holds_alternative( - expr->u)) { + IsBozLiteral(*expr)) { // ok } else if (object.type.type().IsTypelessIntrinsicArgument() && evaluate::IsNullPointer(*expr)) { diff --git a/flang/lib/Semantics/check-io.cpp b/flang/lib/Semantics/check-io.cpp --- a/flang/lib/Semantics/check-io.cpp +++ b/flang/lib/Semantics/check-io.cpp @@ -8,6 +8,7 @@ #include "check-io.h" #include "flang/Common/format.h" +#include "flang/Evaluate/tools.h" #include "flang/Parser/tools.h" #include "flang/Semantics/expression.h" #include "flang/Semantics/tools.h" @@ -550,6 +551,10 @@ flags_.set(Flag::DataList); if (const auto *x{std::get_if(&item.u)}) { if (const auto *expr{GetExpr(*x)}) { + if (evaluate::IsBozLiteral(*expr)) { + context_.Say(parser::FindSourceLocation(*x), // C7109 + "Output item must not be a BOZ literal constant"_err_en_US); + } const Symbol *last{GetLastSymbol(*expr)}; if (last && IsProcedurePointer(*last)) { context_.Say(parser::FindSourceLocation(*x), diff --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp --- a/flang/lib/Semantics/data-to-inits.cpp +++ b/flang/lib/Semantics/data-to-inits.cpp @@ -17,6 +17,7 @@ #include "data-to-inits.h" #include "pointer-assignment.h" #include "flang/Evaluate/fold-designator.h" +#include "flang/Evaluate/tools.h" #include "flang/Semantics/tools.h" namespace Fortran::semantics { @@ -338,7 +339,7 @@ DescribeElement()); } else if (auto converted{ConvertElement(*expr, *designatorType)}) { // value non-pointer initialization - if (std::holds_alternative(expr->u) && + if (IsBozLiteral(*expr) && designatorType->category() != TypeCategory::Integer) { // 8.6.7(11) exprAnalyzer_.Say( "BOZ literal should appear in a DATA statement only as a value for an integer object, but '%s' is '%s'"_en_US, diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -156,9 +156,7 @@ const DynamicType &lhsType, const DynamicType &rhsType); bool OkLogicalIntegerAssignment(TypeCategory lhs, TypeCategory rhs); int GetRank(std::size_t) const; - bool IsBOZLiteral(std::size_t i) const { - return std::holds_alternative(GetExpr(i).u); - } + bool IsBOZLiteral(std::size_t i) const { return IsBozLiteral(GetExpr(i)); } void SayNoMatch(const std::string &, bool isAssignment = false); std::string TypeAsFortran(std::size_t); bool AnyUntypedOrMissingOperand(); diff --git a/flang/test/Semantics/boz-literal-constants.f90 b/flang/test/Semantics/boz-literal-constants.f90 --- a/flang/test/Semantics/boz-literal-constants.f90 +++ b/flang/test/Semantics/boz-literal-constants.f90 @@ -80,4 +80,7 @@ !ERROR: BOZ argument requires an explicit interface call implictSub(Z'12345') + + !ERROR: Output item must not be a BOZ literal constant + print "(Z18)", Z"76543210" end subroutine