Skip to content

Commit 574f9df

Browse files
committed
[flang] Extension: Accept Hollerith actual arguments as if they were BOZ
When a Hollerith (or short character) literal is presented as an actual argument that corresponds to a dummy argument for which a BOZ literal would be acceptable, treat the Hollerith as if it had been a BOZ literal in the same way -- and with the same code -- as f18 already does for the similar extension in DATA statements. Differential Revision: https://reviews.llvm.org/D126144
1 parent a1a14e8 commit 574f9df

File tree

5 files changed

+50
-27
lines changed

5 files changed

+50
-27
lines changed

flang/include/flang/Evaluate/tools.h

+5
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,11 @@ Constant<T> PackageConstant(std::vector<Scalar<T>> &&elements,
10761076
std::optional<Expr<SomeType>> DataConstantConversionExtension(
10771077
FoldingContext &, const DynamicType &, const Expr<SomeType> &);
10781078

1079+
// Convert Hollerith or short character to a another type as if the
1080+
// Hollerith data had been BOZ.
1081+
std::optional<Expr<SomeType>> HollerithToBOZ(
1082+
FoldingContext &, const Expr<SomeType> &, const DynamicType &);
1083+
10791084
} // namespace Fortran::evaluate
10801085

10811086
namespace Fortran::semantics {

flang/lib/Evaluate/tools.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,25 @@ bool MayBePassedAsAbsentOptional(
11251125
IsAllocatableOrPointerObject(expr, context);
11261126
}
11271127

1128+
std::optional<Expr<SomeType>> HollerithToBOZ(FoldingContext &context,
1129+
const Expr<SomeType> &expr, const DynamicType &type) {
1130+
if (std::optional<std::string> chValue{GetScalarConstantValue<Ascii>(expr)}) {
1131+
// Pad on the right with spaces when short, truncate the right if long.
1132+
// TODO: big-endian targets
1133+
auto bytes{static_cast<std::size_t>(
1134+
ToInt64(type.MeasureSizeInBytes(context, false)).value())};
1135+
BOZLiteralConstant bits{0};
1136+
for (std::size_t j{0}; j < bytes; ++j) {
1137+
char ch{j >= chValue->size() ? ' ' : chValue->at(j)};
1138+
BOZLiteralConstant chBOZ{static_cast<unsigned char>(ch)};
1139+
bits = bits.IOR(chBOZ.SHIFTL(8 * j));
1140+
}
1141+
return ConvertToType(type, Expr<SomeType>{bits});
1142+
} else {
1143+
return std::nullopt;
1144+
}
1145+
}
1146+
11281147
} // namespace Fortran::evaluate
11291148

