Hi! The following testcase ICEs starting with the removal of NON_DEPENDENT_EXPR in GCC 14. The problem is that while parsing templates if all the arguments of the overloaded builtins are non-dependent types, targetm.resolve_overloaded_builtin can be called on it. And trying to fold_convert or fold_build2 subexpressions of such arguments can ICE, because they can contain various FE specific trees, or standard trees with NULL_TREE types, or e.g. type mismatches in binary tree operands etc. All that goes away later when the trees are instantiated and targetm.resolve_overloaded_builtin is called again, but if it ICEs while doing that, it won't reach that point. And the reason to call that hook in that case if none of the arguments are type dependent is to figure out if the result type is also non-dependent.
Given the general desire to fold stuff in the FE during parsing as little as possible and fold it only during cp_fold later on and because from the target *-c.cc files it isn't easily possible to find out if it is processing_template_decl or not, the following patch just stops folding anything in the arguments, calls convert instead of fold_convert and just build2 instead of fold_build2 etc. when in C++ (and keeps doing what it did for C). Bootstrapped/regtested on powerpc64le-linux, ok for trunk? 2026-02-18 Jakub Jelinek <[email protected]> PR target/124133 * config/rs6000/rs6000-c.cc (c_fold_convert): New function. (c_fold_build2_loc): Likewise. (fully_fold_convert): Use c_fold_convert instead of fold_convert. (altivec_build_resolved_builtin): Likewise. Use c_fold_build2_loc instead of fold_build2. (resolve_vec_mul, resolve_vec_adde_sube, resolve_vec_addec_subec): Use c_fold_build2_loc instead of fold_build2_loc. (resolve_vec_splats, resolve_vec_extract): Use c_fold_convert instead of fold_convert. (resolve_vec_insert): Use c_fold_build2_loc instead of fold_build2. (altivec_resolve_overloaded_builtin): Use c_fold_convert instead of fold_convert. * g++.target/powerpc/pr124133.C: New test. --- gcc/config/rs6000/rs6000-c.cc.jj 2026-01-02 09:56:10.067338205 +0100 +++ gcc/config/rs6000/rs6000-c.cc 2026-02-17 16:47:03.466183542 +0100 @@ -835,14 +835,40 @@ rs6000_builtin_type_compatible (tree par return lang_hooks.types_compatible_p (parmtype, argtype); } -/* In addition to calling fold_convert for EXPR of type TYPE, also +/* Return fold_convert (TYPE, EXPR) for C and convert (TYPE, EXPR) + for C++. The latter is needed because resolve_overloaded_builtin + can be called when parsing templates too if they don't have type + dependent operands, but the nested trees might not be usable in + GENERIC folding. */ + +static tree +c_fold_convert (tree type, tree expr) +{ + return c_dialect_cxx () ? convert (type, expr) : fold_convert (type, expr); +} + +/* Similar wrapper for fold_build2_loc. For C++ just call build2_loc. */ + +static tree +c_fold_build2_loc (location_t loc, enum tree_code code, tree type, tree arg0, + tree arg1) +{ + if (!c_dialect_cxx ()) + return fold_build2_loc (loc, code, type, arg0, arg1); + else if (loc != UNKNOWN_LOCATION) + return build2_loc (loc, code, type, arg0, arg1); + else + return build2 (code, type, arg0, arg1); +} + +/* In addition to calling c_fold_convert for EXPR of type TYPE, also call c_fully_fold to remove any C_MAYBE_CONST_EXPRs that could be hiding there (PR47197). */ static tree fully_fold_convert (tree type, tree expr) { - tree result = fold_convert (type, expr); + tree result = c_fold_convert (type, expr); bool maybe_const = true; if (!c_dialect_cxx ()) @@ -855,7 +881,7 @@ fully_fold_convert (tree type, tree expr The overloaded builtin that matched the types and args is described by DESC. The N arguments are given in ARGS, respectively. - Actually the only thing it does is calling fold_convert on ARGS, with + Actually the only thing it does is calling c_fold_convert on ARGS, with a small exception for vec_{all,any}_{ge,le} predicates. */ static tree @@ -891,8 +917,9 @@ altivec_build_resolved_builtin (tree *ar std::swap (args[1], args[2]); std::swap (arg_type[1], arg_type[2]); - args[0] = fold_build2 (BIT_XOR_EXPR, TREE_TYPE (args[0]), args[0], - build_int_cst (NULL_TREE, 2)); + args[0] = c_fold_build2_loc (UNKNOWN_LOCATION, BIT_XOR_EXPR, + TREE_TYPE (args[0]), args[0], + build_int_cst (NULL_TREE, 2)); } for (int j = 0; j < n; j++) @@ -923,7 +950,7 @@ altivec_build_resolved_builtin (tree *ar default: gcc_unreachable (); } - return fold_convert (ret_type, call); + return c_fold_convert (ret_type, call); } /* Enumeration of possible results from attempted overload resolution. @@ -964,8 +991,8 @@ resolve_vec_mul (resolution *res, tree * case E_TImode: /* For scalar types just use a multiply expression. */ *res = resolved; - return fold_build2_loc (loc, MULT_EXPR, types[0], args[0], - fold_convert (types[0], args[1])); + return c_fold_build2_loc (loc, MULT_EXPR, types[0], args[0], + c_fold_convert (types[0], args[1])); case E_SFmode: { /* For floats use the xvmulsp instruction directly. */ @@ -1108,8 +1135,8 @@ resolve_vec_adde_sube (resolution *res, params); tree const1 = build_int_cstu (TREE_TYPE (types[0]), 1); tree ones_vector = build_vector_from_val (types[0], const1); - tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, types[0], - args[2], ones_vector); + tree and_expr = c_fold_build2_loc (loc, BIT_AND_EXPR, types[0], + args[2], ones_vector); params = make_tree_vector (); vec_safe_push (params, call); vec_safe_push (params, and_expr); @@ -1194,8 +1221,8 @@ resolve_vec_addec_subec (resolution *res params); tree const1 = build_int_cstu (TREE_TYPE (types[0]), 1); tree ones_vector = build_vector_from_val (types[0], const1); - tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, types[0], - args[2], ones_vector); + tree and_expr = c_fold_build2_loc (loc, BIT_AND_EXPR, types[0], + args[2], ones_vector); params = make_tree_vector (); vec_safe_push (params, call2); vec_safe_push (params, and_expr); @@ -1303,7 +1330,7 @@ resolve_vec_splats (resolution *res, rs6 return error_mark_node; } - arg = save_expr (fold_convert (TREE_TYPE (type), arg)); + arg = save_expr (c_fold_convert (TREE_TYPE (type), arg)); vec<constructor_elt, va_gc> *vec; vec_alloc (vec, size); @@ -1442,7 +1469,7 @@ resolve_vec_extract (resolution *res, ve tree result = build_call_expr (call, 2, arg1, arg2); /* Coerce the result to vector element type. May be no-op. */ arg1_inner_type = TREE_TYPE (arg1_type); - result = fold_convert (arg1_inner_type, result); + result = c_fold_convert (arg1_inner_type, result); *res = resolved; return result; } @@ -1566,8 +1593,9 @@ resolve_vec_insert (resolution *res, vec if (TARGET_VSX) { stmt = build_array_ref (loc, stmt, arg2); - stmt = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg0), stmt, - convert (TREE_TYPE (stmt), arg0)); + stmt = c_fold_build2_loc (UNKNOWN_LOCATION, MODIFY_EXPR, + TREE_TYPE (arg0), stmt, + convert (TREE_TYPE (stmt), arg0)); stmt = build2 (COMPOUND_EXPR, arg1_type, stmt, decl); } else @@ -1791,7 +1819,7 @@ altivec_resolve_overloaded_builtin (loca "const"); type = build_qualified_type (TREE_TYPE (type), 0); type = build_pointer_type (type); - arg = fold_convert (type, arg); + arg = c_fold_convert (type, arg); } /* For RS6000_OVLD_VEC_LXVL, convert any const * to its non constant @@ -1802,7 +1830,7 @@ altivec_resolve_overloaded_builtin (loca { type = build_qualified_type (TREE_TYPE (type), 0); type = build_pointer_type (type); - arg = fold_convert (type, arg); + arg = c_fold_convert (type, arg); } args[n] = arg; --- gcc/testsuite/g++.target/powerpc/pr124133.C.jj 2026-02-17 16:50:11.004054635 +0100 +++ gcc/testsuite/g++.target/powerpc/pr124133.C 2026-02-17 16:50:03.531179705 +0100 @@ -0,0 +1,12 @@ +// PR target/124133 +// { dg-options "-mdejagnu-cpu=power8 -mvsx" } +// { dg-require-effective-target powerpc_vsx } */ + +typedef __INTPTR_TYPE__ intptr_t; + +template <int> +void +foo (int x, short *y, intptr_t z) +{ + __builtin_vec_vsx_ld ((x + z) * 2, y); +} Jakub
