This is an updated version of the patch to replace void_zero_node with void_node. The main controversial point/hack in the original was that it handled void_node in the gimplifier as a zero constant. Jason sent me a patch that traps the dummy object in the front end, meaning that it no longer escapes to the gimplifier.
I tested the combination of both patches on x86_64-linux-gnu. I think Richard has already approved the middle-end bits, but OK for C++? Jason, should I commit your patch or will you? Thanks, Richard gcc/ * tree.def (VOID_CST): New. * tree-core.h (TI_VOID): New. * tree.h (void_node): New. * tree.c (tree_node_structure_for_code, tree_code_size) (iterative_hash_expr): Handle VOID_CST. (build_common_tree_nodes): Initialize void_node. gcc/c-family/ * c-common.h (CTI_VOID_ZERO, void_zero_node): Delete. * c-common.c (c_common_nodes_and_builtins): Don't initialize void_zero_node. * c-pretty-print.c (pp_c_void_constant): New function. (c_pretty_printer::constant, c_pretty_printer::primary_expression) (c_pretty_printer::expression): Handle VOID_CST. * cilk.c (extract_free_variables): Likewise. * c-ubsan.c (ubsan_instrument_division, ubsan_instrument_shift) (ubsan_instrument_vla): Use void_node instead of void_zero_node. gcc/c/ * c-array-notation.c (expand_array_notations): Use void_node instead of void_zero_node. gcc/cp/ * cvt.c (convert_to_void): Use void_node instead of void_zero_node. * cp-array-notation.c (replace_invariant_exprs): Likewise. (expand_array_notation): Handle VOID_CST. * error.c (dump_expr): Likewise. * cxx-pretty-print.c (cxx_pretty_printer::primary_expression) (cxx_pretty_printer::expression): Likewise. (pp_cxx_new_expression): Use void_node instead of void_zero_node. * decl.c (register_dtor_fn): Likewise. * init.c (build_raw_new_expr, build_new_1, build_vec_init) (build_delete, push_base_cleanups): Likewise. * mangle.c (write_expression): Likewise. * semantics.c (finish_break_stmt, empty_expr_stmt_p): Likewise. * pt.c (tsubst_decl, tsubst_copy_and_build): Likewise. (tsubst, tsubst_copy, build_non_dependent_expr): Handle VOID_CST. * tree.c (cp_tree_equal): Likewise. (build_dummy_object, is_dummy_object, stabilize_expr): Use void_node instead of void_zero_node. * typeck.c (check_return_expr): Likewise. * typeck2.c (build_functional_cast): Likewise. Index: gcc/tree.def =================================================================== --- gcc/tree.def 2014-05-19 11:15:16.580535297 +0100 +++ gcc/tree.def 2014-05-20 13:49:09.137734209 +0100 @@ -257,6 +257,8 @@ DEFTREECODE (LANG_TYPE, "lang_type", tcc /* First, the constants. */ +DEFTREECODE (VOID_CST, "void_cst", tcc_constant, 0) + /* Contents are in an array of HOST_WIDE_INTs. We often access these constants both in their native precision and Index: gcc/tree-core.h =================================================================== --- gcc/tree-core.h 2014-05-20 13:48:56.299756356 +0100 +++ gcc/tree-core.h 2014-05-20 13:49:09.135734213 +0100 @@ -410,6 +410,8 @@ enum tree_index { TI_UINT32_TYPE, TI_UINT64_TYPE, + TI_VOID, + TI_INTEGER_ZERO, TI_INTEGER_ONE, TI_INTEGER_THREE, Index: gcc/tree.h =================================================================== --- gcc/tree.h 2014-05-20 13:48:56.299756356 +0100 +++ gcc/tree.h 2014-05-20 13:49:09.138734208 +0100 @@ -3245,6 +3245,8 @@ #define uint16_type_node global_trees[T #define uint32_type_node global_trees[TI_UINT32_TYPE] #define uint64_type_node global_trees[TI_UINT64_TYPE] +#define void_node global_trees[TI_VOID] + #define integer_zero_node global_trees[TI_INTEGER_ZERO] #define integer_one_node global_trees[TI_INTEGER_ONE] #define integer_three_node global_trees[TI_INTEGER_THREE] Index: gcc/tree.c =================================================================== --- gcc/tree.c 2014-05-20 13:48:56.299756356 +0100 +++ gcc/tree.c 2014-05-20 13:49:09.137734209 +0100 @@ -383,6 +383,7 @@ tree_node_structure_for_code (enum tree_ switch (code) { /* tcc_constant cases. */ + case VOID_CST: return TS_TYPED; case INTEGER_CST: return TS_INT_CST; case REAL_CST: return TS_REAL_CST; case FIXED_CST: return TS_FIXED_CST; @@ -652,6 +653,7 @@ tree_code_size (enum tree_code code) case tcc_constant: /* a constant */ switch (code) { + case VOID_CST: return sizeof (struct tree_typed); case INTEGER_CST: gcc_unreachable (); case REAL_CST: return sizeof (struct tree_real_cst); case FIXED_CST: return sizeof (struct tree_fixed_cst); @@ -7360,6 +7362,8 @@ iterative_hash_expr (const_tree t, hashv { /* Alas, constants aren't shared, so we can't rely on pointer identity. */ + case VOID_CST: + return iterative_hash_hashval_t (0, val); case INTEGER_CST: for (i = 0; i < TREE_INT_CST_NUNITS (t); i++) val = iterative_hash_host_wide_int (TREE_INT_CST_ELT (t, i), val); @@ -9631,6 +9635,9 @@ build_common_tree_nodes (bool signed_cha TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; TYPE_USER_ALIGN (void_type_node) = 0; + void_node = make_node (VOID_CST); + TREE_TYPE (void_node) = void_type_node; + null_pointer_node = build_int_cst (build_pointer_type (void_type_node), 0); layout_type (TREE_TYPE (null_pointer_node)); Index: gcc/c-family/c-common.h =================================================================== --- gcc/c-family/c-common.h 2014-05-19 11:15:16.580535297 +0100 +++ gcc/c-family/c-common.h 2014-05-20 13:49:09.142734201 +0100 @@ -297,8 +297,6 @@ enum c_tree_index CTI_C99_FUNCTION_NAME_DECL, CTI_SAVED_FUNCTION_NAME_DECLS, - CTI_VOID_ZERO, - CTI_NULL, CTI_MAX @@ -430,9 +428,6 @@ #define pretty_function_name_decl_node c #define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL] #define saved_function_name_decls c_global_trees[CTI_SAVED_FUNCTION_NAME_DECLS] -/* A node for `((void) 0)'. */ -#define void_zero_node c_global_trees[CTI_VOID_ZERO] - /* The node for C++ `__null'. */ #define null_node c_global_trees[CTI_NULL] Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c 2014-05-20 13:48:56.299756356 +0100 +++ gcc/c-family/c-common.c 2014-05-20 13:49:09.142734201 +0100 @@ -5524,10 +5524,6 @@ c_common_nodes_and_builtins (void) TYPE_NAME (void_type_node) = void_name; } - /* This node must not be shared. */ - void_zero_node = make_int_cst (1, 1); - TREE_TYPE (void_zero_node) = void_type_node; - void_list_node = build_void_list_node (); /* Make a type to be the domain of a few array types Index: gcc/c-family/c-pretty-print.c =================================================================== --- gcc/c-family/c-pretty-print.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/c-family/c-pretty-print.c 2014-05-20 13:49:09.139734206 +0100 @@ -906,6 +906,15 @@ pp_c_string_literal (c_pretty_printer *p pp_doublequote (pp); } +/* Pretty-print a VOID_CST (void_node). */ + +static void +pp_c_void_constant (c_pretty_printer *pp) +{ + pp_c_type_cast (pp, void_type_node); + pp_string (pp, "0"); +} + /* Pretty-print an INTEGER literal. */ static void @@ -1136,6 +1145,10 @@ c_pretty_printer::constant (tree e) switch (code) { + case VOID_CST: + pp_c_void_constant (this); + break; + case INTEGER_CST: { tree type = TREE_TYPE (e); @@ -1241,6 +1254,7 @@ c_pretty_printer::primary_expression (tr translate_string ("<return-value>"); break; + case VOID_CST: case INTEGER_CST: case REAL_CST: case FIXED_CST: @@ -2131,6 +2145,10 @@ c_pretty_printer::expression (tree e) { switch (TREE_CODE (e)) { + case VOID_CST: + pp_c_void_constant (this); + break; + case INTEGER_CST: pp_c_integer_constant (this, e); break; Index: gcc/c-family/cilk.c =================================================================== --- gcc/c-family/cilk.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/c-family/cilk.c 2014-05-20 13:49:09.139734206 +0100 @@ -997,6 +997,7 @@ extract_free_variables (tree t, struct w { case ERROR_MARK: case IDENTIFIER_NODE: + case VOID_CST: case INTEGER_CST: case REAL_CST: case FIXED_CST: Index: gcc/c-family/c-ubsan.c =================================================================== --- gcc/c-family/c-ubsan.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/c-family/c-ubsan.c 2014-05-20 13:49:09.118734243 +0100 @@ -95,7 +95,7 @@ ubsan_instrument_division (location_t lo tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); } - t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node); + t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node); return t; } @@ -178,7 +178,7 @@ ubsan_instrument_shift (location_t loc, tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); } - t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node); + t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node); return t; } @@ -207,7 +207,7 @@ ubsan_instrument_vla (location_t loc, tr tt = builtin_decl_explicit (bcode); tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size)); } - t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node); + t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node); return t; } Index: gcc/c/c-array-notation.c =================================================================== --- gcc/c/c-array-notation.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/c/c-array-notation.c 2014-05-20 13:49:09.119734240 +0100 @@ -1279,7 +1279,7 @@ expand_array_notations (tree *tp, int *w A[x:y:z]; A[x:y]; Replace those with just void zero node. */ - *tp = void_zero_node; + *tp = void_node; default: break; } Index: gcc/cp/cvt.c =================================================================== --- gcc/cp/cvt.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/cvt.c 2014-05-20 13:49:09.120734238 +0100 @@ -1285,7 +1285,7 @@ convert_to_void (tree expr, impl_conv_vo } else return error_mark_node; - expr = void_zero_node; + expr = void_node; } else if (implicit != ICV_CAST && probe == expr && is_overloaded_fn (probe)) { @@ -1415,7 +1415,7 @@ convert_to_void (tree expr, impl_conv_vo expr = build1 (CONVERT_EXPR, void_type_node, expr); } if (! TREE_SIDE_EFFECTS (expr)) - expr = void_zero_node; + expr = void_node; return expr; } Index: gcc/cp/cp-array-notation.c =================================================================== --- gcc/cp/cp-array-notation.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/cp-array-notation.c 2014-05-20 13:49:09.120734238 +0100 @@ -181,7 +181,7 @@ replace_invariant_exprs (tree *node) if (VOID_TYPE_P (TREE_TYPE (t))) { finish_expr_stmt (t); - new_var = void_zero_node; + new_var = void_node; } else new_var = get_temp_regvar (TREE_TYPE (t), t); @@ -1126,6 +1126,7 @@ expand_array_notation_exprs (tree t) { case ERROR_MARK: case IDENTIFIER_NODE: + case VOID_CST: case INTEGER_CST: case REAL_CST: case FIXED_CST: Index: gcc/cp/error.c =================================================================== --- gcc/cp/error.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/error.c 2014-05-20 13:49:09.140734204 +0100 @@ -1913,6 +1913,7 @@ dump_expr (cxx_pretty_printer *pp, tree pp_cxx_ws_string (pp, M_("<unknown>")); break; + case VOID_CST: case INTEGER_CST: case REAL_CST: case STRING_CST: Index: gcc/cp/cxx-pretty-print.c =================================================================== --- gcc/cp/cxx-pretty-print.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/cxx-pretty-print.c 2014-05-20 13:49:09.121734236 +0100 @@ -403,6 +403,7 @@ cxx_pretty_printer::primary_expression ( { switch (TREE_CODE (t)) { + case VOID_CST: case INTEGER_CST: case REAL_CST: case COMPLEX_CST: @@ -690,7 +691,7 @@ pp_cxx_new_expression (cxx_pretty_printe pp_left_paren (pp); if (TREE_CODE (init) == TREE_LIST) pp_c_expression_list (pp, init); - else if (init == void_zero_node) + else if (init == void_node) ; /* OK, empty initializer list. */ else pp->expression (init); @@ -1028,6 +1029,7 @@ cxx_pretty_printer::expression (tree t) switch (TREE_CODE (t)) { case STRING_CST: + case VOID_CST: case INTEGER_CST: case REAL_CST: case COMPLEX_CST: Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/decl.c 2014-05-20 13:49:09.124734232 +0100 @@ -6830,7 +6830,7 @@ register_dtor_fn (tree decl) type = TREE_TYPE (decl); if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) - return void_zero_node; + return void_node; /* If we're using "__cxa_atexit" (or "__cxa_thread_atexit" or "__aeabi_atexit"), and DECL is a class object, we can just pass the @@ -7077,7 +7077,7 @@ expand_static_init (tree decl, tree init TARGET_EXPR_CLEANUP (begin) = build3 (COND_EXPR, void_type_node, flag, - void_zero_node, + void_node, build_call_n (abort_fn, 1, guard_addr)); CLEANUP_EH_ONLY (begin) = 1; @@ -8425,7 +8425,7 @@ compute_array_index_type (tree name, tre tree comp = build2 (LT_EXPR, boolean_type_node, itype, ssize_int (-1)); comp = build3 (COND_EXPR, void_type_node, comp, - throw_bad_array_length (), void_zero_node); + throw_bad_array_length (), void_node); finish_expr_stmt (comp); } else if (flag_sanitize & SANITIZE_VLA) Index: gcc/cp/init.c =================================================================== --- gcc/cp/init.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/init.c 2014-05-20 13:49:09.125734230 +0100 @@ -2116,7 +2116,7 @@ build_raw_new_expr (vec<tree, va_gc> *pl if (init == NULL) init_list = NULL_TREE; else if (init->is_empty ()) - init_list = void_zero_node; + init_list = void_node; else init_list = build_tree_list_vec (init); @@ -2931,7 +2931,7 @@ build_new_1 (vec<tree, va_gc> **placemen TARGET_EXPR_CLEANUP (begin) = build3 (COND_EXPR, void_type_node, sentry, - cleanup, void_zero_node); + cleanup, void_node); end = build2 (MODIFY_EXPR, TREE_TYPE (sentry), sentry, boolean_false_node); @@ -3594,7 +3594,7 @@ build_vec_init (tree base, tree maxindex else throw_call = throw_bad_array_new_length (); length_check = build3 (COND_EXPR, void_type_node, length_check, - throw_call, void_zero_node); + throw_call, void_node); finish_expr_stmt (length_check); } @@ -4016,7 +4016,7 @@ build_delete (tree otype, tree addr, spe } if (auto_delete != sfk_deleting_destructor) - return void_zero_node; + return void_node; return build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), @@ -4104,8 +4104,7 @@ build_delete (tree otype, tree addr, spe } if (ifexp != integer_one_node) - expr = build3 (COND_EXPR, void_type_node, - ifexp, expr, void_zero_node); + expr = build3 (COND_EXPR, void_type_node, ifexp, expr, void_node); return expr; } @@ -4150,7 +4149,7 @@ push_base_cleanups (void) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))) { expr = build3 (COND_EXPR, void_type_node, cond, - expr, void_zero_node); + expr, void_node); finish_decl_cleanup (NULL_TREE, expr); } } Index: gcc/cp/mangle.c =================================================================== --- gcc/cp/mangle.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/mangle.c 2014-05-20 13:49:09.125734230 +0100 @@ -2812,7 +2812,7 @@ write_expression (tree expr) { if (init) write_string ("pi"); - if (init && init != void_zero_node) + if (init && init != void_node) for (t = init; t; t = TREE_CHAIN (t)) write_expression (TREE_VALUE (t)); write_char ('E'); Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/semantics.c 2014-05-20 13:49:09.131734220 +0100 @@ -1083,7 +1083,7 @@ finish_break_stmt (void) block_may_fallthru returns true when given something it does not understand. */ if (!block_may_fallthru (cur_stmt_list)) - return void_zero_node; + return void_node; return add_stmt (build_stmt (input_location, BREAK_STMT)); } @@ -2095,7 +2095,7 @@ empty_expr_stmt_p (tree expr_stmt) { tree body = NULL_TREE; - if (expr_stmt == void_zero_node) + if (expr_stmt == void_node) return true; if (expr_stmt) Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c 2014-05-20 13:48:56.268756409 +0100 +++ gcc/cp/pt.c 2014-05-20 13:49:09.129734223 +0100 @@ -10908,7 +10908,7 @@ #define RETURN(EXP) do { r = (EXP); goto /* Set up DECL_TEMPLATE_INFO so that we can get at the NSDMI in perform_member_init. Still set DECL_INITIAL so that we know there is one. */ - DECL_INITIAL (r) = void_zero_node; + DECL_INITIAL (r) = void_node; gcc_assert (DECL_LANG_SPECIFIC (r) == NULL); retrofit_lang_decl (r); DECL_TEMPLATE_INFO (r) = build_template_info (t, args); @@ -12283,6 +12283,7 @@ tsubst (tree t, tree args, tsubst_flags_ } break; + case VOID_CST: case INTEGER_CST: case REAL_CST: case STRING_CST: @@ -13042,6 +13043,10 @@ tsubst_copy (tree t, tree args, tsubst_f error ("use %<...%> to expand argument pack"); return error_mark_node; + case VOID_CST: + gcc_checking_assert (t == void_node && VOID_TYPE_P (TREE_TYPE (t))); + return t; + case INTEGER_CST: case REAL_CST: case STRING_CST: @@ -14566,7 +14571,7 @@ #define RECUR(NODE) \ else { init_vec = make_tree_vector (); - if (init == void_zero_node) + if (init == void_node) gcc_assert (init_vec != NULL); else { @@ -15222,9 +15227,9 @@ #define RECUR(NODE) \ cur_stmt_expr = old_stmt_expr; /* If the resulting list of expression statement is empty, - fold it further into void_zero_node. */ + fold it further into void_node. */ if (empty_expr_stmt_p (stmt_expr)) - stmt_expr = void_zero_node; + stmt_expr = void_node; RETURN (stmt_expr); } @@ -21509,9 +21514,11 @@ build_non_dependent_expr (tree expr) cannot be used to initialize a "char *". */ if (TREE_CODE (expr) == STRING_CST) return expr; - /* Preserve arithmetic constants, as an optimization -- there is no + /* Preserve void and arithmetic constants, as an optimization -- there is no reason to create a new node. */ - if (TREE_CODE (expr) == INTEGER_CST || TREE_CODE (expr) == REAL_CST) + if (TREE_CODE (expr) == VOID_CST + || TREE_CODE (expr) == INTEGER_CST + || TREE_CODE (expr) == REAL_CST) return expr; /* Preserve THROW_EXPRs -- all throw-expressions have type "void". There is at least one place where we want to know that a Index: gcc/cp/tree.c =================================================================== --- gcc/cp/tree.c 2014-05-19 17:07:44.106746641 +0100 +++ gcc/cp/tree.c 2014-05-20 13:49:09.132734218 +0100 @@ -2620,6 +2620,11 @@ cp_tree_equal (tree t1, tree t2) switch (code1) { + case VOID_CST: + /* There's only a single VOID_CST node, so we should never reach + here. */ + gcc_unreachable (); + case INTEGER_CST: return tree_int_cst_equal (t1, t2); @@ -2947,7 +2952,7 @@ member_p (const_tree decl) tree build_dummy_object (tree type) { - tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_zero_node); + tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_node); return cp_build_indirect_ref (decl, RO_NULL, tf_warning_or_error); } @@ -2997,7 +3002,7 @@ is_dummy_object (const_tree ob) if (INDIRECT_REF_P (ob)) ob = TREE_OPERAND (ob, 0); return (TREE_CODE (ob) == NOP_EXPR - && TREE_OPERAND (ob, 0) == void_zero_node); + && TREE_OPERAND (ob, 0) == void_node); } /* Returns 1 iff type T is something we want to treat as a scalar type for @@ -3775,7 +3780,7 @@ stabilize_expr (tree exp, tree* initp) else if (VOID_TYPE_P (TREE_TYPE (exp))) { init_expr = exp; - exp = void_zero_node; + exp = void_node; } /* There are no expressions with REFERENCE_TYPE, but there can be call arguments with such a type; just treat it as a pointer. */ Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c 2014-05-20 13:49:07.665736749 +0100 +++ gcc/cp/typeck.c 2014-05-20 13:49:09.134734214 +0100 @@ -8424,7 +8424,7 @@ check_return_expr (tree retval, bool *no else { if (!retval) - retval = void_zero_node; + retval = void_node; auto_node = type_uses_auto (current_function_auto_return_pattern); type = do_auto_deduction (current_function_auto_return_pattern, retval, auto_node); Index: gcc/cp/typeck2.c =================================================================== --- gcc/cp/typeck2.c 2014-05-19 11:15:16.580535297 +0100 +++ gcc/cp/typeck2.c 2014-05-20 13:49:09.134734214 +0100 @@ -1856,7 +1856,7 @@ build_functional_cast (tree exp, tree pa if (parms == NULL_TREE) { if (VOID_TYPE_P (type)) - return void_zero_node; + return void_node; return build_value_init (cv_unqualified (type), complain); }