[flang-commits] [flang] [flang] Add structure constructor with allocatable component (PR #77845)
Kelvin Li via flang-commits
flang-commits at lists.llvm.org
Mon Jan 15 18:46:16 PST 2024
https://github.com/kkwli updated https://github.com/llvm/llvm-project/pull/77845
>From f43f9bc59627796f63895d8c516585d18d5398db Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 26 Oct 2023 08:51:21 -0400
Subject: [PATCH 1/4] [flang] Add structure constructor with allocatable
component
---
flang/lib/Evaluate/check-expression.cpp | 6 +
flang/lib/Evaluate/fold.cpp | 5 +
flang/lib/Lower/ConvertConstant.cpp | 15 ++-
.../structure-constructors-alloc-comp.f90 | 120 ++++++++++++++++++
flang/test/Semantics/structconst06.f90 | 1 +
flang/test/Semantics/structconst07.f90 | 6 +
flang/test/Semantics/structconst08.f90 | 57 +++++++++
7 files changed, 208 insertions(+), 2 deletions(-)
create mode 100644 flang/test/Lower/structure-constructors-alloc-comp.f90
create mode 100644 flang/test/Semantics/structconst08.f90
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 2f46ed7dccb645..2e8a6589806c2a 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -188,6 +188,12 @@ struct IsActuallyConstantHelper {
return common::visit([this](const auto &y) { return (*this)(y); }, x.u);
}
bool operator()(const StructureConstructor &x) {
+ // If the comp-spec of a derived-type-spec is a structure constructor that
+ // is not a constant, the derived-type-spec is not a constant
+ if (!UnwrapExpr<Constant<SomeDerived>>(x)) {
+ return false;
+ }
+
for (const auto &pair : x) {
const Expr<SomeType> &y{pair.second.value()};
if (!(*this)(y) && !IsNullPointer(y)) {
diff --git a/flang/lib/Evaluate/fold.cpp b/flang/lib/Evaluate/fold.cpp
index dfcc2599a555e5..ed882958199802 100644
--- a/flang/lib/Evaluate/fold.cpp
+++ b/flang/lib/Evaluate/fold.cpp
@@ -82,6 +82,11 @@ Expr<SomeDerived> FoldOperation(
} else {
isConstant &= IsInitialDataTarget(expr);
}
+ } else if (IsAllocatable(symbol)) {
+ // F2023: 10.1.12 (3)(a)
+ // If comp-spec is not null() for the allocatable component the
+ // structure constructor is not a constant expression.
+ isConstant &= IsNullPointer(expr);
} else {
isConstant &= IsActuallyConstant(expr) || IsNullPointer(expr);
if (auto valueShape{GetConstantExtents(context, expr)}) {
diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp
index d7a4d68f2aaae7..2efacd4e2db959 100644
--- a/flang/lib/Lower/ConvertConstant.cpp
+++ b/flang/lib/Lower/ConvertConstant.cpp
@@ -18,6 +18,7 @@
#include "flang/Lower/ConvertVariable.h"
#include "flang/Lower/Mangler.h"
#include "flang/Optimizer/Builder/Complex.h"
+#include "flang/Optimizer/Builder/MutableBox.h"
#include "flang/Optimizer/Builder/Todo.h"
#include <algorithm>
@@ -362,8 +363,18 @@ static mlir::Value genStructureComponentInit(
loc, fieldTy, name, recTy,
/*typeParams=*/mlir::ValueRange{} /*TODO*/);
- if (Fortran::semantics::IsAllocatable(sym))
- TODO(loc, "allocatable component in structure constructor");
+ if (Fortran::semantics::IsAllocatable(sym)) {
+ if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr)) {
+ // Handle NULL() initialization
+ mlir::Value componentValue{fir::factory::createUnallocatedBox(
+ builder, loc, componentTy, std::nullopt)};
+ componentValue = builder.createConvert(loc, componentTy, componentValue);
+
+ return builder.create<fir::InsertValueOp>(
+ loc, recTy, res, componentValue,
+ builder.getArrayAttr(field.getAttributes()));
+ }
+ }
if (Fortran::semantics::IsPointer(sym)) {
if (Fortran::semantics::IsProcedure(sym))
diff --git a/flang/test/Lower/structure-constructors-alloc-comp.f90 b/flang/test/Lower/structure-constructors-alloc-comp.f90
new file mode 100644
index 00000000000000..49270bcd5288a1
--- /dev/null
+++ b/flang/test/Lower/structure-constructors-alloc-comp.f90
@@ -0,0 +1,120 @@
+! Test lowering of structure constructors of derived types with allocatable component
+! RUN: bbc -emit-hlfir %s -o - | FileCheck --check-prefixes=HLFIR %s
+
+module m_struct_ctor
+ implicit none
+ type t_alloc
+ real :: x
+ integer, allocatable :: a(:)
+ end type
+
+contains
+ subroutine test_alloc1(y)
+ real :: y
+ call print_alloc_comp(t_alloc(x=y, a=null()))
+! HLFIR-LABEL: func.func @_QMm_struct_ctorPtest_alloc1(
+! HLFIR-SAME: %[[ARG_0:.*]]: !fir.ref<f32> {fir.bindc_name = "y"}) {
+! HLFIR: %[[VAL_0:.*]] = fir.alloca !fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@_QMm_struct_ctorE.n.x) : !fir.ref<!fir.char<1>>
+! HLFIR: %[[CONS_1:.*]] = arith.constant 1 : index
+! HLFIR: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {{.*}}"_QMm_struct_ctorE.n.x"
+! HLFIR: %[[VAL_3:.*]] = fir.address_of(@_QMm_struct_ctorE.n.a) : !fir.ref<!fir.char<1>>
+! HLFIR: %[[CONS_2:.* ]]= arith.constant 1 : index
+! HLFIR: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {{.*}}"_QMm_struct_ctorE.n.a"
+! HLFIR: %[[VAL_5:.*]] = fir.address_of(@_QMm_struct_ctorE.n.t_alloc) : !fir.ref<!fir.char<1,7>>
+! HLFIR: %[[CONS_3:.*]] = arith.constant 7 : index
+! HLFIR: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {{.*}}"_QMm_struct_ctorE.n.t_alloc"
+! HLFIR: %[[VAL_7:.*]] = fir.address_of(@_QMm_struct_ctorE.c.t_alloc)
+! HLFIR: %[[CONS_4:.*]] = arith.constant 0 : index
+! HLFIR: %[[CONS_5:.*]] = arith.constant 2 : index
+! HLFIR: %[[VAL_8:.*]] = fir.shape_shift %[[CONS_4]], %[[CONS_5]] : (index, index) -> !fir.shapeshift<1>
+! HLFIR: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_8]]) {{.*}}"_QMm_struct_ctorE.c.t_alloc"
+! HLFIR: %[[VAL_10:.*]] = fir.address_of(@_QMm_struct_ctorE.dt.t_alloc)
+! HLFIR: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {{.*}}"_QMm_struct_ctorE.dt.t_alloc"
+! HLFIR: %[[VAL_12:.*]]:2 = hlfir.declare %[[ARG_0]] {uniq_name = "_QMm_struct_ctorFtest_alloc1Ey"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! HLFIR: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
+! HLFIR: %[[VAL_14:.*]] = fir.embox %[[VAL_13]]#0 : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+! HLFIR: %[[VAL_15:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
+! HLFIR: %[[CONS_6:.*]] = arith.constant {{.*}} : i32
+! HLFIR: %[[VAL_16:.*]] = fir.convert %[[VAL_14]] : (!fir.box<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<none>
+! HLFIR: %[[VAL_17:.*]] = fir.convert %[[VAL_15]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! HLFIR: %{{.*}} = fir.call @_FortranAInitialize(%[[VAL_16]], %[[VAL_17]], %[[CONS_6]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
+! HLFIR: %[[VAL_18:.*]] = hlfir.designate %[[VAL_13]]#0{"x"} : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.ref<f32>
+! HLFIR: %[[VAL_19:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref<f32>
+! HLFIR: hlfir.assign %[[VAL_19]] to %[[VAL_18]] temporary_lhs : f32, !fir.ref<f32>
+! HLFIR: fir.call @_QPprint_alloc_comp(%[[VAL_13]]#1) fastmath<contract> : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> ()
+! HLFIR: return
+! HLFIR: }
+ end subroutine
+
+ subroutine test_alloc2(y, b)
+ real :: y
+ integer :: b(5)
+ call print_alloc_comp(t_alloc(x=y, a=b))
+! HLFIR-LABEL: func.func @_QMm_struct_ctorPtest_alloc2
+! HLFIR-SAME: (%[[ARG_0:.*]]: !fir.ref<f32> {fir.bindc_name = "y"}, %[[ARG_1:.*]]: !fir.ref<!fir.array<5xi32>> {fir.bindc_name = "b"}) {
+! HLFIR: %[[VAL_0:.*]] = fir.alloca !fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@_QMm_struct_ctorE.n.x) : !fir.ref<!fir.char<1>>
+! HLFIR: %[[CONS_1:.*]] = arith.constant 1 : index
+! HLFIR: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] typeparams %[[CONS_1]] {{.*}}"_QMm_struct_ctorE.n.x"
+! HLFIR: %[[VAL_3:.*]] = fir.address_of(@_QMm_struct_ctorE.n.a) : !fir.ref<!fir.char<1>>
+! HLFIR: %[[CONS_2:.*]] = arith.constant 1 : index
+! HLFIR: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] typeparams %[[CONS_2]] {{.*}}"_QMm_struct_ctorE.n.a"
+! HLFIR: %[[VAL_5:.*]] = fir.address_of(@_QMm_struct_ctorE.n.t_alloc) : !fir.ref<!fir.char<1,7>>
+! HLFIR: %[[CONS_3:.*]] = arith.constant 7 : index
+! HLFIR: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[CONS_3]] {{.*}}"_QMm_struct_ctorE.n.t_alloc"
+! HLFIR: %[[VAL_7:.*]] = fir.address_of(@_QMm_struct_ctorE.c.t_alloc)
+! HLFIR: %[[CONS_4:.*]] = arith.constant 0 : index
+! HLFIR: %[[CONS_5:.*]] = arith.constant 2 : index
+! HLFIR: %[[VAL_8:.*]] = fir.shape_shift %[[CONS_4]], %[[CONS_5]] : (index, index) -> !fir.shapeshift<1>
+! HLFIR: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_8]]) {{.*}}"_QMm_struct_ctorE.c.t_alloc"
+! HLFIR: %[[VAL_10:.*]] = fir.address_of(@_QMm_struct_ctorE.dt.t_alloc)
+! HLFIR: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {{.*}}"_QMm_struct_ctorE.dt.t_alloc"
+! HLFIR: %[[CONS_6:.*]] = arith.constant 5 : index
+! HLFIR: %[[VAL_12:.*]] = fir.shape %[[CONS_6]] : (index) -> !fir.shape<1>
+! HLFIR: %[[VAL_13:.*]]:2 = hlfir.declare %[[ARG_1]](%[[VAL_12]]) {uniq_name = "_QMm_struct_ctorFtest_alloc2Eb"} : (!fir.ref<!fir.array<5xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.array<5xi32>>)
+! HLFIR: %[[VAL_14:.*]]:2 = hlfir.declare %[[ARG_0]] {uniq_name = "_QMm_struct_ctorFtest_alloc2Ey"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! HLFIR: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
+! HLFIR: %[[VAL_16:.*]] = fir.embox %[[VAL_15]]#0 : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+! HLFIR: %[[VAL_17:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
+! HLFIR: %[[CONS_7:.*]] = arith.constant {{.*}} : i32
+! HLFIR: %[[VAL_18:.*]] = fir.convert %[[VAL_16]] : (!fir.box<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<none>
+! HLFIR: %[[VAL_19:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! HLFIR: {{.*}} = fir.call @_FortranAInitialize(%[[VAL_18]], %[[VAL_19]], %[[CONS_7]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
+! HLFIR: %[[VAL_20:.*]] = hlfir.designate %[[VAL_15]]#0{"x"} : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.ref<f32>
+! HLFIR: %[[VAL_21:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref<f32>
+! HLFIR: hlfir.assign %[[VAL_21]] to %[[VAL_20]] temporary_lhs : f32, !fir.ref<f32>
+! HLFIR: %[[VAL_22:.*]] = hlfir.designate %[[VAL_15]]#0{"a"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! HLFIR: hlfir.assign %[[VAL_13]]#0 to %[[VAL_22]] realloc temporary_lhs : !fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! HLFIR: fir.call @_QPprint_alloc_comp(%[[VAL_15]]#1) fastmath<contract> : (!fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> ()
+! HLFIR: return
+! HLFIR: }
+ end subroutine
+
+ subroutine test_alloc3()
+ type(t_alloc) :: t1 = t_alloc(x=5, a=null())
+! HLFIR-LABEL: func.func @_QMm_struct_ctorPtest_alloc3() {
+! HLFIR: %[[VAL_0:.*]] = fir.address_of(@_QMm_struct_ctorE.n.x) : !fir.ref<!fir.char<1>>
+! HLFIR: %c1 = arith.constant 1 : index
+! HLFIR: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %c1 {{.*}}"_QMm_struct_ctorE.n.x"
+! HLFIR: %[[VAL_2:.*]] = fir.address_of(@_QMm_struct_ctorE.n.a) : !fir.ref<!fir.char<1>>
+! HLFIR: %c1_0 = arith.constant 1 : index
+! HLFIR: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %c1_0 {{.*}}"_QMm_struct_ctorE.n.a"
+! HLFIR: %[[VAL_4:.*]] = fir.address_of(@_QMm_struct_ctorE.n.t_alloc) : !fir.ref<!fir.char<1,7>>
+! HLFIR: %c7 = arith.constant 7 : index
+! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] typeparams %c7 {{.*}}"_QMm_struct_ctorE.n.t_alloc"
+! HLFIR: %[[VAL_6:.*]] = fir.address_of(@_QMm_struct_ctorE.c.t_alloc)
+! HLFIR: %c0 = arith.constant 0 : index
+! HLFIR: %c2 = arith.constant 2 : index
+! HLFIR: %[[VAL_7:.*]] = fir.shape_shift %c0, %c2 : (index, index) -> !fir.shapeshift<1>
+! HLFIR: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_7]]) {{.*}}"_QMm_struct_ctorE.c.t_alloc"
+! HLFIR: %[[VAL_9:.*]] = fir.address_of(@_QMm_struct_ctorE.dt.t_alloc)
+! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {{.*}}"_QMm_struct_ctorE.dt.t_alloc"
+! HLFIR: %[[VAL_11:.*]] = fir.address_of(@_QMm_struct_ctorFtest_alloc3Et1) : !fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+! HLFIR: {{.*}}:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QMm_struct_ctorFtest_alloc3Et1"}
+! HLFIR: return
+! HLFIR: }
+
+ end subroutine
+
+end module m_struct_ctor
diff --git a/flang/test/Semantics/structconst06.f90 b/flang/test/Semantics/structconst06.f90
index d5a40410ea63a1..45a0fb97842d30 100644
--- a/flang/test/Semantics/structconst06.f90
+++ b/flang/test/Semantics/structconst06.f90
@@ -4,6 +4,7 @@ module m
type t
real, allocatable :: a(:)
end type
+ !ERROR: Must be a constant value
!ERROR: Scalar value cannot be expanded to shape of array component 'a'
type(t) :: x = t(0.)
end module
diff --git a/flang/test/Semantics/structconst07.f90 b/flang/test/Semantics/structconst07.f90
index a34289a817af44..d61c54200dc82d 100644
--- a/flang/test/Semantics/structconst07.f90
+++ b/flang/test/Semantics/structconst07.f90
@@ -2,8 +2,14 @@
type :: hasPointer
class(*), pointer :: sp
end type
+type :: hasAllocatable
+ class(*), allocatable :: sa
+end type
type(hasPointer) hp
+type(hasAllocatable) ha
!CHECK: hp=haspointer(sp=NULL())
hp = hasPointer()
+!CHECK: ha=hasallocatable(sa=NULL())
+ha = hasAllocatable()
end
diff --git a/flang/test/Semantics/structconst08.f90 b/flang/test/Semantics/structconst08.f90
new file mode 100644
index 00000000000000..211b0e79bf5e44
--- /dev/null
+++ b/flang/test/Semantics/structconst08.f90
@@ -0,0 +1,57 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
+!
+! Error tests for structure constructors of derived types with allocatable components
+
+module m
+ type parent1
+ integer, allocatable :: pa
+ end type parent1
+ type parent2
+ real, allocatable :: pa(:)
+ end type parent2
+ type child
+ integer :: i
+ type(parent2) :: ca
+ end type
+
+contains
+ subroutine test1()
+ integer :: j
+ real :: arr(5)
+!ERROR: Must be a constant value
+ type(parent1) :: tp1 = parent1(3)
+!ERROR: Must be a constant value
+ type(parent1) :: tp2 = parent1(j)
+ type(parent1) :: tp3 = parent1(null())
+
+!ERROR: Must be a constant value
+ type(parent2) :: tp4 = parent2([1.1,2.1,3.1])
+!ERROR: Must be a constant value
+ type(parent2) :: tp5 = parent2(arr)
+ type(parent2) :: tp6 = parent2(null())
+ end subroutine test1
+
+ subroutine test2()
+ integer :: j
+ real :: arr(5)
+ type(parent1) :: tp1
+ type(parent2) :: tp2
+ tp1 = parent1(3)
+ tp1 = parent1(j)
+ tp1 = parent1(null())
+
+ tp2 = parent2([1.1,2.1,3.1])
+ tp2 = parent2(arr)
+ tp2 = parent2(null())
+ end subroutine test2
+
+ subroutine test3()
+ type(child) :: tc1 = child(5, parent2(null()))
+!ERROR: Must be a constant value
+ type(child) :: tc2 = child(5, parent2([1.1,1.2]))
+ type(child) :: tc3
+
+ tc3 = child(5, parent2(null()))
+ tc3 = child(5, parent2([1.1,1.2]))
+ end subroutine test3
+end module m
>From 9f0a25289098efebd666cdc96093b46ba28024bd Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 11 Jan 2024 23:08:40 -0500
Subject: [PATCH 2/4] Fix the component check
---
flang/lib/Evaluate/check-expression.cpp | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 2e8a6589806c2a..14abac5ff9ba80 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -188,15 +188,14 @@ struct IsActuallyConstantHelper {
return common::visit([this](const auto &y) { return (*this)(y); }, x.u);
}
bool operator()(const StructureConstructor &x) {
- // If the comp-spec of a derived-type-spec is a structure constructor that
- // is not a constant, the derived-type-spec is not a constant
- if (!UnwrapExpr<Constant<SomeDerived>>(x)) {
- return false;
- }
-
for (const auto &pair : x) {
const Expr<SomeType> &y{pair.second.value()};
- if (!(*this)(y) && !IsNullPointer(y)) {
+ const auto sym{pair.first};
+ const bool compIsConstant{(*this)(y)};
+ // If an allocatable component is initialized by a constant,
+ // the structure constructor is not a constant.
+ if ((!compIsConstant && !IsNullPointer(y)) ||
+ (compIsConstant && IsAllocatable(sym))) {
return false;
}
}
>From 2fd230411796f9b983f112327cd82325f3e021b4 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Mon, 15 Jan 2024 21:38:27 -0500
Subject: [PATCH 3/4] - update logic to handle the null(mod) case - add more
tests
---
flang/lib/Lower/ConvertConstant.cpp | 4 +-
.../structure-constructors-alloc-comp.f90 | 40 +++++++++++++++++--
flang/test/Semantics/structconst08.f90 | 29 ++++++++++----
3 files changed, 61 insertions(+), 12 deletions(-)
diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp
index 2efacd4e2db959..756eab6da49531 100644
--- a/flang/lib/Lower/ConvertConstant.cpp
+++ b/flang/lib/Lower/ConvertConstant.cpp
@@ -364,7 +364,9 @@ static mlir::Value genStructureComponentInit(
/*typeParams=*/mlir::ValueRange{} /*TODO*/);
if (Fortran::semantics::IsAllocatable(sym)) {
- if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr)) {
+ if (!Fortran::evaluate::IsNullPointer(expr)) {
+ fir::emitFatalError(loc, "constant structure constructor with an allocatable component value that is not NULL");
+ } else {
// Handle NULL() initialization
mlir::Value componentValue{fir::factory::createUnallocatedBox(
builder, loc, componentTy, std::nullopt)};
diff --git a/flang/test/Lower/structure-constructors-alloc-comp.f90 b/flang/test/Lower/structure-constructors-alloc-comp.f90
index 49270bcd5288a1..f6dceb8f5e0501 100644
--- a/flang/test/Lower/structure-constructors-alloc-comp.f90
+++ b/flang/test/Lower/structure-constructors-alloc-comp.f90
@@ -46,7 +46,7 @@ subroutine test_alloc1(y)
! HLFIR: return
! HLFIR: }
end subroutine
-
+
subroutine test_alloc2(y, b)
real :: y
integer :: b(5)
@@ -103,18 +103,50 @@ subroutine test_alloc3()
! HLFIR: %[[VAL_4:.*]] = fir.address_of(@_QMm_struct_ctorE.n.t_alloc) : !fir.ref<!fir.char<1,7>>
! HLFIR: %c7 = arith.constant 7 : index
! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] typeparams %c7 {{.*}}"_QMm_struct_ctorE.n.t_alloc"
-! HLFIR: %[[VAL_6:.*]] = fir.address_of(@_QMm_struct_ctorE.c.t_alloc)
+! HLFIR: %[[VAL_6:.*]] = fir.address_of(@_QMm_struct_ctorE.c.t_alloc)
! HLFIR: %c0 = arith.constant 0 : index
! HLFIR: %c2 = arith.constant 2 : index
! HLFIR: %[[VAL_7:.*]] = fir.shape_shift %c0, %c2 : (index, index) -> !fir.shapeshift<1>
! HLFIR: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_7]]) {{.*}}"_QMm_struct_ctorE.c.t_alloc"
-! HLFIR: %[[VAL_9:.*]] = fir.address_of(@_QMm_struct_ctorE.dt.t_alloc)
+! HLFIR: %[[VAL_9:.*]] = fir.address_of(@_QMm_struct_ctorE.dt.t_alloc)
! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {{.*}}"_QMm_struct_ctorE.dt.t_alloc"
! HLFIR: %[[VAL_11:.*]] = fir.address_of(@_QMm_struct_ctorFtest_alloc3Et1) : !fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
-! HLFIR: {{.*}}:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QMm_struct_ctorFtest_alloc3Et1"}
+! HLFIR: {{.*}}:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QMm_struct_ctorFtest_alloc3Et1"}
! HLFIR: return
! HLFIR: }
+ end subroutine
+ subroutine test_alloc4()
+ integer, pointer :: p(:)
+ type(t_alloc) :: t1 = t_alloc(x=5, a=null(p))
+! HLFIR-LABEL: func.func @_QMm_struct_ctorPtest_alloc4() {
+! HLFIR: %[[VAL_0:.*]] = fir.address_of(@_QMm_struct_ctorE.n.x) : !fir.ref<!fir.char<1>>
+! HLFIR: %[[CONS_1:.*]] = arith.constant 1 : index
+! HLFIR: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[CONS_1]] {{.*}}"_QMm_struct_ctorE.n.x"
+! HLFIR: %[[VAL_2:.*]] = fir.address_of(@_QMm_struct_ctorE.n.a) : !fir.ref<!fir.char<1>>
+! HLFIR: %[[CONS_2:.*]] = arith.constant 1 : index
+! HLFIR: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[CONS_2]] {{.*}}"_QMm_struct_ctorE.n.a"
+! HLFIR: %[[VAL_4:.*]] = fir.address_of(@_QMm_struct_ctorE.n.t_alloc) : !fir.ref<!fir.char<1,7>>
+! HLFIR: %[[CONS_3:.*]] = arith.constant 7 : index
+! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] typeparams %[[CONS_3]] {{.*}}"_QMm_struct_ctorE.n.t_alloc"
+! HLFIR: %[[VAL_6:.*]] = fir.address_of(@_QMm_struct_ctorE.c.t_alloc)
+! HLFIR: %[[CONS_4:.*]] = arith.constant 0 : index
+! HLFIR: %[[CONS_5:.*]] = arith.constant 2 : index
+! HLFIR: %[[VAL_7:.*]] = fir.shape_shift %[[CONS_4]], %[[CONS_5]] : (index, index) -> !fir.shapeshift<1>
+! HLFIR: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_7]]) {{.*}}"_QMm_struct_ctorE.c.t_alloc"
+! HLFIR: %[[VAL_9:.*]] = fir.address_of(@_QMm_struct_ctorE.dt.t_alloc)
+! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {{.*}}"_QMm_struct_ctorE.dt.t_alloc"
+! HLFIR: %[[VAL_11:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "p", uniq_name = "_QMm_struct_ctorFtest_alloc4Ep"}
+! HLFIR: %[[VAL_12:.*]] = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+! HLFIR: %[[CONS_6:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_13:.*]] = fir.shape %[[CONS_6]] : (index) -> !fir.shape<1>
+! HLFIR: %[[VAL_14:.*]] = fir.embox %[[VAL_12]](%[[VAL_13]]) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! HLFIR: fir.store %[[VAL_14]] to %[[VAL_11]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! HLFIR: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_11]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMm_struct_ctorFtest_alloc4Ep"}
+! HLFIR: %[[VAL_16:.*]] = fir.address_of(@_QMm_struct_ctorFtest_alloc4Et1) : !fir.ref<!fir.type<_QMm_struct_ctorTt_alloc{x:f32,a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+! HLFIR: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QMm_struct_ctorFtest_alloc4Et1"}
+! HLFIR: return
+! HLFIR: }
end subroutine
end module m_struct_ctor
diff --git a/flang/test/Semantics/structconst08.f90 b/flang/test/Semantics/structconst08.f90
index 211b0e79bf5e44..149c898dda9d4d 100644
--- a/flang/test/Semantics/structconst08.f90
+++ b/flang/test/Semantics/structconst08.f90
@@ -18,40 +18,55 @@ module m
subroutine test1()
integer :: j
real :: arr(5)
+ integer, pointer :: ipp
+ real, pointer :: rpp(:)
!ERROR: Must be a constant value
type(parent1) :: tp1 = parent1(3)
!ERROR: Must be a constant value
type(parent1) :: tp2 = parent1(j)
type(parent1) :: tp3 = parent1(null())
+!PORTABILITY: NULL() with arguments is not standard conforming as the value for allocatable component 'pa'
+ type(parent1) :: tp4 = parent1(null(ipp))
!ERROR: Must be a constant value
- type(parent2) :: tp4 = parent2([1.1,2.1,3.1])
+ type(parent2) :: tp5 = parent2([1.1,2.1,3.1])
!ERROR: Must be a constant value
- type(parent2) :: tp5 = parent2(arr)
- type(parent2) :: tp6 = parent2(null())
+ type(parent2) :: tp6 = parent2(arr)
+ type(parent2) :: tp7 = parent2(null())
+!PORTABILITY: NULL() with arguments is not standard conforming as the value for allocatable component 'pa'
+ type(parent2) :: tp8 = parent2(null(rpp))
end subroutine test1
subroutine test2()
integer :: j
real :: arr(5)
+ integer, pointer :: ipp
+ real, pointer :: rpp(:)
type(parent1) :: tp1
type(parent2) :: tp2
tp1 = parent1(3)
tp1 = parent1(j)
tp1 = parent1(null())
+!PORTABILITY: NULL() with arguments is not standard conforming as the value for allocatable component 'pa'
+ tp1 = parent1(null(ipp))
tp2 = parent2([1.1,2.1,3.1])
tp2 = parent2(arr)
tp2 = parent2(null())
+!PORTABILITY: NULL() with arguments is not standard conforming as the value for allocatable component 'pa'
+ tp2 = parent2(null(rpp))
end subroutine test2
subroutine test3()
+ real, pointer :: pp(:)
type(child) :: tc1 = child(5, parent2(null()))
+!PORTABILITY: NULL() with arguments is not standard conforming as the value for allocatable component 'pa'
+ type(child) :: tc10 = child(5, parent2(null(pp)))
!ERROR: Must be a constant value
- type(child) :: tc2 = child(5, parent2([1.1,1.2]))
- type(child) :: tc3
+ type(child) :: tc3 = child(5, parent2([1.1,1.2]))
+ type(child) :: tc4
- tc3 = child(5, parent2(null()))
- tc3 = child(5, parent2([1.1,1.2]))
+ tc4 = child(5, parent2(null()))
+ tc4 = child(5, parent2([1.1,1.2]))
end subroutine test3
end module m
>From 9fa5d4f939ec890088f2bdd59719154176b65cb3 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Mon, 15 Jan 2024 21:45:48 -0500
Subject: [PATCH 4/4] fix format
---
flang/lib/Lower/ConvertConstant.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp
index 756eab6da49531..336944d35b7e4a 100644
--- a/flang/lib/Lower/ConvertConstant.cpp
+++ b/flang/lib/Lower/ConvertConstant.cpp
@@ -365,7 +365,8 @@ static mlir::Value genStructureComponentInit(
if (Fortran::semantics::IsAllocatable(sym)) {
if (!Fortran::evaluate::IsNullPointer(expr)) {
- fir::emitFatalError(loc, "constant structure constructor with an allocatable component value that is not NULL");
+ fir::emitFatalError(loc, "constant structure constructor with an "
+ "allocatable component value that is not NULL");
} else {
// Handle NULL() initialization
mlir::Value componentValue{fir::factory::createUnallocatedBox(
More information about the flang-commits
mailing list