diff options
author | jeanPerier <jperier@nvidia.com> | 2024-01-19 15:09:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-19 15:09:25 +0100 |
commit | eaa8def929b17ea4c7a13a7bf860ac07bfd5bf14 (patch) | |
tree | bdc94a48a936c80d71c41a644fc94bf49c42b825 | |
parent | 836dcdb84ab91aa2b69a6cec412d83c840a7196d (diff) | |
download | llvm-eaa8def929b17ea4c7a13a7bf860ac07bfd5bf14.zip llvm-eaa8def929b17ea4c7a13a7bf860ac07bfd5bf14.tar.gz llvm-eaa8def929b17ea4c7a13a7bf860ac07bfd5bf14.tar.bz2 |
[flang] Expand parent component in procedure pointer component ref (#78593)
For simplicity, lowering relies on semantics expansion of parent
components in designators.
This was not done in `call x%p()` where `p` is a procedure component
pointer of a parent component of `x`.
Do it and turn lowering TODO into a new lowering TODO for `call bar(x%type_bound_procedure)` (passing a tybe bound procedure is allowed as an extension, but lowering does not handle this extension yet. This is a lowering issue, will do in different patch).
-rw-r--r-- | flang/include/flang/Semantics/expression.h | 4 | ||||
-rw-r--r-- | flang/lib/Lower/ConvertProcedureDesignator.cpp | 6 | ||||
-rw-r--r-- | flang/lib/Semantics/expression.cpp | 25 | ||||
-rw-r--r-- | flang/test/Lower/HLFIR/proc-pointer-comp-in-parent.f90 | 30 |
4 files changed, 53 insertions, 12 deletions
diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h index 790d0a4d..a330e24 100644 --- a/flang/include/flang/Semantics/expression.h +++ b/flang/include/flang/Semantics/expression.h @@ -327,8 +327,8 @@ private: const parser::SectionSubscript &); std::vector<Subscript> AnalyzeSectionSubscripts( const std::list<parser::SectionSubscript> &); - std::optional<Component> CreateComponent( - DataRef &&, const Symbol &, const semantics::Scope &); + std::optional<Component> CreateComponent(DataRef &&, const Symbol &, + const semantics::Scope &, bool C919bAlreadyEnforced = false); MaybeExpr CompleteSubscripts(ArrayRef &&); MaybeExpr ApplySubscripts(DataRef &&, std::vector<Subscript> &&); void CheckConstantSubscripts(ArrayRef &); diff --git a/flang/lib/Lower/ConvertProcedureDesignator.cpp b/flang/lib/Lower/ConvertProcedureDesignator.cpp index 0806f78..2446be3 100644 --- a/flang/lib/Lower/ConvertProcedureDesignator.cpp +++ b/flang/lib/Lower/ConvertProcedureDesignator.cpp @@ -113,10 +113,10 @@ static hlfir::EntityWithAttributes designateProcedurePointerComponent( auto recordType = hlfir::getFortranElementType(base.getType()).cast<fir::RecordType>(); mlir::Type fieldType = recordType.getType(fieldName); - // FIXME: semantics is not expanding intermediate parent components in: - // call x%p() where p is a component of a parent type of x type. + // Note: semantics turns x%p() into x%t%p() when the procedure pointer + // component is part of parent component t. if (!fieldType) - TODO(loc, "reference to procedure pointer component from parent type"); + TODO(loc, "passing type bound procedure (extension)"); mlir::Type designatorType = fir::ReferenceType::get(fieldType); mlir::Value compRef = builder.create<hlfir::DesignateOp>( loc, designatorType, base, fieldName, diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index bfc3801..44e16ac 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -1296,9 +1296,11 @@ static NamedEntity IgnoreAnySubscripts(Designator<SomeDerived> &&designator) { } // Components of parent derived types are explicitly represented as such. -std::optional<Component> ExpressionAnalyzer::CreateComponent( - DataRef &&base, const Symbol &component, const semantics::Scope &scope) { - if (IsAllocatableOrPointer(component) && base.Rank() > 0) { // C919b +std::optional<Component> ExpressionAnalyzer::CreateComponent(DataRef &&base, + const Symbol &component, const semantics::Scope &scope, + bool C919bAlreadyEnforced) { + if (!C919bAlreadyEnforced && IsAllocatableOrPointer(component) && + base.Rank() > 0) { // C919b Say("An allocatable or pointer component reference must be applied to a scalar base"_err_en_US); } if (&component.owner() == &scope) { @@ -1313,7 +1315,7 @@ std::optional<Component> ExpressionAnalyzer::CreateComponent( parentType->derivedTypeSpec().scope()}) { return CreateComponent( DataRef{Component{std::move(base), *parentComponent}}, - component, *parentScope); + component, *parentScope, C919bAlreadyEnforced); } } } @@ -2391,9 +2393,18 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef( ProcedureDesignator{*resolution}, std::move(arguments)}; } else if (dataRef.has_value()) { if (sym->attrs().test(semantics::Attr::NOPASS)) { - return CalleeAndArguments{ - ProcedureDesignator{Component{std::move(*dataRef), *sym}}, - std::move(arguments)}; + const auto *dtSpec{GetDerivedTypeSpec(dtExpr->GetType())}; + if (dtSpec && dtSpec->scope()) { + if (auto component{CreateComponent(std::move(*dataRef), *sym, + *dtSpec->scope(), /*C919bAlreadyEnforced=*/true)}) { + return CalleeAndArguments{ + ProcedureDesignator{std::move(*component)}, + std::move(arguments)}; + } + } + Say(sc.component.source, + "Component is not in scope of base derived type"_err_en_US); + return std::nullopt; } else { AddPassArg(arguments, Expr<SomeDerived>{Designator<SomeDerived>{std::move(*dataRef)}}, diff --git a/flang/test/Lower/HLFIR/proc-pointer-comp-in-parent.f90 b/flang/test/Lower/HLFIR/proc-pointer-comp-in-parent.f90 new file mode 100644 index 0000000..5b37b6a --- /dev/null +++ b/flang/test/Lower/HLFIR/proc-pointer-comp-in-parent.f90 @@ -0,0 +1,30 @@ +! Test that parent components are made explicit in reference to +! procedure pointer from parent type. +! RUN: bbc -emit-hlfir -o - %s | FileCheck %s + +module type_defs + interface + subroutine s1 + end subroutine + real function s2() + end function + end interface + type :: t + procedure(s1), pointer, nopass :: p1 + procedure(s2), pointer, nopass :: p2 + end type + type, extends(t) :: t2 + end type +end module + +! CHECK-LABEL: func.func @_QPtest( +subroutine test (x) +use type_defs, only : t2 +type(t2) :: x +call x%p1() +! CHECK: %[[T_REF1:.*]] = hlfir.designate %{{.*}}{"t"} +! CHECK: hlfir.designate %[[T_REF1]]{"p1"} +print *, x%p2() +! CHECK: %[[T_REF2:.*]] = hlfir.designate %{{.*}}{"t"} +! CHECK: hlfir.designate %[[T_REF2]]{"p2"} +end subroutine |