Hi Yuao,
Yuao Ma wrote:
Hi Paul,
On 7/31/2025 6:02 AM, Paul Richard Thomas wrote:
That's exactly how I had a mind to do it. You beat me to it 🙁
Just get on, polish the patch and add more tests.
I've updated the patch with improvements to both the functionality and
test cases. It should now work well for simple scalar types.
However, I've found that the issue is more complex than I initially
thought. The current implementation causes an ICE with character and
array types. It seems that we need to handle EXPR_CONDITIONAL every
time we switch against an expr's type, and a quick search shows that
there are many instances of this.
I'm wondering if we could create separate, incremental patches for
this. For example, in this patch, we could deny other complex types in
the resolution process and gradually relax that constraint in future
patches.
IMHO that's fine. We use "gfc_error ("Sorry, … is not yet supported")" in
gfortran for this.
We might want to file Bugzilla problem report in order to track this to avoid
that it falls
through the cracks, unless the follow up patches are expected to arrive soon.
* * *
Build fails with:
fortran/module.cc: In function ‘void mio_expr(gfc_expr**)’:
fortran/module.cc:3773:10: error: enumeration value ‘EXPR_CONDITIONAL’ not
handled in switch [-Werror=switch]
3773 | switch (e->expr_type)
| ^
fortran/trans-expr.cc: In function ‘void
gfc_apply_interface_mapping_to_expr(gfc_interface_mapping*, gfc_expr*)’:
fortran/trans-expr.cc:5338:10: error: enumeration value ‘EXPR_CONDITIONAL’ not
handled in switch [-Werror=switch]
5338 | switch (expr->expr_type)
* * *
But there are more, e.g. gfc_walk_subexpr
* * *
+static bool
+simplify_conditional (gfc_expr *p, int type)
+{
…
+ p->value.conditional.condition = NULL;
+ p->value.conditional.true_expr = NULL;
+ p->value.conditional.false_expr = NULL;
+
+ if (condition->value.logical)
+ gfc_replace_expr (p, true_expr);
+ else
+ gfc_replace_expr (p, false_expr);
This looks like a memory leak. I think you need to
call gfc_free_expr for condition and for
either false_expr or true_expr.
* * *
Ignoring the issue of the array (segfault in scalarizer),
a check that the condition is a scalar (logical) expression is
missing:
implicit none
logical :: ll(2)
integer :: A(1)
integer :: B(2,3)
print *, (ll ? A : B(:,1))
Possibly a copy and paste error? Because you check twice for BT_LOGICAL.
* * *
Regarding the diagnostic:
6 | print *, (ll ? A : .true. ? B(:,1) : 5)
| 1
Error: True and false expressions in conditional expression must have the same
rank at (1)
Talking about the location, I wonder whether
the expr->where should be not the beginning of the expr,
i.e. 'll' for the outer and the leftmost ':' for the inner
conditional, but at the (respective) '?'.
Additionally, I wonder whether in
+ gfc_error ("True and false expressions in conditional expression "
+ "must have the same declared type at %L",
+ &expr->where);
the '&expr->where' should be replaced by:
gfc_get_location_range (NULL, 0, &true_expr->where,0, &false_expr->where, 0)
[gfc_get_location_range can also be used in general, which C++ does;
albeit there is a small overhead doing so.
The output is "~~~~~(1)~~~~~" where ~~~~~ extends from begin to end and
(1) it placed at the caret position.]
* * *
Regarding: resolve_conditional
There needs to be also a check for parameterized derived types (PDT) that their
kind argument is the same.
I guess this can be done later, but that would be another SORRY case.
And, in general, for derived types ('TYPE', 'CLASS'), it must be the same
derived, type. I think for the beginning, rejecting those are fine.
It seems as we also need to check for a matching cor
* * *
print *, 2 > 3 ? 3 : 2
I believe this is invalid but it is currently accepted. Fortran seems to
require the enclosing "(...)" in this case:
R1002 conditional-expr is ( scalar-logical-expr ? expr [ : scalar-logical-expr
? expr ]... : expr )
But Fortran does not seem to require it for inner conditional expressions
in the 'else' branch:
print *, ( i>j ? i : j > k ? k) ! OK
print *, ( i>j ? j > k ? j : k : m ) ! invalid
print *, ( i>j ? (j > k ? j : k) : m ) ! OK
* * *
NOTE: That as actual argument, the following is valid:
subroutine five(x)
integer, optional :: x
if (present(x)) X = 5
end
integer :: a, b
a = 4
call five( ( a < 5 ? a : b) )
call five( ( a < 5 ? a : .nil.) )
Note the 'nil' and that the arguments have to be passed by reference!
That's then:
R1526 conditional-arg
is ( scalar-logical-expr ? consequent
[ : scalar-logical-expr ? consequent ]... : consequent )
R1527 consequent is consequent-arg
or .NIL.
R1528 consequent-arg is expr or variable
If it is a variable, as in my example above, it can be assigned to,
otherwise not - but mixing the two is fine as long as at runtime
one never assigns to the an expression.
We don't need to handle this completely, but I guess we want to prepare
the handling of conditional-arg when adding the conditional-expr support.
See also "US 22. Conditional expressions and arguments" in
"The new features of Fortran 202x" by John Reid,
https://wg5-fortran.org/N2201-N2250/N2212.pdf
* * *
Thanks for the draft and sorry for the very late response. Having
a visitor + vacation (not alone) + a cold did not really help :-(
Tobias