diff --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h --- a/flang/include/flang/Semantics/scope.h +++ b/flang/include/flang/Semantics/scope.h @@ -104,7 +104,10 @@ bool IsParameterizedDerivedTypeInstantiation() const { return kind_ == Kind::DerivedType && !symbol_; } + /// Does this derived type have at least one kind parameter ? bool IsDerivedTypeWithKindParameter() const; + /// Does this derived type have at least one length parameter ? + bool IsDerivedTypeWithLengthParameter() const; Symbol *symbol() { return symbol_; } const Symbol *symbol() const { return symbol_; } SemanticsContext &context() const { return context_; } diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -765,8 +765,9 @@ return true; if (const Fortran::semantics::DerivedTypeSpec *derived = Fortran::evaluate::GetDerivedTypeSpec(obj.type.type())) - // Need to pass type parameters in fir.box if any. - return derived->parameters().empty(); + if (const Fortran::semantics::Scope *scope = derived->scope()) + // Need to pass length type parameters in fir.box if any. + return scope->IsDerivedTypeWithLengthParameter(); return false; } diff --git a/flang/lib/Semantics/scope.cpp b/flang/lib/Semantics/scope.cpp --- a/flang/lib/Semantics/scope.cpp +++ b/flang/lib/Semantics/scope.cpp @@ -357,35 +357,32 @@ return symbol_ && symbol_->test(Symbol::Flag::StmtFunction); } -bool Scope::IsParameterizedDerivedType() const { - if (!IsDerivedType()) { - return false; - } - if (const Scope * parent{GetDerivedTypeParent()}) { - if (parent->IsParameterizedDerivedType()) { - return true; - } - } - for (const auto &pair : symbols_) { - if (pair.second->has()) { - return true; - } +template struct IsTypeParamHelper { + static_assert(sizeof...(ParamAttr) == 0, "must have one or zero template"); + static bool IsParam(const Symbol &symbol) { + return symbol.has(); } - return false; -} +}; -bool Scope::IsDerivedTypeWithKindParameter() const { - if (!IsDerivedType()) { +template struct IsTypeParamHelper { + static bool IsParam(const Symbol &symbol) { + if (const auto *typeParam{symbol.detailsIf()}) { + return typeParam->attr() == ParamAttr; + } return false; } - if (const Scope * parent{GetDerivedTypeParent()}) { - if (parent->IsDerivedTypeWithKindParameter()) { - return true; +}; + +template +static bool IsParameterizedDerivedTypeHelper(const Scope &scope) { + if (scope.IsDerivedType()) { + if (const Scope * parent{scope.GetDerivedTypeParent()}) { + if (IsParameterizedDerivedTypeHelper(*parent)) { + return true; + } } - } - for (const auto &pair : symbols_) { - if (const auto *typeParam{pair.second->detailsIf()}) { - if (typeParam->attr() == common::TypeParamAttr::Kind) { + for (const auto &nameAndSymbolPair : scope) { + if (IsTypeParamHelper::IsParam(*nameAndSymbolPair.second)) { return true; } } @@ -393,6 +390,16 @@ return false; } +bool Scope::IsParameterizedDerivedType() const { + return IsParameterizedDerivedTypeHelper<>(*this); +} +bool Scope::IsDerivedTypeWithLengthParameter() const { + return IsParameterizedDerivedTypeHelper(*this); +} +bool Scope::IsDerivedTypeWithKindParameter() const { + return IsParameterizedDerivedTypeHelper(*this); +} + const DeclTypeSpec *Scope::FindInstantiatedDerivedType( const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const { DeclTypeSpec type{category, spec}; diff --git a/flang/test/Lower/default-initialization.f90 b/flang/test/Lower/default-initialization.f90 --- a/flang/test/Lower/default-initialization.f90 +++ b/flang/test/Lower/default-initialization.f90 @@ -75,11 +75,12 @@ ! Test that optional intent(out) are default initialized only when ! present. ! CHECK-LABEL: func @_QMtest_dinitPintent_out_optional( - ! CHECK-SAME: %[[x:.*]]: !fir.box> {fir.bindc_name = "x", fir.optional}) + ! CHECK-SAME: %[[x:.*]]: !fir.ref> {fir.bindc_name = "x", fir.optional}) subroutine intent_out_optional(x) - ! CHECK: %[[isPresent:.*]] = fir.is_present %[[x]] : (!fir.box>) -> i1 + ! CHECK: %[[isPresent:.*]] = fir.is_present %[[x]] : (!fir.ref>) -> i1 ! CHECK: fir.if %[[isPresent]] { - ! CHECK: %[[xboxNone:.*]] = fir.convert %[[x]] + ! CHECK: %[[xbox:.*]] = fir.embox %[[x]] : (!fir.ref>) -> !fir.box> + ! CHECK: %[[xboxNone:.*]] = fir.convert %[[xbox]] ! CHECK: fir.call @_FortranAInitialize(%[[xboxNone]], %{{.*}}, %{{.*}}) : (!fir.box, !fir.ref, i32) -> none ! CHECK: } type(t), intent(out), optional :: x diff --git a/flang/test/Lower/dummy-argument-derived.f90 b/flang/test/Lower/dummy-argument-derived.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/dummy-argument-derived.f90 @@ -0,0 +1,116 @@ +! Test lowering of derived type dummy arguments +! RUN: bbc -emit-fir %s -o - | FileCheck %s +module type_defs + type simple_type + integer :: i + end type + type with_kind(k) + integer, kind :: k + real(k) :: x + end type +end module + +! ----------------------------------------------------------------------------- +! Test passing of derived type arguments that do not require a +! fir.box (runtime descriptor). +! ----------------------------------------------------------------------------- + +! Test simple type scalar with no attribute. +! CHECK-LABEL: func @_QPtest1( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "a"}) { +subroutine test1(a) + use type_defs + type(simple_type) :: a +end subroutine + +! Test simple type explicit array with no attribute. +! CHECK-LABEL: func @_QPtest2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>> {fir.bindc_name = "a"}) { +subroutine test2(a) + use type_defs + type(simple_type) :: a(100) +end subroutine + +! Test simple type scalar with TARGET attribute. +! CHECK-LABEL: func @_QPtest3( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "a", fir.target}) { +subroutine test3(a) + use type_defs + type(simple_type), target :: a +end subroutine + +! Test simple type explicit array with TARGET attribute. +! CHECK-LABEL: func @_QPtest4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>> {fir.bindc_name = "a", fir.target}) { +subroutine test4(a) + use type_defs + type(simple_type), target :: a(100) +end subroutine + +! Test kind parametrized derived type scalar with no attribute. +! CHECK-LABEL: func @_QPtest1k( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "a"}) { +subroutine test1k(a) + use type_defs + type(with_kind(4)) :: a +end subroutine + +! Test kind parametrized derived type explicit array with no attribute. +! CHECK-LABEL: func @_QPtest2k( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>> {fir.bindc_name = "a"}) { +subroutine test2k(a) + use type_defs + type(with_kind(4)) :: a(100) +end subroutine + +! Test kind parametrized derived type scalar with TARGET attribute. +! CHECK-LABEL: func @_QPtest3k( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "a", fir.target}) { +subroutine test3k(a) + use type_defs + type(with_kind(4)), target :: a +end subroutine + +! Test kind parametrized derived type explicit array with TARGET attribute. +! CHECK-LABEL: func @_QPtest4k( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>> {fir.bindc_name = "a", fir.target}) { +subroutine test4k(a) + use type_defs + type(with_kind(4)), target :: a(100) +end subroutine + +! ----------------------------------------------------------------------------- +! Test passing of derived type arguments that require a fir.box (runtime descriptor). +! ----------------------------------------------------------------------------- + +! Test simple type assumed shape array with no attribute. +! CHECK-LABEL: func @_QPtest5( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a"}) { +subroutine test5(a) + use type_defs + type(simple_type) :: a(:) +end subroutine + +! Test simple type assumed shape array with TARGET attribute. +! CHECK-LABEL: func @_QPtest6( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a", fir.target}) { +subroutine test6(a) + use type_defs + type(simple_type), target :: a(:) +end subroutine + +! Test kind parametrized derived type assumed shape array with no attribute. +! CHECK-LABEL: func @_QPtest5k( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a"}) { +subroutine test5k(a) + use type_defs + type(with_kind(4)) :: a(:) +end subroutine + +! Test kind parametrized derived type assumed shape array with TARGET attribute. +! CHECK-LABEL: func @_QPtest6k( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a", fir.target}) { +subroutine test6k(a) + use type_defs + type(with_kind(4)), target :: a(:) +end subroutine