Skip to content

Commit d1f5d42

Browse files
committed
[flang] Enforce F'2023 C15121
No specification expression in the declaration of the result variable of an elemental function may depend on the value of a dummy argument. This ensures that all of the results have the same type when the elemental function is applied to the elements of an array.
1 parent 2e0e163 commit d1f5d42

File tree

3 files changed

+71
-39
lines changed

3 files changed

+71
-39
lines changed

flang/lib/Semantics/check-declarations.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,31 @@ void CheckHelper::Check(
243243
}
244244
}
245245

246+
// Checks an elemental function result type parameter specification
247+
// expression for an unacceptable use of a dummy argument.
248+
class BadDummyChecker : public evaluate::AnyTraverse<BadDummyChecker, bool> {
249+
public:
250+
using Base = evaluate::AnyTraverse<BadDummyChecker, bool>;
251+
BadDummyChecker(parser::ContextualMessages &messages, const Scope &scope)
252+
: Base{*this}, messages_{messages}, scope_{scope} {}
253+
using Base::operator();
254+
bool operator()(const evaluate::DescriptorInquiry &) {
255+
return false; // shield base() of inquiry from further checking
256+
}
257+
bool operator()(const Symbol &symbol) {
258+
if (&symbol.owner() == &scope_ && IsDummy(symbol)) {
259+
messages_.Say(
260+
"Specification expression for elemental function result may not depend on dummy argument '%s''s value"_err_en_US,
261+
symbol.name());
262+
}
263+
return false;
264+
}
265+
266+
private:
267+
parser::ContextualMessages &messages_;
268+
const Scope &scope_;
269+
};
270+
246271
void CheckHelper::Check(const Symbol &symbol) {
247272
if (symbol.name().size() > common::maxNameLen &&
248273
&symbol == &symbol.GetUltimate()) {
@@ -378,24 +403,31 @@ void CheckHelper::Check(const Symbol &symbol) {
378403
} else {
379404
Check(*type, canHaveAssumedParameter);
380405
}
381-
if (InPure() && InFunction() && IsFunctionResult(symbol)) {
382-
if (type->IsPolymorphic() && IsAllocatable(symbol)) { // C1585
383-
messages_.Say(
384-
"Result of pure function may not be both polymorphic and ALLOCATABLE"_err_en_US);
385-
}
386-
if (derived) {
387-
// These cases would be caught be the general validation of local
388-
// variables in a pure context, but these messages are more specific.
389-
if (HasImpureFinal(symbol)) { // C1584
406+
if (InFunction() && IsFunctionResult(symbol)) {
407+
if (InPure()) {
408+
if (type->IsPolymorphic() && IsAllocatable(symbol)) { // C1585
390409
messages_.Say(
391-
"Result of pure function may not have an impure FINAL subroutine"_err_en_US);
410+
"Result of pure function may not be both polymorphic and ALLOCATABLE"_err_en_US);
392411
}
393-
if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) {
394-
SayWithDeclaration(*bad,
395-
"Result of pure function may not have polymorphic ALLOCATABLE ultimate component '%s'"_err_en_US,
396-
bad.BuildResultDesignatorName());
412+
if (derived) {
413+
// These cases would be caught be the general validation of local
414+
// variables in a pure context, but these messages are more specific.
415+
if (HasImpureFinal(symbol)) { // C1584
416+
messages_.Say(
417+
"Result of pure function may not have an impure FINAL subroutine"_err_en_US);
418+
}
419+
if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) {
420+
SayWithDeclaration(*bad,
421+
"Result of pure function may not have polymorphic ALLOCATABLE ultimate component '%s'"_err_en_US,
422+
bad.BuildResultDesignatorName());
423+
}
397424
}
398425
}
426+
if (InElemental() && isChar) { // F'2023 C15121
427+
BadDummyChecker{messages_, symbol.owner()}(
428+
type->characterTypeSpec().length().GetExplicit());
429+
// TODO: check PDT LEN parameters
430+
}
399431
}
400432
}
401433
if (IsAssumedLengthCharacter(symbol) && IsFunction(symbol)) { // C723

flang/test/Lower/HLFIR/elemental-result-length.f90

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ elemental function fct1(a, b) result(t)
88
t = a // b
99
end function
1010

11-
elemental function fct2(c) result(t)
12-
integer, intent(in) :: c
13-
character(c) :: t
14-
15-
end function
16-
1711
subroutine sub2(a,b,c)
1812
character(*), intent(inout) :: c
1913
character(*), intent(in) :: a, b
@@ -42,25 +36,6 @@ subroutine sub2(a,b,c)
4236
! CHECK: %[[RES:.*]] = fir.alloca !fir.char<1,?>(%[[RES_LENGTH]] : index) {bindc_name = ".result"}
4337
! CHECK: fir.call @_QMm1Pfct1
4438

45-
subroutine sub3(c)
46-
character(*), intent(inout) :: c(:)
47-
48-
c = fct2(10)
49-
end subroutine
50-
51-
! CHECK-LABEL: func.func @_QMm1Psub3(
52-
! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>> {fir.bindc_name = "c"}) {
53-
! CHECK: %[[C10:.*]] = arith.constant 10 : i32
54-
! CHECK: %[[C:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs<intent_inout>, uniq_name = "_QMm1Fsub3Ec"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
55-
! CHECK: %[[ASSOC:.*]]:3 = hlfir.associate %[[C10]] {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
56-
! CHECK: %[[INPUT_ARG0:.*]]:2 = hlfir.declare %[[ASSOC]]#1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMm1Ffct2Ec"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
57-
! CHECK: %[[LOAD_INPUT_ARG0:.*]] = fir.load %[[INPUT_ARG0]]#0 : !fir.ref<i32>
58-
! CHECK: %[[LOAD_INPUT_ARG0_IDX:.*]] = fir.convert %[[LOAD_INPUT_ARG0]] : (i32) -> index
59-
! CHECK: %[[CMPI:.*]] = arith.cmpi sgt, %[[LOAD_INPUT_ARG0_IDX]], %c0{{.*}} : index
60-
! CHECK: %[[LENGTH:.*]] = arith.select %[[CMPI]], %[[LOAD_INPUT_ARG0_IDX]], %c0{{.*}} : index
61-
! CHECK: %[[RES:.*]] = fir.alloca !fir.char<1,?>(%[[LENGTH]] : index) {bindc_name = ".result"}
62-
! CHECK: fir.call @_QMm1Pfct2
63-
6439
subroutine sub4(a,b,c)
6540
character(*), intent(inout) :: c(:)
6641
character(*), intent(in) :: a(:), b(:)

flang/test/Semantics/elemental01.f90

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,28 @@ elemental function ptrf(n)
4747
!ERROR: The result of an ELEMENTAL function may not be a POINTER
4848
real, pointer :: ptrf
4949
end function
50+
51+
module m
52+
integer modvar
53+
type t
54+
character(:), allocatable :: c
55+
end type
56+
contains
57+
!ERROR: Specification expression for elemental function result may not depend on dummy argument 'n''s value
58+
elemental character(n) function bad1(n)
59+
integer, intent(in) :: n
60+
end
61+
!ERROR: Specification expression for elemental function result may not depend on dummy argument 'x''s value
62+
elemental character(x%c%len) function bad2(x)
63+
type(t), intent(in) :: x
64+
end
65+
elemental character(len(x)) function ok1(x) ! ok
66+
character(*), intent(in) :: x
67+
end
68+
elemental character(modvar) function ok2(x) ! ok
69+
character(*), intent(in) :: x
70+
end
71+
elemental character(len(x)) function ok3(x) ! ok
72+
character(modvar), intent(in) :: x
73+
end
74+
end

0 commit comments

Comments
 (0)