@@ -1367,37 +1367,7 @@ struct UnaryOp<
1367
1367
hlfir::Entity lhs) {
1368
1368
if constexpr (TC1 == Fortran::common::TypeCategory::Character &&
1369
1369
TC2 == TC1) {
1370
- auto kindMap = builder.getKindMap ();
1371
- mlir::Type fromTy = lhs.getFortranElementType ();
1372
- mlir::Value origBufferSize = genCharLength (loc, builder, lhs);
1373
- mlir::Value bufferSize{origBufferSize};
1374
- auto fromBits = kindMap.getCharacterBitsize (
1375
- fir::unwrapRefType (fromTy).cast <fir::CharacterType>().getFKind ());
1376
- mlir::Type toTy = Fortran::lower::getFIRType (
1377
- builder.getContext (), TC1, KIND, /* params=*/ std::nullopt );
1378
- auto toBits = kindMap.getCharacterBitsize (
1379
- toTy.cast <fir::CharacterType>().getFKind ());
1380
- if (toBits < fromBits) {
1381
- // Scale by relative ratio to give a buffer of the same length.
1382
- auto ratio = builder.createIntegerConstant (loc, bufferSize.getType (),
1383
- fromBits / toBits);
1384
- bufferSize =
1385
- builder.create <mlir::arith::MulIOp>(loc, bufferSize, ratio);
1386
- }
1387
- // allocate space on the stack for toBuffer
1388
- auto dest = builder.create <fir::AllocaOp>(loc, toTy,
1389
- mlir::ValueRange{bufferSize});
1390
- auto src = hlfir::convertToAddress (loc, builder, lhs,
1391
- lhs.getFortranElementType ());
1392
- builder.create <fir::CharConvertOp>(loc, src.first .getCharBox ()->getAddr (),
1393
- origBufferSize, dest);
1394
- if (src.second .has_value ())
1395
- src.second .value ()();
1396
-
1397
- return hlfir::EntityWithAttributes{builder.create <hlfir::DeclareOp>(
1398
- loc, dest, " ctor.temp" , /* shape=*/ nullptr ,
1399
- /* typeparams=*/ mlir::ValueRange{origBufferSize},
1400
- fir::FortranVariableFlagsAttr{})};
1370
+ return hlfir::convertCharacterKind (loc, builder, lhs, KIND);
1401
1371
}
1402
1372
mlir::Type type = Fortran::lower::getFIRType (builder.getContext (), TC1,
1403
1373
KIND, /* params=*/ std::nullopt );
@@ -1789,7 +1759,7 @@ class HlfirBuilder {
1789
1759
// If it is allocatable, then using AssignOp for unallocated RHS
1790
1760
// will cause illegal dereference. When an unallocated allocatable
1791
1761
// value is used to construct an allocatable component, the component
1792
- // must just stay unallocated.
1762
+ // must just stay unallocated (see Fortran 2018 7.5.10 point 7) .
1793
1763
1794
1764
// If the component is allocatable and RHS is NULL() expression, then
1795
1765
// we can just skip it: the LHS must remain unallocated with its
@@ -1798,56 +1768,44 @@ class HlfirBuilder {
1798
1768
Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr))
1799
1769
continue ;
1800
1770
1771
+ bool keepLhsLength = false ;
1772
+ if (allowRealloc)
1773
+ if (const Fortran::semantics::DeclTypeSpec *declType = sym.GetType ())
1774
+ keepLhsLength =
1775
+ declType->category () ==
1776
+ Fortran::semantics::DeclTypeSpec::Category::Character &&
1777
+ !declType->characterTypeSpec ().length ().isDeferred ();
1801
1778
// Handle special case when the initializer expression is
1802
1779
// '{%SET_LENGTH(x,const_kind)}'. In structure constructor,
1803
- // SET_LENGTH is used for initializers of character allocatable
1804
- // components with *explicit* length, because they have to keep
1805
- // their length regardless of the initializer expression's length.
1806
- // We cannot just lower SET_LENGTH into hlfir.set_length in case
1807
- // when 'x' is allocatable: if 'x' is unallocated, it is not clear
1808
- // what hlfir.expr should be produced by hlfir.set_length.
1809
- // So whenever the initializer expression is SET_LENGTH we
1810
- // recognize it as the directive to keep the explicit length
1811
- // of the LHS component, and we completely ignore 'const_kind'
1812
- // operand assuming that it matches the LHS component's explicit
1813
- // length. Note that in case when LHS component has deferred length,
1814
- // the FE does not produce SET_LENGTH expression.
1815
- //
1816
- // When SET_LENGTH is recognized, we use 'x' as the initializer
1817
- // for the LHS component. If 'x' is allocatable, the dynamic
1818
- // isAllocated check will guard the assign operation as usual.
1819
- bool keepLhsLength = false ;
1820
- hlfir::Entity rhs = std::visit (
1821
- [&](const auto &x) -> hlfir::Entity {
1822
- using T = std::decay_t <decltype (x)>;
1823
- if constexpr (Fortran::common::HasMember<
1824
- T, Fortran::lower::CategoryExpression>) {
1825
- if constexpr (T::Result::category ==
1826
- Fortran::common::TypeCategory::Character) {
1827
- return std::visit (
1828
- [&](const auto &someKind) -> hlfir::Entity {
1829
- using T = std::decay_t <decltype (someKind)>;
1830
- if (const auto *setLength = std::get_if<
1831
- Fortran::evaluate::SetLength<T::Result::kind>>(
1832
- &someKind.u )) {
1833
- keepLhsLength = true ;
1834
- return gen (setLength->left ());
1835
- }
1836
-
1837
- return gen (someKind);
1838
- },
1839
- x.u );
1840
- }
1841
- }
1842
- return gen (x);
1843
- },
1844
- expr.u );
1845
-
1846
- if (!allowRealloc || !rhs.isMutableBox ()) {
1780
+ // SET_LENGTH is used for initializers of non-allocatable character
1781
+ // components so that the front-end can better
1782
+ // fold and work with these structure constructors.
1783
+ // Here, they are just noise since the assignment semantics will deal
1784
+ // with any length mismatch, and creating an extra temp with the lhs
1785
+ // length is useless.
1786
+ // TODO: should this be moved into an hlfir.assign + hlfir.set_length
1787
+ // pattern rewrite?
1788
+ hlfir::Entity rhs = gen (expr);
1789
+ if (auto set_length = rhs.getDefiningOp <hlfir::SetLengthOp>())
1790
+ rhs = hlfir::Entity{set_length.getString ()};
1791
+
1792
+ // lambda to generate `lhs = rhs` and deal with potential rhs implicit
1793
+ // cast
1794
+ auto genAssign = [&] {
1847
1795
rhs = hlfir::loadTrivialScalar (loc, builder, rhs);
1848
- builder.create <hlfir::AssignOp>(loc, rhs, lhs, allowRealloc,
1796
+ auto rhsCastAndCleanup =
1797
+ hlfir::genTypeAndKindConvert (loc, builder, rhs, lhs.getType (),
1798
+ /* preserveLowerBounds=*/ allowRealloc);
1799
+ builder.create <hlfir::AssignOp>(loc, rhsCastAndCleanup.first , lhs,
1800
+ allowRealloc,
1849
1801
allowRealloc ? keepLhsLength : false ,
1850
1802
/* temporary_lhs=*/ true );
1803
+ if (rhsCastAndCleanup.second )
1804
+ (*rhsCastAndCleanup.second )();
1805
+ };
1806
+
1807
+ if (!allowRealloc || !rhs.isMutableBox ()) {
1808
+ genAssign ();
1851
1809
continue ;
1852
1810
}
1853
1811
@@ -1860,14 +1818,7 @@ class HlfirBuilder {
1860
1818
" to mutable box" );
1861
1819
mlir::Value isAlloc =
1862
1820
fir::factory::genIsAllocatedOrAssociatedTest (builder, loc, *fromBox);
1863
- builder.genIfThen (loc, isAlloc)
1864
- .genThen ([&]() {
1865
- rhs = hlfir::loadTrivialScalar (loc, builder, rhs);
1866
- builder.create <hlfir::AssignOp>(loc, rhs, lhs, allowRealloc,
1867
- keepLhsLength,
1868
- /* temporary_lhs=*/ true );
1869
- })
1870
- .end ();
1821
+ builder.genIfThen (loc, isAlloc).genThen (genAssign).end ();
1871
1822
}
1872
1823
1873
1824
return varOp;
0 commit comments