================
@@ -1931,159 +1988,171 @@ template <typename DERIVED, typename RESULT, typename 
LEFT, typename RIGHT>
 auto ApplyElementwise(
     FoldingContext &context, Operation<DERIVED, RESULT, LEFT, RIGHT> 
&operation)
     -> std::optional<Expr<RESULT>> {
+  const int kind{operation.kind()};
   return ApplyElementwise(context, operation,
       std::function<Expr<RESULT>(Expr<LEFT> &&, Expr<RIGHT> &&)>{
-          [](Expr<LEFT> &&left, Expr<RIGHT> &&right) {
-            return Expr<RESULT>{DERIVED{std::move(left), std::move(right)}};
+          [kind](Expr<LEFT> &&left, Expr<RIGHT> &&right) {
+            return Expr<RESULT>{
+                DERIVED{kind, std::move(left), std::move(right)}};
           }});
 }
 
 // Unary operations
 
 template <typename TO, typename FROM>
-common::IfNoLvalue<std::optional<TO>, FROM> ConvertString(FROM &&s) {
-  if constexpr (std::is_same_v<TO, FROM>) {
+common::IfNoLvalue<std::optional<TO>, FROM> ConvertString(
+    int toKind, FROM &&s) {
+  const int fromKind{s.kind()};
+  if (std::is_same_v<TO, FROM> && toKind == fromKind) {
     return std::make_optional<TO>(std::move(s));
+  } else if (auto result{s.ToAscii(toKind)}; !result.IsNull()) {
+    return result;
   } else {
-    // Fortran character conversion is well defined between distinct kinds
-    // only when the actual characters are valid 7-bit ASCII.
-    TO str;
-    for (auto iter{s.cbegin()}; iter != s.cend(); ++iter) {
-      if (static_cast<std::uint64_t>(*iter) > 127) {
-        return std::nullopt;
-      }
-      str.push_back(static_cast<typename TO::value_type>(*iter));
-    }
-    return std::make_optional<TO>(std::move(str));
+    return std::nullopt;
   }
 }
 
 template <typename TO, TypeCategory FROMCAT>
 Expr<TO> FoldOperation(
     FoldingContext &context, Convert<TO, FROMCAT> &&convert) {
+  const int toKind{convert.kind()};
   if (auto array{ApplyElementwise(context, convert)}) {
     return *array;
   }
   struct {
     FoldingContext &context;
     Convert<TO, FROMCAT> &convert;
-  } msvcWorkaround{context, convert};
+    int toKind;
+  } msvcWorkaround{context, convert, toKind};
   return common::visit(
       [&msvcWorkaround](auto &kindExpr) -> Expr<TO> {
         using Operand = ResultType<decltype(kindExpr)>;
+        const int operandKind{kindExpr.kind()};
+        const int toKind{msvcWorkaround.toKind};
         // This variable is a workaround for msvc which emits an error when
         // using the FROMCAT template parameter below.
         TypeCategory constexpr FromCat{FROMCAT};
         static_assert(FromCat == Operand::category);
         auto &convert{msvcWorkaround.convert};
         if (auto value{GetScalarConstantValue<Operand>(kindExpr)}) {
           FoldingContext &ctx{msvcWorkaround.context};
+          const int fromKind{value->kind()};
           if constexpr (TO::category == TypeCategory::Integer) {
             if constexpr (FromCat == TypeCategory::Integer) {
-              auto converted{Scalar<TO>::ConvertSigned(*value)};
+              auto converted{Scalar<TO>::ConvertSigned(toKind, *value)};
               if (converted.overflow) {
                 ctx.Warn(common::UsageWarning::FoldingException,
                     "conversion of %s_%d to INTEGER(%d) overflowed; result is 
%s"_warn_en_US,
-                    value->SignedDecimal(), Operand::kind, TO::kind,
+                    value->SignedDecimal(), fromKind, toKind,
                     converted.value.SignedDecimal());
               }
-              return ScalarConstantToExpr(std::move(converted.value));
+              return MakeConstantExpr<TO>(toKind, std::move(converted.value));
             } else if constexpr (FromCat == TypeCategory::Unsigned) {
-              auto converted{Scalar<TO>::ConvertUnsigned(*value)};
+              auto converted{Scalar<TO>::ConvertUnsigned(toKind, *value)};
               if ((converted.overflow || converted.value.IsNegative())) {
                 ctx.Warn(common::UsageWarning::FoldingException,
                     "conversion of %s_U%d to INTEGER(%d) overflowed; result is 
%s"_warn_en_US,
-                    value->UnsignedDecimal(), Operand::kind, TO::kind,
+                    value->UnsignedDecimal(), fromKind, toKind,
                     converted.value.SignedDecimal());
               }
-              return ScalarConstantToExpr(std::move(converted.value));
+              return MakeConstantExpr<TO>(toKind, std::move(converted.value));
             } else if constexpr (FromCat == TypeCategory::Real) {
-              auto converted{value->template ToInteger<Scalar<TO>>()};
+              auto converted{value->ToInteger(
+                  common::RoundingMode::ToZero, Scalar<TO>::bits(toKind))};
               if (converted.flags.test(RealFlag::InvalidArgument)) {
                 ctx.Warn(common::UsageWarning::FoldingException,
                     "REAL(%d) to INTEGER(%d) conversion: invalid 
argument"_warn_en_US,
-                    Operand::kind, TO::kind);
+                    fromKind, toKind);
               } else if (converted.flags.test(RealFlag::Overflow)) {
                 ctx.Warn(common::UsageWarning::FoldingException,
                     "REAL(%d) to INTEGER(%d) conversion overflowed"_warn_en_US,
-                    Operand::kind, TO::kind);
+                    fromKind, toKind);
               }
-              return ScalarConstantToExpr(std::move(converted.value));
+              return MakeConstantExpr<TO>(toKind, std::move(converted.value));
             }
           } else if constexpr (TO::category == TypeCategory::Unsigned) {
             if constexpr (FromCat == TypeCategory::Integer ||
                 FromCat == TypeCategory::Unsigned) {
-              return Expr<TO>{
-                  Constant<TO>{Scalar<TO>::ConvertUnsigned(*value).value}};
+              return MakeConstantExpr<TO>(
+                  toKind, Scalar<TO>::ConvertUnsigned(toKind, *value).value);
             } else if constexpr (FromCat == TypeCategory::Real) {
-              return Expr<TO>{
-                  Constant<TO>{value->template ToInteger<Scalar<TO>>().value}};
+              return MakeConstantExpr<TO>(toKind,
+                  value
+                      ->ToInteger(common::RoundingMode::ToZero,
+                          Scalar<TO>::bits(toKind))
+                      .value);
             }
           } else if constexpr (TO::category == TypeCategory::Real) {
             if constexpr (FromCat == TypeCategory::Integer ||
                 FromCat == TypeCategory::Unsigned) {
               auto converted{Scalar<TO>::FromInteger(
-                  *value, FromCat == TypeCategory::Unsigned)};
+                  toKind, *value, FromCat == TypeCategory::Unsigned)};
               if (!converted.flags.empty()) {
                 char buffer[64];
                 std::snprintf(buffer, sizeof buffer,
-                    "INTEGER(%d) to REAL(%d) conversion", Operand::kind,
-                    TO::kind);
+                    "INTEGER(%d) to REAL(%d) conversion", fromKind, toKind);
                 ctx.RealFlagWarnings(converted.flags, buffer);
               }
-              return ScalarConstantToExpr(std::move(converted.value));
+              return MakeConstantExpr<TO>(toKind, std::move(converted.value));
             } else if constexpr (FromCat == TypeCategory::Real) {
-              auto converted{Scalar<TO>::Convert(*value)};
+              auto converted{Scalar<TO>::Convert(toKind, *value)};
               char buffer[64];
               if (!converted.flags.empty()) {
                 std::snprintf(buffer, sizeof buffer,
-                    "REAL(%d) to REAL(%d) conversion", Operand::kind, 
TO::kind);
+                    "REAL(%d) to REAL(%d) conversion", fromKind, toKind);
                 ctx.RealFlagWarnings(converted.flags, buffer);
               }
               if (ctx.targetCharacteristics().areSubnormalsFlushedToZero()) {
                 converted.value = converted.value.FlushSubnormalToZero();
               }
-              return ScalarConstantToExpr(std::move(converted.value));
+              return MakeConstantExpr<TO>(toKind, std::move(converted.value));
             }
           } else if constexpr (TO::category == TypeCategory::Complex) {
             if constexpr (FromCat == TypeCategory::Complex) {
               return FoldOperation(ctx,
-                  ComplexConstructor<TO::kind>{
-                      AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
-                          Constant<typename Operand::Part>{value->REAL()})}),
-                      AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
-                          Constant<typename 
Operand::Part>{value->AIMAG()})})});
+                  ComplexConstructor{toKind,
+                      Fold(ctx,
+                          AsExpr(Convert<typename TO::Part>(toKind,
+                              AsCategoryExpr(Constant<typename Operand::Part>{
+                                  toKind, value->REAL()})))),
+                      Fold(ctx,
+                          AsExpr(Convert<typename TO::Part>(toKind,
+                              AsCategoryExpr(Constant<typename Operand::Part>{
+                                  toKind, value->AIMAG()}))))});
             }
           } else if constexpr (TO::category == TypeCategory::Character &&
               FromCat == TypeCategory::Character) {
-            if (auto converted{ConvertString<Scalar<TO>>(std::move(*value))}) {
+            if (auto converted{
+                    ConvertString<Scalar<TO>>(toKind, std::move(*value))}) {
               return ScalarConstantToExpr(std::move(*converted));
             }
           } else if constexpr (TO::category == TypeCategory::Logical &&
               FromCat == TypeCategory::Logical) {
-            return Expr<TO>{value->IsTrue()};
+            return MakeConstantExpr<TO>(toKind, value->IsTrue());
           }
         } else if constexpr (TO::category == FromCat &&
             FromCat != TypeCategory::Character) {
           // Conversion of non-constant in same type category
-          if constexpr (std::is_same_v<Operand, TO>) {
+          if (Operand::category == TO::category && toKind == operandKind) {
             return std::move(kindExpr); // remove needless conversion
           } else if constexpr (TO::category == TypeCategory::Logical ||
               TO::category == TypeCategory::Integer) {
             if (auto *innerConv{
                     std::get_if<Convert<Operand, TO::category>>(&kindExpr.u)}) 
{
               // Conversion of conversion of same category & kind
               if (auto *x{std::get_if<Expr<TO>>(&innerConv->left().u)}) {
-                if constexpr (TO::category == TypeCategory::Logical ||
-                    TO::kind <= Operand::kind) {
+                if (TO::category == TypeCategory::Logical ||
+                    toKind <= operandKind) {
----------------
tblah wrote:

I think this needs to be `==`. The relational operator isn't new, but it is 
newly exposed. Previously, the kind was encoded into the type and so the 
`get_if` would fail if the kinds differed. Now this code is actually reachable 
with non-equal kinds.

Otherwise something like `integer(8) :: x`,
`int(int(x,kind=4),kind=2)` therefore returns `x` and drops both
conversions

https://github.com/llvm/llvm-project/pull/216960
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to