Improve costs for DImode shifts of interger constants.
[official-gcc.git] / gcc / gimple-array-bounds.cc
blobc2dd6663c3a24db02465a602bdf78f1d253bd5b6
1 /* Array bounds checking.
2 Copyright (C) 2005-2020 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "backend.h"
24 #include "tree.h"
25 #include "gimple.h"
26 #include "ssa.h"
27 #include "gimple-array-bounds.h"
28 #include "gimple-iterator.h"
29 #include "gimple-walk.h"
30 #include "tree-dfa.h"
31 #include "fold-const.h"
32 #include "diagnostic-core.h"
33 #include "intl.h"
34 #include "tree-vrp.h"
35 #include "alloc-pool.h"
36 #include "vr-values.h"
37 #include "domwalk.h"
38 #include "tree-cfg.h"
40 // This purposely returns a value_range, not a value_range_equiv, to
41 // break the dependency on equivalences for this pass.
43 const value_range *
44 array_bounds_checker::get_value_range (const_tree op)
46 return ranges->get_value_range (op);
49 /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
50 arrays and "struct" hacks. If VRP can determine that the array
51 subscript is a constant, check if it is outside valid range. If
52 the array subscript is a RANGE, warn if it is non-overlapping with
53 valid range. IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
54 a ADDR_EXPR. Returns true if a warning has been issued. */
56 bool
57 array_bounds_checker::check_array_ref (location_t location, tree ref,
58 bool ignore_off_by_one)
60 if (TREE_NO_WARNING (ref))
61 return false;
63 tree low_sub = TREE_OPERAND (ref, 1);
64 tree up_sub = low_sub;
65 tree up_bound = array_ref_up_bound (ref);
67 /* Referenced decl if one can be determined. */
68 tree decl = NULL_TREE;
70 /* Set for accesses to interior zero-length arrays. */
71 bool interior_zero_len = false;
73 tree up_bound_p1;
75 if (!up_bound
76 || TREE_CODE (up_bound) != INTEGER_CST
77 || (warn_array_bounds < 2
78 && array_at_struct_end_p (ref)))
80 /* Accesses to trailing arrays via pointers may access storage
81 beyond the types array bounds. For such arrays, or for flexible
82 array members, as well as for other arrays of an unknown size,
83 replace the upper bound with a more permissive one that assumes
84 the size of the largest object is PTRDIFF_MAX. */
85 tree eltsize = array_ref_element_size (ref);
87 if (TREE_CODE (eltsize) != INTEGER_CST
88 || integer_zerop (eltsize))
90 up_bound = NULL_TREE;
91 up_bound_p1 = NULL_TREE;
93 else
95 tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node);
96 tree maxbound = ptrdiff_max;
97 tree arg = TREE_OPERAND (ref, 0);
99 const bool compref = TREE_CODE (arg) == COMPONENT_REF;
100 if (compref)
102 /* Try to determine the size of the trailing array from
103 its initializer (if it has one). */
104 if (tree refsize = component_ref_size (arg, &interior_zero_len))
105 if (TREE_CODE (refsize) == INTEGER_CST)
106 maxbound = refsize;
109 if (maxbound == ptrdiff_max)
111 /* Try to determine the size of the base object. Avoid
112 COMPONENT_REF already tried above. Using its DECL_SIZE
113 size wouldn't necessarily be correct if the reference is
114 to its flexible array member initialized in a different
115 translation unit. */
116 poly_int64 off;
117 if (tree base = get_addr_base_and_unit_offset (arg, &off))
119 if (!compref && DECL_P (base))
120 if (tree basesize = DECL_SIZE_UNIT (base))
121 if (TREE_CODE (basesize) == INTEGER_CST)
123 maxbound = basesize;
124 decl = base;
127 if (known_gt (off, 0))
128 maxbound = wide_int_to_tree (sizetype,
129 wi::sub (wi::to_wide (maxbound),
130 off));
133 else
134 maxbound = fold_convert (sizetype, maxbound);
136 up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
138 if (up_bound_p1 != NULL_TREE)
139 up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
140 build_int_cst (ptrdiff_type_node, 1));
141 else
142 up_bound = NULL_TREE;
145 else
146 up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
147 build_int_cst (TREE_TYPE (up_bound), 1));
149 tree low_bound = array_ref_low_bound (ref);
151 tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
153 bool warned = false;
155 /* Empty array. */
156 if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
157 warned = warning_at (location, OPT_Warray_bounds,
158 "array subscript %E is outside array bounds of %qT",
159 low_sub, artype);
161 const value_range *vr = NULL;
162 if (TREE_CODE (low_sub) == SSA_NAME)
164 vr = get_value_range (low_sub);
165 if (!vr->undefined_p () && !vr->varying_p ())
167 low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
168 up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
172 if (warned)
173 ; /* Do nothing. */
174 else if (vr && vr->kind () == VR_ANTI_RANGE)
176 if (up_bound
177 && TREE_CODE (up_sub) == INTEGER_CST
178 && (ignore_off_by_one
179 ? tree_int_cst_lt (up_bound, up_sub)
180 : tree_int_cst_le (up_bound, up_sub))
181 && TREE_CODE (low_sub) == INTEGER_CST
182 && tree_int_cst_le (low_sub, low_bound))
183 warned = warning_at (location, OPT_Warray_bounds,
184 "array subscript [%E, %E] is outside "
185 "array bounds of %qT",
186 low_sub, up_sub, artype);
188 else if (up_bound
189 && TREE_CODE (up_sub) == INTEGER_CST
190 && (ignore_off_by_one
191 ? !tree_int_cst_le (up_sub, up_bound_p1)
192 : !tree_int_cst_le (up_sub, up_bound)))
193 warned = warning_at (location, OPT_Warray_bounds,
194 "array subscript %E is above array bounds of %qT",
195 up_sub, artype);
196 else if (TREE_CODE (low_sub) == INTEGER_CST
197 && tree_int_cst_lt (low_sub, low_bound))
198 warned = warning_at (location, OPT_Warray_bounds,
199 "array subscript %E is below array bounds of %qT",
200 low_sub, artype);
202 if (!warned && interior_zero_len)
203 warned = warning_at (location, OPT_Wzero_length_bounds,
204 (TREE_CODE (low_sub) == INTEGER_CST
205 ? G_("array subscript %E is outside the bounds "
206 "of an interior zero-length array %qT")
207 : G_("array subscript %qE is outside the bounds "
208 "of an interior zero-length array %qT")),
209 low_sub, artype);
211 if (warned)
213 if (dump_file && (dump_flags & TDF_DETAILS))
215 fprintf (dump_file, "Array bound warning for ");
216 dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
217 fprintf (dump_file, "\n");
220 ref = decl ? decl : TREE_OPERAND (ref, 0);
222 tree rec = NULL_TREE;
223 if (TREE_CODE (ref) == COMPONENT_REF)
225 /* For a reference to a member of a struct object also mention
226 the object if it's known. It may be defined in a different
227 function than the out-of-bounds access. */
228 rec = TREE_OPERAND (ref, 0);
229 if (!VAR_P (rec))
230 rec = NULL_TREE;
231 ref = TREE_OPERAND (ref, 1);
234 if (DECL_P (ref))
235 inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
236 if (rec && DECL_P (rec))
237 inform (DECL_SOURCE_LOCATION (rec), "defined here %qD", rec);
239 TREE_NO_WARNING (ref) = 1;
242 return warned;
245 /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
246 references to string constants. If VRP can determine that the array
247 subscript is a constant, check if it is outside valid range.
248 If the array subscript is a RANGE, warn if it is non-overlapping
249 with valid range.
250 IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
251 (used to allow one-past-the-end indices for code that takes
252 the address of the just-past-the-end element of an array).
253 Returns true if a warning has been issued. */
255 bool
256 array_bounds_checker::check_mem_ref (location_t location, tree ref,
257 bool ignore_off_by_one)
259 if (TREE_NO_WARNING (ref))
260 return false;
262 tree arg = TREE_OPERAND (ref, 0);
263 /* The constant and variable offset of the reference. */
264 tree cstoff = TREE_OPERAND (ref, 1);
265 tree varoff = NULL_TREE;
267 const offset_int maxobjsize = tree_to_shwi (max_object_size ());
269 /* The array or string constant bounds in bytes. Initially set
270 to [-MAXOBJSIZE - 1, MAXOBJSIZE] until a tighter bound is
271 determined. */
272 offset_int arrbounds[2] = { -maxobjsize - 1, maxobjsize };
274 /* The minimum and maximum intermediate offset. For a reference
275 to be valid, not only does the final offset/subscript must be
276 in bounds but all intermediate offsets should be as well.
277 GCC may be able to deal gracefully with such out-of-bounds
278 offsets so the checking is only enbaled at -Warray-bounds=2
279 where it may help detect bugs in uses of the intermediate
280 offsets that could otherwise not be detectable. */
281 offset_int ioff = wi::to_offset (fold_convert (ptrdiff_type_node, cstoff));
282 offset_int extrema[2] = { 0, wi::abs (ioff) };
284 /* The range of the byte offset into the reference. */
285 offset_int offrange[2] = { 0, 0 };
287 const value_range *vr = NULL;
289 /* Determine the offsets and increment OFFRANGE for the bounds of each.
290 The loop computes the range of the final offset for expressions such
291 as (A + i0 + ... + iN)[CSTOFF] where i0 through iN are SSA_NAMEs in
292 some range. */
293 const unsigned limit = param_ssa_name_def_chain_limit;
294 for (unsigned n = 0; TREE_CODE (arg) == SSA_NAME && n < limit; ++n)
296 gimple *def = SSA_NAME_DEF_STMT (arg);
297 if (!is_gimple_assign (def))
298 break;
300 tree_code code = gimple_assign_rhs_code (def);
301 if (code == POINTER_PLUS_EXPR)
303 arg = gimple_assign_rhs1 (def);
304 varoff = gimple_assign_rhs2 (def);
306 else if (code == ASSERT_EXPR)
308 arg = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
309 continue;
311 else
312 return false;
314 /* VAROFF should always be a SSA_NAME here (and not even
315 INTEGER_CST) but there's no point in taking chances. */
316 if (TREE_CODE (varoff) != SSA_NAME)
317 break;
319 vr = get_value_range (varoff);
320 if (!vr || vr->undefined_p () || vr->varying_p ())
321 break;
323 if (!vr->constant_p ())
324 break;
326 if (vr->kind () == VR_RANGE)
328 offset_int min
329 = wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
330 offset_int max
331 = wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
332 if (min < max)
334 offrange[0] += min;
335 offrange[1] += max;
337 else
339 /* When MIN >= MAX, the offset is effectively in a union
340 of two ranges: [-MAXOBJSIZE -1, MAX] and [MIN, MAXOBJSIZE].
341 Since there is no way to represent such a range across
342 additions, conservatively add [-MAXOBJSIZE -1, MAXOBJSIZE]
343 to OFFRANGE. */
344 offrange[0] += arrbounds[0];
345 offrange[1] += arrbounds[1];
348 else
350 /* For an anti-range, analogously to the above, conservatively
351 add [-MAXOBJSIZE -1, MAXOBJSIZE] to OFFRANGE. */
352 offrange[0] += arrbounds[0];
353 offrange[1] += arrbounds[1];
356 /* Keep track of the minimum and maximum offset. */
357 if (offrange[1] < 0 && offrange[1] < extrema[0])
358 extrema[0] = offrange[1];
359 if (offrange[0] > 0 && offrange[0] > extrema[1])
360 extrema[1] = offrange[0];
362 if (offrange[0] < arrbounds[0])
363 offrange[0] = arrbounds[0];
365 if (offrange[1] > arrbounds[1])
366 offrange[1] = arrbounds[1];
369 if (TREE_CODE (arg) == ADDR_EXPR)
371 arg = TREE_OPERAND (arg, 0);
372 if (TREE_CODE (arg) != STRING_CST
373 && TREE_CODE (arg) != PARM_DECL
374 && TREE_CODE (arg) != VAR_DECL)
375 return false;
377 else
378 return false;
380 /* The type of the object being referred to. It can be an array,
381 string literal, or a non-array type when the MEM_REF represents
382 a reference/subscript via a pointer to an object that is not
383 an element of an array. Incomplete types are excluded as well
384 because their size is not known. */
385 tree reftype = TREE_TYPE (arg);
386 if (POINTER_TYPE_P (reftype)
387 || !COMPLETE_TYPE_P (reftype)
388 || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST)
389 return false;
391 /* Except in declared objects, references to trailing array members
392 of structs and union objects are excluded because MEM_REF doesn't
393 make it possible to identify the member where the reference
394 originated. */
395 if (RECORD_OR_UNION_TYPE_P (reftype)
396 && (!VAR_P (arg)
397 || (DECL_EXTERNAL (arg) && array_at_struct_end_p (ref))))
398 return false;
400 arrbounds[0] = 0;
402 offset_int eltsize;
403 if (TREE_CODE (reftype) == ARRAY_TYPE)
405 eltsize = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (reftype)));
406 if (tree dom = TYPE_DOMAIN (reftype))
408 tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
409 if (TREE_CODE (arg) == COMPONENT_REF)
411 offset_int size = maxobjsize;
412 if (tree fldsize = component_ref_size (arg))
413 size = wi::to_offset (fldsize);
414 arrbounds[1] = wi::lrshift (size, wi::floor_log2 (eltsize));
416 else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
417 arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
418 else
419 arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset (bnds[0])
420 + 1) * eltsize;
422 else
423 arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
425 /* Determine a tighter bound of the non-array element type. */
426 tree eltype = TREE_TYPE (reftype);
427 while (TREE_CODE (eltype) == ARRAY_TYPE)
428 eltype = TREE_TYPE (eltype);
429 eltsize = wi::to_offset (TYPE_SIZE_UNIT (eltype));
431 else
433 eltsize = 1;
434 tree size = TYPE_SIZE_UNIT (reftype);
435 if (VAR_P (arg))
436 if (tree initsize = DECL_SIZE_UNIT (arg))
437 if (tree_int_cst_lt (size, initsize))
438 size = initsize;
440 arrbounds[1] = wi::to_offset (size);
443 offrange[0] += ioff;
444 offrange[1] += ioff;
446 /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
447 is set (when taking the address of the one-past-last element
448 of an array) but always use the stricter bound in diagnostics. */
449 offset_int ubound = arrbounds[1];
450 if (ignore_off_by_one)
451 ubound += 1;
453 if (arrbounds[0] == arrbounds[1]
454 || offrange[0] >= ubound
455 || offrange[1] < arrbounds[0])
457 /* Treat a reference to a non-array object as one to an array
458 of a single element. */
459 if (TREE_CODE (reftype) != ARRAY_TYPE)
460 reftype = build_array_type_nelts (reftype, 1);
462 /* Extract the element type out of MEM_REF and use its size
463 to compute the index to print in the diagnostic; arrays
464 in MEM_REF don't mean anything. A type with no size like
465 void is as good as having a size of 1. */
466 tree type = TREE_TYPE (ref);
467 while (TREE_CODE (type) == ARRAY_TYPE)
468 type = TREE_TYPE (type);
469 if (tree size = TYPE_SIZE_UNIT (type))
471 offrange[0] = offrange[0] / wi::to_offset (size);
472 offrange[1] = offrange[1] / wi::to_offset (size);
475 bool warned;
476 if (offrange[0] == offrange[1])
477 warned = warning_at (location, OPT_Warray_bounds,
478 "array subscript %wi is outside array bounds "
479 "of %qT",
480 offrange[0].to_shwi (), reftype);
481 else
482 warned = warning_at (location, OPT_Warray_bounds,
483 "array subscript [%wi, %wi] is outside "
484 "array bounds of %qT",
485 offrange[0].to_shwi (),
486 offrange[1].to_shwi (), reftype);
487 if (warned && DECL_P (arg))
488 inform (DECL_SOURCE_LOCATION (arg), "while referencing %qD", arg);
490 if (warned)
491 TREE_NO_WARNING (ref) = 1;
492 return warned;
495 if (warn_array_bounds < 2)
496 return false;
498 /* At level 2 check also intermediate offsets. */
499 int i = 0;
500 if (extrema[i] < -arrbounds[1] || extrema[i = 1] > ubound)
502 HOST_WIDE_INT tmpidx = extrema[i].to_shwi () / eltsize.to_shwi ();
504 if (warning_at (location, OPT_Warray_bounds,
505 "intermediate array offset %wi is outside array bounds "
506 "of %qT", tmpidx, reftype))
508 TREE_NO_WARNING (ref) = 1;
509 return true;
513 return false;
516 /* Searches if the expr T, located at LOCATION computes
517 address of an ARRAY_REF, and call check_array_ref on it. */
519 void
520 array_bounds_checker::check_addr_expr (location_t location, tree t)
522 /* For the most significant subscript only, accept taking the address
523 of the just-past-the-end element. */
524 bool ignore_off_by_one = true;
526 /* Check each ARRAY_REF and MEM_REF in the reference chain. */
529 bool warned = false;
530 if (TREE_CODE (t) == ARRAY_REF)
532 warned = check_array_ref (location, t, ignore_off_by_one);
533 ignore_off_by_one = false;
535 else if (TREE_CODE (t) == MEM_REF)
536 warned = check_mem_ref (location, t, ignore_off_by_one);
538 if (warned)
539 TREE_NO_WARNING (t) = true;
541 t = TREE_OPERAND (t, 0);
543 while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
545 if (TREE_CODE (t) != MEM_REF
546 || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
547 || TREE_NO_WARNING (t))
548 return;
550 tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
551 tree low_bound, up_bound, el_sz;
552 if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
553 || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
554 || !TYPE_DOMAIN (TREE_TYPE (tem)))
555 return;
557 low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
558 up_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
559 el_sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (tem)));
560 if (!low_bound
561 || TREE_CODE (low_bound) != INTEGER_CST
562 || !up_bound
563 || TREE_CODE (up_bound) != INTEGER_CST
564 || !el_sz
565 || TREE_CODE (el_sz) != INTEGER_CST)
566 return;
568 offset_int idx;
569 if (!mem_ref_offset (t).is_constant (&idx))
570 return;
572 bool warned = false;
573 idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
574 if (idx < 0)
576 if (dump_file && (dump_flags & TDF_DETAILS))
578 fprintf (dump_file, "Array bound warning for ");
579 dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
580 fprintf (dump_file, "\n");
582 warned = warning_at (location, OPT_Warray_bounds,
583 "array subscript %wi is below "
584 "array bounds of %qT",
585 idx.to_shwi (), TREE_TYPE (tem));
587 else if (idx > (wi::to_offset (up_bound)
588 - wi::to_offset (low_bound) + 1))
590 if (dump_file && (dump_flags & TDF_DETAILS))
592 fprintf (dump_file, "Array bound warning for ");
593 dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
594 fprintf (dump_file, "\n");
596 warned = warning_at (location, OPT_Warray_bounds,
597 "array subscript %wu is above "
598 "array bounds of %qT",
599 idx.to_uhwi (), TREE_TYPE (tem));
602 if (warned)
604 if (DECL_P (t))
605 inform (DECL_SOURCE_LOCATION (t), "while referencing %qD", t);
607 TREE_NO_WARNING (t) = 1;
611 /* Callback for walk_tree to check a tree for out of bounds array
612 accesses. The array_bounds_checker class is passed in DATA. */
614 tree
615 array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
616 void *data)
618 tree t = *tp;
619 struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
620 location_t location;
622 if (EXPR_HAS_LOCATION (t))
623 location = EXPR_LOCATION (t);
624 else
625 location = gimple_location (wi->stmt);
627 *walk_subtree = TRUE;
629 bool warned = false;
630 array_bounds_checker *checker = (array_bounds_checker *) wi->info;
631 if (TREE_CODE (t) == ARRAY_REF)
632 warned = checker->check_array_ref (location, t,
633 false/*ignore_off_by_one*/);
634 else if (TREE_CODE (t) == MEM_REF)
635 warned = checker->check_mem_ref (location, t,
636 false /*ignore_off_by_one*/);
637 else if (TREE_CODE (t) == ADDR_EXPR)
639 checker->check_addr_expr (location, t);
640 *walk_subtree = FALSE;
642 /* Propagate the no-warning bit to the outer expression. */
643 if (warned)
644 TREE_NO_WARNING (t) = true;
646 return NULL_TREE;
649 /* A dom_walker subclass for use by check_all_array_refs, to walk over
650 all statements of all reachable BBs and call check_array_bounds on
651 them. */
653 class check_array_bounds_dom_walker : public dom_walker
655 public:
656 check_array_bounds_dom_walker (array_bounds_checker *checker)
657 : dom_walker (CDI_DOMINATORS,
658 /* Discover non-executable edges, preserving EDGE_EXECUTABLE
659 flags, so that we can merge in information on
660 non-executable edges from vrp_folder . */
661 REACHABLE_BLOCKS_PRESERVING_FLAGS),
662 checker (checker) { }
663 ~check_array_bounds_dom_walker () {}
665 edge before_dom_children (basic_block) FINAL OVERRIDE;
667 private:
668 array_bounds_checker *checker;
671 /* Implementation of dom_walker::before_dom_children.
673 Walk over all statements of BB and call check_array_bounds on them,
674 and determine if there's a unique successor edge. */
676 edge
677 check_array_bounds_dom_walker::before_dom_children (basic_block bb)
679 gimple_stmt_iterator si;
680 for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
682 gimple *stmt = gsi_stmt (si);
683 struct walk_stmt_info wi;
684 if (!gimple_has_location (stmt)
685 || is_gimple_debug (stmt))
686 continue;
688 memset (&wi, 0, sizeof (wi));
690 wi.info = checker;
692 walk_gimple_op (stmt, array_bounds_checker::check_array_bounds, &wi);
695 /* Determine if there's a unique successor edge, and if so, return
696 that back to dom_walker, ensuring that we don't visit blocks that
697 became unreachable during the VRP propagation
698 (PR tree-optimization/83312). */
699 return find_taken_edge (bb, NULL_TREE);
702 void
703 array_bounds_checker::check ()
705 check_array_bounds_dom_walker w (this);
706 w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));