On Wed, Feb 09, 2022 at 11:19:25AM +0100, Richard Biener wrote: > That does look like bogus abstraction though - I'd rather have > the target be specific w/o option checks and replace > targetm.zero_addres_valid uses with a wrapper (like you do for > flag_delete_null_pointer_checks), if we think that the specific > query should be adjusted by sanitize flags (why?) or > folding_initializer (why?).
Based on discussions on IRC, here is a WIP patch. Unfortunately, there are 3 unresolved issues: 1) ipa-icf.cc uses && opt_for_fn (decl, flag_delete_null_pointer_checks)) there is a pointer type, but I guess we'd need to adjust the target hook to take a defaulted fndecl argument and use that for the options 2) rtlanal.cc has: case SYMBOL_REF: return flag_delete_null_pointer_checks && !SYMBOL_REF_WEAK (x); Is there any way how to find out address space of a SYMBOL_REF? Or shall it hardcode ADDR_SPACE_GENERIC? 3) tree-ssa-structalias.cc has: if ((TREE_CODE (t) == INTEGER_CST && integer_zerop (t)) /* The only valid CONSTRUCTORs in gimple with pointer typed elements are zero-initializer. But in IPA mode we also process global initializers, so verify at least. */ || (TREE_CODE (t) == CONSTRUCTOR && CONSTRUCTOR_NELTS (t) == 0)) { if (flag_delete_null_pointer_checks) temp.var = nothing_id; else temp.var = nonlocal_id; temp.type = ADDRESSOF; temp.offset = 0; results->safe_push (temp); return; } mpt really sure where to get the address space from in that case And perhaps I didn't do it right in some other spots too. --- gcc/targhooks.cc.jj 2022-01-18 11:58:59.919977242 +0100 +++ gcc/targhooks.cc 2022-02-09 13:21:08.958835833 +0100 @@ -1598,7 +1598,7 @@ default_addr_space_subset_p (addr_space_ bool default_addr_space_zero_address_valid (addr_space_t as ATTRIBUTE_UNUSED) { - return false; + return !flag_delete_null_pointer_checks_; } /* The default hook for debugging the address space is to return the --- gcc/tree.cc.jj 2022-02-08 20:08:04.001539492 +0100 +++ gcc/tree.cc 2022-02-09 14:44:01.602693848 +0100 @@ -69,6 +69,7 @@ along with GCC; see the file COPYING3. #include "gimple-fold.h" #include "escaped_string.h" #include "gimple-range.h" +#include "asan.h" /* Tree code classes. */ @@ -13937,12 +13938,13 @@ nonnull_arg_p (const_tree arg) /* THIS argument of method is always non-NULL. */ if (TREE_CODE (TREE_TYPE (cfun->decl)) == METHOD_TYPE && arg == DECL_ARGUMENTS (cfun->decl) - && flag_delete_null_pointer_checks) + && POINTER_TYPE_P (TREE_TYPE (arg)) + && !zero_address_valid (TREE_TYPE (arg))) return true; /* Values passed by reference are always non-NULL. */ if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE - && flag_delete_null_pointer_checks) + && !zero_address_valid (TREE_TYPE (arg))) return true; fntype = TREE_TYPE (cfun->decl); @@ -14549,6 +14551,24 @@ get_attr_nonstring_decl (tree expr, tree return NULL_TREE; } +/* Return true if NULL is a valid address in AS. */ + +bool +zero_address_valid (addr_space_t as) +{ + if (targetm.addr_space.zero_address_valid (as)) + return true; + /* -fsanitize={null,{,returns-}nonnull-attribute sanitizers need + NULL pointer checks to be preserved, so pretend NULL addresses + are valid for it as well. + But don't do that in constant expressions or initializers. */ + if (folding_initializer) + return false; + return sanitize_flags_p (SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE, + current_function_decl); +} + #if CHECKING_P namespace selftest { --- gcc/config/i386/i386.cc.jj 2022-02-09 12:55:50.716774241 +0100 +++ gcc/config/i386/i386.cc 2022-02-09 13:23:01.041272540 +0100 @@ -23804,7 +23804,9 @@ ix86_gen_scratch_sse_rtx (machine_mode m static bool ix86_addr_space_zero_address_valid (addr_space_t as) { - return as != ADDR_SPACE_GENERIC; + if (as != ADDR_SPACE_GENERIC) + return true; + return default_addr_space_zero_address_valid (as); } static void --- gcc/config/nios2/elf.h.jj 2022-01-11 23:11:21.915296829 +0100 +++ gcc/config/nios2/elf.h 2022-02-09 13:04:42.643433282 +0100 @@ -57,5 +57,5 @@ vector). Users can override this on the command line to get the additional optimizations it enables. */ #define SUBTARGET_OVERRIDE_OPTIONS \ - if (flag_delete_null_pointer_checks < 0) \ - flag_delete_null_pointer_checks = 0 + if (flag_delete_null_pointer_checks_ < 0) \ + flag_delete_null_pointer_checks_ = 0 --- gcc/config/msp430/msp430.cc.jj 2022-02-04 14:36:54.410613609 +0100 +++ gcc/config/msp430/msp430.cc 2022-02-09 13:04:09.372888416 +0100 @@ -161,7 +161,7 @@ msp430_option_override (void) { /* The MSP430 architecture can safely dereference a NULL pointer. In fact, there are memory mapped registers there. */ - flag_delete_null_pointer_checks = 0; + flag_delete_null_pointer_checks_ = 0; init_machine_status = msp430_init_machine_status; --- gcc/config/cr16/cr16.cc.jj 2022-01-18 11:58:59.076989285 +0100 +++ gcc/config/cr16/cr16.cc 2022-02-09 13:03:47.292190471 +0100 @@ -277,7 +277,7 @@ cr16_override_options (void) Programs which rely on NULL pointer dereferences _not_ halting the program may not work properly with this option. So disable this option. */ - flag_delete_null_pointer_checks = 0; + flag_delete_null_pointer_checks_ = 0; /* FIXME: To avoid spill_failure ICE during exception handling, * disable cse_fllow_jumps. The spill error occurs when compiler --- gcc/range-op.cc.jj 2022-02-08 20:08:03.888541042 +0100 +++ gcc/range-op.cc 2022-02-09 14:01:50.561978439 +0100 @@ -3870,8 +3870,7 @@ pointer_plus_operator::wi_fold (irange & if ((!wi_includes_zero_p (type, lh_lb, lh_ub) || !wi_includes_zero_p (type, rh_lb, rh_ub)) && !TYPE_OVERFLOW_WRAPS (type) - && (flag_delete_null_pointer_checks - || !wi::sign_mask (rh_ub))) + && (!zero_address_valid (type) || !wi::sign_mask (rh_ub))) r = range_nonzero (type); else if (lh_lb == lh_ub && lh_lb == 0 && rh_lb == rh_ub && rh_lb == 0) --- gcc/gimple-range-fold.cc.jj 2022-02-08 20:08:03.829541850 +0100 +++ gcc/gimple-range-fold.cc 2022-02-09 13:53:24.595030465 +0100 @@ -721,7 +721,7 @@ fold_using_range::range_of_address (iran /* If &X->a is equal to X, the range of X is the result. */ if (off_cst && known_eq (off, 0)) return true; - else if (flag_delete_null_pointer_checks + else if (!zero_address_valid (TREE_TYPE (expr)) && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) { /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't @@ -741,7 +741,7 @@ fold_using_range::range_of_address (iran if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) && off_cst && known_ne (off, 0) - && (flag_delete_null_pointer_checks || known_gt (off, 0))) + && (!zero_address_valid (TREE_TYPE (expr)) || known_gt (off, 0))) { r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; --- gcc/cp/typeck.cc.jj 2022-02-08 20:08:03.783542481 +0100 +++ gcc/cp/typeck.cc 2022-02-09 14:47:47.552526504 +0100 @@ -7917,7 +7917,7 @@ build_static_cast_1 (location_t loc, tre that expr is NULL, if the static_cast is to a reference type, it is UB if it would be NULL, so omit the non-NULL check. */ expr = build_base_path (MINUS_EXPR, expr, base, - /*nonnull=*/flag_delete_null_pointer_checks, + /*nonnull=*/!zero_address_valid (type), complain); /* Convert the pointer to a reference -- but then remember that --- gcc/tree-ssa-structalias.cc.jj 2022-02-08 20:08:03.952540164 +0100 +++ gcc/tree-ssa-structalias.cc 2022-02-09 14:32:39.127226322 +0100 @@ -4591,8 +4591,10 @@ find_func_aliases_for_builtin_call (stru } get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc); do_deref (&lhsc); - if (flag_delete_null_pointer_checks - && integer_zerop (gimple_call_arg (t, 1))) + tree arg1 = gimple_call_arg (t, 1); + if (integer_zerop (arg1) + && POINTER_TYPE_P (TREE_TYPE (arg1)) + && !zero_address_valid (TREE_TYPE (arg1))) { ac.type = ADDRESSOF; ac.var = nothing_id; --- gcc/testsuite/g++.dg/ubsan/pr104426.C.jj 2022-02-09 13:20:26.419429166 +0100 +++ gcc/testsuite/g++.dg/ubsan/pr104426.C 2022-02-09 13:20:26.419429166 +0100 @@ -0,0 +1,29 @@ +// PR c++/104426 +// { dg-do compile } +// { dg-options "-std=c++17 -fsanitize=undefined" } + +struct category +{ + constexpr bool failed () const noexcept { return true; } +}; + +inline constexpr category s_cat; + +struct condition +{ + category const *cat_; + constexpr bool failed () const noexcept + { + if (cat_) + return cat_->failed (); + else + return false; + } +}; + +int +main () +{ + constexpr condition cond { &s_cat }; + static_assert (cond.failed ()); +} --- gcc/testsuite/g++.dg/ubsan/pr71962.C.jj 2022-02-09 13:20:26.419429166 +0100 +++ gcc/testsuite/g++.dg/ubsan/pr71962.C 2022-02-09 13:20:26.419429166 +0100 @@ -0,0 +1,17 @@ +// PR c++/71962 +// { dg-do compile } +// { dg-options "-std=c++14 -fsanitize=undefined" } + +struct P { + constexpr P (const int *p) : p(p) { } + const int *p; + explicit constexpr operator bool() const { return (bool) p; } +}; + +int +main () +{ + static constexpr int x{1}; + constexpr P p{&x}; + static_assert ((bool)p, ""); +} --- gcc/symtab.cc.jj 2022-02-08 20:08:03.913540699 +0100 +++ gcc/symtab.cc 2022-02-09 14:10:50.866452450 +0100 @@ -2135,11 +2135,11 @@ symtab_node::nonzero_address () could be useful to eliminate the NULL pointer checks in LTO programs. */ if (target->definition && !DECL_EXTERNAL (target->decl)) - return true; + return true; if (target->resolution != LDPR_UNKNOWN && target->resolution != LDPR_UNDEF && !target->can_be_discarded_p () - && flag_delete_null_pointer_checks) + && !zero_address_valid (TYPE_ADDR_SPACE (TREE_TYPE (decl)))) return true; return false; } @@ -2147,7 +2147,7 @@ symtab_node::nonzero_address () return false; } - /* With !flag_delete_null_pointer_checks we assume that symbols may + /* With -fno-delete-null-pointer-checks we assume that symbols may bind to NULL. This is on by default on embedded targets only. Otherwise all non-WEAK symbols must be defined and thus non-NULL or @@ -2156,7 +2156,7 @@ symtab_node::nonzero_address () When parsing, beware the cases when WEAK attribute is added later. */ if ((!DECL_WEAK (decl) || DECL_COMDAT (decl)) - && flag_delete_null_pointer_checks) + && !zero_address_valid (TYPE_ADDR_SPACE (TREE_TYPE (decl)))) { refuse_visibility_changes = true; return true; @@ -2164,10 +2164,11 @@ symtab_node::nonzero_address () /* If target is defined and not extern, we know it will be output and thus it will bind to non-NULL. - Play safe for flag_delete_null_pointer_checks where weak definition may + Play safe for -fno-delete-null-pointer-checks where weak definition may be re-defined by NULL. */ if (definition && !DECL_EXTERNAL (decl) - && (flag_delete_null_pointer_checks || !DECL_WEAK (decl))) + && (!zero_address_valid (TYPE_ADDR_SPACE (TREE_TYPE (decl))) + || !DECL_WEAK (decl))) { if (!DECL_WEAK (decl)) refuse_visibility_changes = true; @@ -2178,7 +2179,7 @@ symtab_node::nonzero_address () if (resolution != LDPR_UNKNOWN && resolution != LDPR_UNDEF && !can_be_discarded_p () - && flag_delete_null_pointer_checks) + && !zero_address_valid (TYPE_ADDR_SPACE (TREE_TYPE (decl)))) return true; return false; } --- gcc/ipa-fnsummary.cc.jj 2022-02-08 20:08:03.855541494 +0100 +++ gcc/ipa-fnsummary.cc 2022-02-09 13:54:40.594971201 +0100 @@ -2573,7 +2573,7 @@ points_to_local_or_readonly_memory_p (tr { /* See if memory location is clearly invalid. */ if (integer_zerop (t)) - return flag_delete_null_pointer_checks; + return !zero_address_valid (TREE_TYPE (t)); if (TREE_CODE (t) == SSA_NAME) { /* For IPA passes we can consinder accesses to return slot local --- gcc/tree.h.jj 2022-02-04 14:36:56.382586067 +0100 +++ gcc/tree.h 2022-02-09 13:37:22.944332825 +0100 @@ -6579,4 +6579,14 @@ extern unsigned fndecl_dealloc_argno (tr object or pointer. Otherwise return null. */ extern tree get_attr_nonstring_decl (tree, tree * = NULL); +/* Return true if NULL is a valid address in AS. */ +extern bool zero_address_valid (addr_space_t); + +inline bool +zero_address_valid (tree type) +{ + gcc_checking_assert (POINTER_TYPE_P (type)); + return zero_address_valid (TYPE_ADDR_SPACE (TREE_TYPE (type))); +} + #endif /* GCC_TREE_H */ --- gcc/tree-ssa-alias.cc.jj 2022-02-08 20:08:03.917540644 +0100 +++ gcc/tree-ssa-alias.cc 2022-02-09 14:16:14.231951242 +0100 @@ -2644,13 +2644,13 @@ modref_may_conflict (const gcall *stmt, alias_stats.modref_baseptr_tests++; - if (integer_zerop (arg) && flag_delete_null_pointer_checks) - continue; - - /* PTA oracle will be unhapy of arg is not an pointer. */ + /* PTA oracle will be unhapy if arg is not an pointer. */ if (!POINTER_TYPE_P (TREE_TYPE (arg))) return true; + if (integer_zerop (arg) && !zero_address_valid (TREE_TYPE (arg))) + continue; + /* If we don't have base pointer, give up. */ if (!ref->ref && !ref->base) continue; --- gcc/opts.cc.jj 2022-02-08 20:08:03.873541247 +0100 +++ gcc/opts.cc 2022-02-09 13:20:26.418429180 +0100 @@ -1224,12 +1224,6 @@ finish_options (struct gcc_options *opts error_at (loc, "%<-fsanitize-recover=%s%> is not supported", sanitizer_opts[i].name); - /* When instrumenting the pointers, we don't want to remove - the null pointer checks. */ - if (opts->x_flag_sanitize & (SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE - | SANITIZE_RETURNS_NONNULL_ATTRIBUTE)) - opts->x_flag_delete_null_pointer_checks = 0; - /* Aggressive compiler optimizations may cause false negatives. */ if (opts->x_flag_sanitize & ~(SANITIZE_LEAK | SANITIZE_UNREACHABLE)) opts->x_flag_aggressive_loop_optimizations = 0; --- gcc/ubsan.cc.jj 2022-02-08 20:08:04.001539492 +0100 +++ gcc/ubsan.cc 2022-02-09 13:20:26.419429166 +0100 @@ -1946,10 +1946,11 @@ instrument_nonnull_arg (gimple_stmt_iter { gimple *stmt = gsi_stmt (*gsi); location_t loc[2]; - /* infer_nonnull_range needs flag_delete_null_pointer_checks set, + /* infer_nonnull_range needs zero_address_valid true, while for nonnull sanitization it is clear. */ - int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks; - flag_delete_null_pointer_checks = 1; + int save_flag_sanitize = flag_sanitize; + flag_sanitize &= ~(SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE); loc[0] = gimple_location (stmt); loc[1] = UNKNOWN_LOCATION; for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++) @@ -2001,7 +2002,7 @@ instrument_nonnull_arg (gimple_stmt_iter } *gsi = gsi_for_stmt (stmt); } - flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks; + flag_sanitize = save_flag_sanitize; } /* Instrument returns in functions with returns_nonnull attribute. */ @@ -2012,10 +2013,11 @@ instrument_nonnull_return (gimple_stmt_i greturn *stmt = as_a <greturn *> (gsi_stmt (*gsi)); location_t loc[2]; tree arg = gimple_return_retval (stmt); - /* infer_nonnull_range needs flag_delete_null_pointer_checks set, - while for nonnull return sanitization it is clear. */ - int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks; - flag_delete_null_pointer_checks = 1; + /* infer_nonnull_range needs zero_address_valid true, + while for nonnull sanitization it is clear. */ + int save_flag_sanitize = flag_sanitize; + flag_sanitize &= ~(SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE); loc[0] = gimple_location (stmt); loc[1] = UNKNOWN_LOCATION; if (arg @@ -2056,7 +2058,7 @@ instrument_nonnull_return (gimple_stmt_i ubsan_create_edge (g); *gsi = gsi_for_stmt (stmt); } - flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks; + flag_sanitize = save_flag_sanitize; } /* Instrument memory references. Here we check whether the pointer --- gcc/tree-vrp.cc.jj 2022-02-08 20:08:03.977539821 +0100 +++ gcc/tree-vrp.cc 2022-02-09 14:33:26.884560195 +0100 @@ -732,7 +732,7 @@ extract_range_from_pointer_plus_expr (va if ((!range_includes_zero_p (vr0) || !range_includes_zero_p (vr1)) && !TYPE_OVERFLOW_WRAPS (expr_type) - && (flag_delete_null_pointer_checks + && (!zero_address_valid (expr_type) || (range_int_cst_p (vr1) && !tree_int_cst_sign_bit (vr1->max ())))) vr->set_nonzero (expr_type); --- gcc/vr-values.cc.jj 2022-02-08 20:08:04.001539492 +0100 +++ gcc/vr-values.cc 2022-02-09 14:34:32.257648360 +0100 @@ -426,7 +426,7 @@ vr_values::vrp_stmt_computes_nonzero (gi For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't allow going from non-NULL pointer to NULL. */ if ((off_cst && known_eq (off, 0)) - || (flag_delete_null_pointer_checks + || (!zero_address_valid (TREE_TYPE (expr)) && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)))) { const value_range_equiv *vr @@ -440,7 +440,7 @@ vr_values::vrp_stmt_computes_nonzero (gi if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) && off_cst && known_ne (off, 0) - && (flag_delete_null_pointer_checks || known_gt (off, 0))) + && (!zero_address_valid (TREE_TYPE (expr)) || known_gt (off, 0))) return true; } } --- gcc/tree-ssa-loop-niter.cc.jj 2022-02-08 20:08:03.952540164 +0100 +++ gcc/tree-ssa-loop-niter.cc 2022-02-09 14:17:40.614748806 +0100 @@ -3899,7 +3899,7 @@ infer_loop_bounds_from_pointer_arith (cl NULL pointer since that would mean wrapping, which we assume here not to happen. So, we can exclude NULL from the valid range of pointer arithmetic. */ - if (flag_delete_null_pointer_checks && int_cst_value (low) == 0) + if (!zero_address_valid (type) && int_cst_value (low) == 0) low = build_int_cstu (TREE_TYPE (low), TYPE_ALIGN_UNIT (TREE_TYPE (type))); record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true); --- gcc/common.opt.jj 2022-02-08 20:08:03.655544236 +0100 +++ gcc/common.opt 2022-02-09 13:02:46.907016534 +0100 @@ -1288,7 +1288,7 @@ Common Var(flag_delete_dead_exceptions) Delete dead instructions that may throw exceptions. fdelete-null-pointer-checks -Common Var(flag_delete_null_pointer_checks) Init(-1) Optimization +Common Var(flag_delete_null_pointer_checks_) Init(-1) Optimization Delete useless null pointer checks. fdevirtualize-at-ltrans --- gcc/c-family/c-ubsan.cc.jj 2022-02-08 20:08:03.611544839 +0100 +++ gcc/c-family/c-ubsan.cc 2022-02-09 13:20:26.419429166 +0100 @@ -464,17 +464,16 @@ ubsan_maybe_instrument_reference_or_call { bool strict_overflow_p = false; /* tree_single_nonzero_warnv_p will not return true for non-weak - non-automatic decls with -fno-delete-null-pointer-checks, + non-automatic decls with !zero_address_valid, which is disabled during -fsanitize=null. We don't want to instrument those, just weak vars though. */ - int save_flag_delete_null_pointer_checks - = flag_delete_null_pointer_checks; - flag_delete_null_pointer_checks = 1; + int save_flag_sanitize = flag_sanitize; + flag_sanitize &= ~(SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE); if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p) || strict_overflow_p) instrument = true; - flag_delete_null_pointer_checks - = save_flag_delete_null_pointer_checks; + flag_sanitize = save_flag_sanitize; } else if (sanitize_flags_p (SANITIZE_NULL)) instrument = true; --- gcc/ipa-pure-const.cc.jj 2022-02-08 20:08:03.856541480 +0100 +++ gcc/ipa-pure-const.cc 2022-02-09 14:00:45.161889970 +0100 @@ -971,8 +971,7 @@ malloc_candidate_p (function *fun, bool edge_iterator ei; cgraph_node *node = cgraph_node::get_create (fun->decl); - if (EDGE_COUNT (exit_block->preds) == 0 - || !flag_delete_null_pointer_checks) + if (EDGE_COUNT (exit_block->preds) == 0) return false; auto_bitmap visited; @@ -992,6 +991,9 @@ malloc_candidate_p (function *fun, bool || TREE_CODE (TREE_TYPE (retval)) != POINTER_TYPE) DUMP_AND_RETURN("Return value is not SSA_NAME or not a pointer type.") + if (zero_address_valid (TREE_TYPE (retval))) + return false; + if (!malloc_candidate_p_1 (fun, retval, ret_stmt, ipa, visited)) return false; } --- gcc/gimple.cc.jj 2022-02-08 20:08:03.851541549 +0100 +++ gcc/gimple.cc 2022-02-09 13:47:54.762626732 +0100 @@ -1673,19 +1673,22 @@ gimple_call_nonnull_result_p (gcall *cal tree fndecl = gimple_call_fndecl (call); if (!fndecl) return false; - if (flag_delete_null_pointer_checks && !flag_check_new + if (!flag_check_new && DECL_IS_OPERATOR_NEW_P (fndecl) - && !TREE_NOTHROW (fndecl)) + && !TREE_NOTHROW (fndecl) + && POINTER_TYPE_P (TREE_TYPE (fndecl)) + && !zero_address_valid (TREE_TYPE (fndecl))) return true; /* References are always non-NULL. */ - if (flag_delete_null_pointer_checks - && TREE_CODE (TREE_TYPE (fndecl)) == REFERENCE_TYPE) + if (TREE_CODE (TREE_TYPE (fndecl)) == REFERENCE_TYPE + && !zero_address_valid (TREE_TYPE (fndecl))) return true; - if (flag_delete_null_pointer_checks - && lookup_attribute ("returns_nonnull", - TYPE_ATTRIBUTES (gimple_call_fntype (call)))) + tree fntype = gimple_call_fntype (call); + if (lookup_attribute ("returns_nonnull", TYPE_ATTRIBUTES (fntype)) + && POINTER_TYPE_P (TREE_TYPE (fntype)) + && !zero_address_valid (TREE_TYPE (fntype))) return true; return gimple_alloca_call_p (call); } @@ -3033,10 +3036,10 @@ infer_nonnull_range_by_dereference (gimp { /* We can only assume that a pointer dereference will yield non-NULL if -fdelete-null-pointer-checks is enabled. */ - if (!flag_delete_null_pointer_checks - || !POINTER_TYPE_P (TREE_TYPE (op)) + if (!POINTER_TYPE_P (TREE_TYPE (op)) || gimple_code (stmt) == GIMPLE_ASM - || gimple_clobber_p (stmt)) + || gimple_clobber_p (stmt) + || zero_address_valid (TREE_TYPE (TREE_TYPE (op)))) return false; if (walk_stmt_load_store_ops (stmt, (void *)op, @@ -3053,9 +3056,9 @@ infer_nonnull_range_by_attribute (gimple { /* We can only assume that a pointer dereference will yield non-NULL if -fdelete-null-pointer-checks is enabled. */ - if (!flag_delete_null_pointer_checks - || !POINTER_TYPE_P (TREE_TYPE (op)) - || gimple_code (stmt) == GIMPLE_ASM) + if (!POINTER_TYPE_P (TREE_TYPE (op)) + || gimple_code (stmt) == GIMPLE_ASM + || zero_address_valid (TREE_TYPE (TREE_TYPE (op)))) return false; if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt)) --- gcc/fold-const.cc.jj 2022-02-08 20:08:03.800542248 +0100 +++ gcc/fold-const.cc 2022-02-09 13:43:49.947029100 +0100 @@ -10713,13 +10713,16 @@ tree_expr_nonzero_warnv_p (tree t, bool { tree fndecl = get_callee_fndecl (t); if (!fndecl) return false; - if (flag_delete_null_pointer_checks && !flag_check_new + if (!flag_check_new && DECL_IS_OPERATOR_NEW_P (fndecl) - && !TREE_NOTHROW (fndecl)) + && !TREE_NOTHROW (fndecl) + && POINTER_TYPE_P (TREE_TYPE (fndecl)) + && !zero_address_valid (TREE_TYPE (fndecl))) return true; - if (flag_delete_null_pointer_checks - && lookup_attribute ("returns_nonnull", - TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + if (lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl))) + && POINTER_TYPE_P (TREE_TYPE (fndecl)) + && !zero_address_valid (TREE_TYPE (fndecl))) return true; return alloca_call_p (t); } Jakub