11301149
namespace Fortran::semantics {

flang/lib/Semantics/check-call.cpp

+20-8
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,27 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
167167
characteristics::TypeAndShape &actualType, bool isElemental,
168168
evaluate::FoldingContext &context, const Scope *scope,
169169
const evaluate::SpecificIntrinsic *intrinsic,
170-
bool allowIntegerConversions) {
170+
bool allowActualArgumentConversions) {
171171

172172
// Basic type & rank checking
173173
parser::ContextualMessages &messages{context.messages()};
174174
CheckCharacterActual(actual, dummy.type, actualType, context, messages);
175-
if (allowIntegerConversions) {
175+
if (allowActualArgumentConversions) {
176176
ConvertIntegerActual(actual, dummy.type, actualType, messages);
177177
}
178178
bool typesCompatible{dummy.type.type().IsTkCompatibleWith(actualType.type())};
179+
if (!typesCompatible && dummy.type.Rank() == 0 &&
180+
allowActualArgumentConversions) {
181+
// Extension: pass Hollerith literal to scalar as if it had been BOZ
182+
if (auto converted{
183+
evaluate::HollerithToBOZ(context, actual, dummy.type.type())}) {
184+
messages.Say(
185+
"passing Hollerith or character literal as if it were BOZ"_port_en_US);
186+
actual = *converted;
187+
actualType.type() = dummy.type.type();
188+
typesCompatible = true;
189+
}
190+
}
179191
if (typesCompatible) {
180192
if (isElemental) {
181193
} else if (dummy.type.attrs().test(
@@ -683,7 +695,7 @@ static void CheckExplicitInterfaceArg(evaluate::ActualArgument &arg,
683695
const characteristics::DummyArgument &dummy,
684696
const characteristics::Procedure &proc, evaluate::FoldingContext &context,
685697
const Scope *scope, const evaluate::SpecificIntrinsic *intrinsic,
686-
bool allowIntegerConversions) {
698+
bool allowActualArgumentConversions) {
687699
auto &messages{context.messages()};
688700
std::string dummyName{"dummy argument"};
689701
if (!dummy.name.empty()) {
@@ -714,7 +726,7 @@ static void CheckExplicitInterfaceArg(evaluate::ActualArgument &arg,
714726
object.type.Rank() == 0 && proc.IsElemental()};
715727
CheckExplicitDataArg(object, dummyName, *expr, *type,
716728
isElemental, context, scope, intrinsic,
717-
allowIntegerConversions);
729+
allowActualArgumentConversions);
718730
} else if (object.type.type().IsTypelessIntrinsicArgument() &&
719731
IsBOZLiteral(*expr)) {
720732
// ok
@@ -867,7 +879,7 @@ static parser::Messages CheckExplicitInterface(
867879
const characteristics::Procedure &proc, evaluate::ActualArguments &actuals,
868880
const evaluate::FoldingContext &context, const Scope *scope,
869881
const evaluate::SpecificIntrinsic *intrinsic,
870-
bool allowIntegerConversions) {
882+
bool allowActualArgumentConversions) {
871883
parser::Messages buffer;
872884
parser::ContextualMessages messages{context.messages().at(), &buffer};
873885
RearrangeArguments(proc, actuals, messages);
@@ -878,7 +890,7 @@ static parser::Messages CheckExplicitInterface(
878890
const auto &dummy{proc.dummyArguments.at(index++)};
879891
if (actual) {
880892
CheckExplicitInterfaceArg(*actual, dummy, proc, localContext, scope,
881-
intrinsic, allowIntegerConversions);
893+
intrinsic, allowActualArgumentConversions);
882894
} else if (!dummy.IsOptional()) {
883895
if (dummy.name.empty()) {
884896
messages.Say(
@@ -909,9 +921,9 @@ parser::Messages CheckExplicitInterface(const characteristics::Procedure &proc,
909921

910922
bool CheckInterfaceForGeneric(const characteristics::Procedure &proc,
911923
evaluate::ActualArguments &actuals, const evaluate::FoldingContext &context,
912-
bool allowIntegerConversions) {
924+
bool allowActualArgumentConversions) {
913925
return !CheckExplicitInterface(
914-
proc, actuals, context, nullptr, nullptr, allowIntegerConversions)
926+
proc, actuals, context, nullptr, nullptr, allowActualArgumentConversions)
915927
.AnyFatalError();
916928
}
917929

flang/lib/Semantics/check-call.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,6 @@ parser::Messages CheckExplicitInterface(
4646
// Checks actual arguments for the purpose of resolving a generic interface.
4747
bool CheckInterfaceForGeneric(const evaluate::characteristics::Procedure &,
4848
evaluate::ActualArguments &, const evaluate::FoldingContext &,
49-
bool allowIntegerConversions = false);
49+
bool allowActualArgumentConversions = false);
5050
} // namespace Fortran::semantics
5151
#endif

flang/lib/Semantics/data-to-inits.cpp

+5-18
Original file line numberDiff line numberDiff line change
@@ -274,24 +274,11 @@ DataInitializationCompiler<DSV>::ConvertElement(
274274
if (auto converted{evaluate::ConvertToType(type, SomeExpr{expr})}) {
275275
return {std::make_pair(std::move(*converted), false)};
276276
}
277-
if (std::optional<std::string> chValue{
278-
evaluate::GetScalarConstantValue<evaluate::Ascii>(expr)}) {
279-
// Allow DATA initialization with Hollerith and kind=1 CHARACTER like
280-
// (most) other Fortran compilers do. Pad on the right with spaces
281-
// when short, truncate the right if long.
282-
// TODO: big-endian targets
283-
auto bytes{static_cast<std::size_t>(evaluate::ToInt64(
284-
type.MeasureSizeInBytes(exprAnalyzer_.GetFoldingContext(), false))
285-
.value())};
286-
evaluate::BOZLiteralConstant bits{0};
287-
for (std::size_t j{0}; j < bytes; ++j) {
288-
char ch{j >= chValue->size() ? ' ' : chValue->at(j)};
289-
evaluate::BOZLiteralConstant chBOZ{static_cast<unsigned char>(ch)};
290-
bits = bits.IOR(chBOZ.SHIFTL(8 * j));
291-
}
292-
if (auto converted{evaluate::ConvertToType(type, SomeExpr{bits})}) {
293-
return {std::make_pair(std::move(*converted), true)};
294-
}
277+
// Allow DATA initialization with Hollerith and kind=1 CHARACTER like
278+
// (most) other Fortran compilers do.
279+
if (auto converted{evaluate::HollerithToBOZ(
280+
exprAnalyzer_.GetFoldingContext(), expr, type)}) {
281+
return {std::make_pair(std::move(*converted), true)};
295282
}
296283
SemanticsContext &context{exprAnalyzer_.context()};
297284
if (context.IsEnabled(common::LanguageFeature::LogicalIntegerAssignment)) {

0 commit comments

Comments
 (0)