1 /* -Wnonnull-compare warning support. 2 Copyright (C) 2016-2018 Free Software Foundation, Inc. 3 Contributed by Jakub Jelinek <jakub@redhat.com> 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "backend.h" 25 #include "tree.h" 26 #include "gimple.h" 27 #include "tree-pass.h" 28 #include "ssa.h" 29 #include "diagnostic-core.h" 30 #include "tree-dfa.h" 31 32 /* Warn about comparison of nonnull_arg_p argument initial values 33 with NULL. */ 34 35 static void 36 do_warn_nonnull_compare (function *fun, tree arg) 37 { 38 if (!POINTER_TYPE_P (TREE_TYPE (arg)) 39 && TREE_CODE (TREE_TYPE (arg)) != OFFSET_TYPE) 40 return; 41 42 if (!nonnull_arg_p (arg)) 43 return; 44 45 tree d = ssa_default_def (fun, arg); 46 if (d == NULL_TREE) 47 return; 48 49 use_operand_p use_p; 50 imm_use_iterator iter; 51 52 FOR_EACH_IMM_USE_FAST (use_p, iter, d) 53 { 54 gimple *stmt = USE_STMT (use_p); 55 tree op = NULL_TREE; 56 location_t loc = gimple_location (stmt); 57 if (gimple_code (stmt) == GIMPLE_COND) 58 switch (gimple_cond_code (stmt)) 59 { 60 case EQ_EXPR: 61 case NE_EXPR: 62 if (gimple_cond_lhs (stmt) == d) 63 op = gimple_cond_rhs (stmt); 64 break; 65 default: 66 break; 67 } 68 else if (is_gimple_assign (stmt)) 69 switch (gimple_assign_rhs_code (stmt)) 70 { 71 case EQ_EXPR: 72 case NE_EXPR: 73 if (gimple_assign_rhs1 (stmt) == d) 74 op = gimple_assign_rhs2 (stmt); 75 break; 76 case COND_EXPR: 77 switch (TREE_CODE (gimple_assign_rhs1 (stmt))) 78 { 79 case EQ_EXPR: 80 case NE_EXPR: 81 op = gimple_assign_rhs1 (stmt); 82 if (TREE_OPERAND (op, 0) != d) 83 { 84 op = NULL_TREE; 85 break; 86 } 87 loc = EXPR_LOC_OR_LOC (op, loc); 88 op = TREE_OPERAND (op, 1); 89 break; 90 default: 91 break; 92 } 93 break; 94 default: 95 break; 96 } 97 if (op 98 && (POINTER_TYPE_P (TREE_TYPE (arg)) 99 ? integer_zerop (op) : integer_minus_onep (op)) 100 && !gimple_no_warning_p (stmt)) 101 warning_at (loc, OPT_Wnonnull_compare, 102 "nonnull argument %qD compared to NULL", arg); 103 } 104 } 105 106 namespace { 107 108 const pass_data pass_data_warn_nonnull_compare = 109 { 110 GIMPLE_PASS, /* type */ 111 "*nonnullcmp", /* name */ 112 OPTGROUP_NONE, /* optinfo_flags */ 113 TV_NONE, /* tv_id */ 114 PROP_ssa, /* properties_required */ 115 0, /* properties_provided */ 116 0, /* properties_destroyed */ 117 0, /* todo_flags_start */ 118 0, /* todo_flags_finish */ 119 }; 120 121 class pass_warn_nonnull_compare : public gimple_opt_pass 122 { 123 public: 124 pass_warn_nonnull_compare (gcc::context *ctxt) 125 : gimple_opt_pass (pass_data_warn_nonnull_compare, ctxt) 126 {} 127 128 /* opt_pass methods: */ 129 virtual bool gate (function *) { return warn_nonnull_compare; } 130 131 virtual unsigned int execute (function *); 132 133 }; // class pass_warn_nonnull_compare 134 135 unsigned int 136 pass_warn_nonnull_compare::execute (function *fun) 137 { 138 if (fun->static_chain_decl) 139 do_warn_nonnull_compare (fun, fun->static_chain_decl); 140 141 for (tree arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg)) 142 do_warn_nonnull_compare (fun, arg); 143 return 0; 144 } 145 146 } // anon namespace 147 148 gimple_opt_pass * 149 make_pass_warn_nonnull_compare (gcc::context *ctxt) 150 { 151 return new pass_warn_nonnull_compare (ctxt); 152 } 153