Hi Tobias, On Mon, Sep 8, 2025 at 10:54 PM Tobias Burnus <[email protected]> wrote: > * * * > > >>> + if (true_expr->rank != false_expr->rank) > >>> + { > >>> + gfc_error ("true_expr at %L and false_expr at %L in conditional " > >>> + "expression must have the same rank", > >>> + &true_expr->where, &false_expr->where); > >>> + return false; > >>> + } > >> I wonder whether 'true_expr' / 'false_expr' are the best wording; Fortran > >> itself just has: > >> > >> "R1002 conditional-expr is ( scalar-logical-expr ? expr > >> [ : scalar-logical-expr ? expr ]... : expr ) > >> "C1004 Each expr of a conditional-expr shall have the same declared type, > >> kind > >> type parameters, and rank." > >> > >> and > >> > >> "Evaluation of a conditional-expr evaluates each scalar-logical-expr in > >> order, until the value of a scalar-logical-expr is true, or there are > >> no more scalar-logical-exprs. If the value of a scalar-logical-expr is > >> true, its subsequent expr is chosen; otherwise, the last expr of the > >> conditional-expr is chosen. The chosen expr is evaluated, and its > >> value is the value of the conditional expression." > >> > >> I wonder whether we shouldn't just use 'expr' without true_/false_ > >> prefix; I am especially stumbling over the underscore but also > >> "true/false expr" sounds a bit odd. > > I'm open to different naming. In the GCC C frontend, the > > build_conditional_expr function uses op1 and op2, while the Clang AST > > uses an expression array with COND, LHS, and RHS > > Note: I am not talking about the internal name - I am totally fine with > true_expr and false_expr. > > I am talking about the wording presented to the Fortran user, who > will see the compiler error message. > > Thus, "+ if (true_expr->rank != false_expr->rank)" is perfectly fine > with me. > > But instead of: > > Error: true_expr at (1) and false_expr at (2) in conditional expression must > have the same rank > > I wonder whether it would be more Fortran like (without loosing > information) to say: > > Error: expr at (1) and expr at (2) in conditional expression must have the > same rank > > > which avoids the underscore and true/false prefix. >
Yeah, that makes sense. Fixed. > * * * > > BTW, just thinking about it: When simplifying, I wonder > whether we want to have a special case for > cond ? expr1 : expr1 > > Namely, condition is only known at runtime but both expressions are > identically? I think gfc_dep_compare_expr (...) == 0 does this. > (If you add it, please re-check that my claim is correct.) > It seems like a good optimization to me. However, our current implementation already seems to have this capability. When I attempt to use `i > 0 ? j : j` and view the output using dump-tree-original, I only see `i = j`. My initial assumption is that COND_EXPR will perform this transformation for simple scalar types that we currently support. I believe we will need this optimization for future complex types, so perhaps we should hold this until we actually need this part. For gfc_dep_compare_expr, yes returning 0 indicates that the two expressions are identical. > * * * > > > I'm not sure if I'm understanding you correctly here. Are you > > suggesting we treat the conditional expression as a special case for > > EXPR_OP (the ternary operator)? > > My initial thought, which isn't fully developed, is to store a nullptr > > for the nil in the AST. However, this would require a null check every > > time we use the true/false expr... > > Not as ternery operator, only for .NIL.: > > I was wondering about .NIL. as an operator that takes 0 expressions > with it - contrary to .NOT. that takes one (unary) and .AND. that takes > two (binary). - I got the idea because of the '.<something>.' it looks > very much like an operator and fits into the parser for operators. > > But I have not thought whether that has additional implications or > how many code changes it requires. > > Your idea of using nullptr is also interesting - and at a first glance, > should work. On the second thought, wouldn't this have issues (a) for > the diagnostic if gfc_expr == nullptr as there is also no expr->where > in that case. Additionally, (b) condition is known at compile time, > the might simplify to nullptr - which has issues. Having a special > case for EXPR_CONDITIONAL is fine - as it is localized, but adding > it elsewhere is a problem, especially as we already have several > null values in Fortran: > > At least null(), c_null_ptr, and c_null_funptr come into my mind. > And '(cond ? c_null_ptr : .nil.)' looks like a valid expression, > depending on the associated dummy argument. > > If you can get it working, having a nullptr for .NIL. works for me, > but I fear it won't work out and (too) many hacks are required. > > > But I am not sure whether there is a better third solution or whether > we can get one of the two ideas (.NIL. as EXPR_OP or as nullptr working). > Yeah, you convinced me. Just using a nullptr doesn't seem to work. I came up with another idea: using a gfc_expr with type EXPR_CONDITIONAL and a condition of nullptr (actually cond/true/false could all be nullptr). For any valid cond-expr, the condition must be a valid scalar-logical-expr. So using a nullptr cond to indicate a .NIL. seems safe. It is also localized, no need to touch the EXPR_OP part. Not sure if this will have any bad case, though. * * * BTW, the newly attached patch has a properly wrapped commit message : ) Thanks, Yuao
0001-fortran-implement-conditional-expression-for-fortran.patch
Description: Binary data
