Newer
Older
gimplify_ctxp->exit_label = saved_label;
*expr_p = NULL;
return GS_ALL_DONE;
}
/* Gimplify a statement list onto a sequence. These may be created either
by an enlightened front-end, or by shortcut_cond_expr. */
static enum gimplify_status
gimplify_statement_list (tree *expr_p, gimple_seq *pre_p)
{
tree temp = voidify_wrapper_expr (*expr_p, NULL);
tree_stmt_iterator i = tsi_start (*expr_p);
while (!tsi_end_p (i))
gimplify_stmt (tsi_stmt_ptr (i), pre_p);
tsi_delink (&i);
if (temp)
{
*expr_p = temp;
return GS_OK;
}
return GS_ALL_DONE;
}
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
/* Emit warning for the unreachable statment STMT if needed.
Return the gimple itself when the warning is emitted, otherwise
return NULL. */
static gimple *
emit_warn_switch_unreachable (gimple *stmt)
{
if (gimple_code (stmt) == GIMPLE_GOTO
&& TREE_CODE (gimple_goto_dest (stmt)) == LABEL_DECL
&& DECL_ARTIFICIAL (gimple_goto_dest (stmt)))
/* Don't warn for compiler-generated gotos. These occur
in Duff's devices, for example. */
return NULL;
else if ((flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
&& ((gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
|| (gimple_call_builtin_p (stmt, BUILT_IN_CLEAR_PADDING)
&& (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)))
|| (is_gimple_assign (stmt)
&& gimple_assign_single_p (stmt)
&& (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
&& gimple_call_internal_p (
SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)),
IFN_DEFERRED_INIT))))
/* Don't warn for compiler-generated initializations for
-ftrivial-auto-var-init.
There are 3 cases:
case 1: a call to .DEFERRED_INIT;
case 2: a call to __builtin_clear_padding with the 2nd argument is
present and non-zero;
case 3: a gimple assign store right after the call to .DEFERRED_INIT
that has the LHS of .DEFERRED_INIT as the RHS as following:
_1 = .DEFERRED_INIT (4, 2, &"i1"[0]);
i1 = _1. */
return NULL;
else
warning_at (gimple_location (stmt), OPT_Wswitch_unreachable,
"statement will never be executed");
return stmt;
}
Marek Polacek
committed
/* Callback for walk_gimple_seq. */
static tree
warn_switch_unreachable_and_auto_init_r (gimple_stmt_iterator *gsi_p,
bool *handled_ops_p,
struct walk_stmt_info *wi)
Marek Polacek
committed
{
gimple *stmt = gsi_stmt (*gsi_p);
bool unreachable_issued = wi->info != NULL;
Marek Polacek
committed
*handled_ops_p = true;
switch (gimple_code (stmt))
{
case GIMPLE_TRY:
/* A compiler-generated cleanup or a user-written try block.
If it's empty, don't dive into it--that would result in
worse location info. */
if (gimple_try_eval (stmt) == NULL)
{
if (warn_switch_unreachable && !unreachable_issued)
wi->info = emit_warn_switch_unreachable (stmt);
/* Stop when auto var init warning is not on. */
if (!warn_trivial_auto_var_init)
return integer_zero_node;
Marek Polacek
committed
}
/* Fall through. */
case GIMPLE_BIND:
case GIMPLE_CATCH:
case GIMPLE_EH_FILTER:
case GIMPLE_TRANSACTION:
/* Walk the sub-statements. */
*handled_ops_p = false;
break;
case GIMPLE_DEBUG:
/* Ignore these. We may generate them before declarations that
are never executed. If there's something to warn about,
there will be non-debug stmts too, and we'll catch those. */
break;
case GIMPLE_LABEL:
/* Stop till the first Label. */
return integer_zero_node;
case GIMPLE_CALL:
if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
{
*handled_ops_p = false;
break;
}
if (warn_trivial_auto_var_init
&& flag_auto_var_init > AUTO_INIT_UNINITIALIZED
&& gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
{
/* Get the variable name from the 3rd argument of call. */
tree var_name = gimple_call_arg (stmt, 2);
var_name = TREE_OPERAND (TREE_OPERAND (var_name, 0), 0);
const char *var_name_str = TREE_STRING_POINTER (var_name);
warning_at (gimple_location (stmt), OPT_Wtrivial_auto_var_init,
"%qs cannot be initialized with"
"%<-ftrivial-auto-var_init%>",
var_name_str);
break;
}
Marek Polacek
committed
default:
/* check the first "real" statement (not a decl/lexical scope/...), issue
warning if needed. */
if (warn_switch_unreachable && !unreachable_issued)
wi->info = emit_warn_switch_unreachable (stmt);
/* Stop when auto var init warning is not on. */
if (!warn_trivial_auto_var_init)
return integer_zero_node;
break;
Marek Polacek
committed
}
return NULL_TREE;
}
Marek Polacek
committed
/* Possibly warn about unreachable statements between switch's controlling
expression and the first case. Also warn about -ftrivial-auto-var-init
cannot initialize the auto variable under such situation.
SEQ is the body of a switch expression. */
Marek Polacek
committed
static void
maybe_warn_switch_unreachable_and_auto_init (gimple_seq seq)
Marek Polacek
committed
{
if ((!warn_switch_unreachable && !warn_trivial_auto_var_init)
Marek Polacek
committed
/* This warning doesn't play well with Fortran when optimizations
are on. */
|| lang_GNU_Fortran ()
|| seq == NULL)
return;
struct walk_stmt_info wi;
memset (&wi, 0, sizeof (wi));
walk_gimple_seq (seq, warn_switch_unreachable_and_auto_init_r, NULL, &wi);
Marek Polacek
committed
}
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
/* A label entry that pairs label and a location. */
struct label_entry
{
tree label;
location_t loc;
};
/* Find LABEL in vector of label entries VEC. */
static struct label_entry *
find_label_entry (const auto_vec<struct label_entry> *vec, tree label)
{
unsigned int i;
struct label_entry *l;
FOR_EACH_VEC_ELT (*vec, i, l)
if (l->label == label)
return l;
return NULL;
}
/* Return true if LABEL, a LABEL_DECL, represents a case label
in a vector of labels CASES. */
static bool
case_label_p (const vec<tree> *cases, tree label)
{
unsigned int i;
tree l;
FOR_EACH_VEC_ELT (*cases, i, l)
if (CASE_LABEL (l) == label)
return true;
return false;
}
Alexandre Oliva
committed
/* Find the last nondebug statement in a scope STMT. */
static gimple *
last_stmt_in_scope (gimple *stmt)
{
if (!stmt)
return NULL;
switch (gimple_code (stmt))
{
case GIMPLE_BIND:
{
gbind *bind = as_a <gbind *> (stmt);
Alexandre Oliva
committed
stmt = gimple_seq_last_nondebug_stmt (gimple_bind_body (bind));
return last_stmt_in_scope (stmt);
}
case GIMPLE_TRY:
{
gtry *try_stmt = as_a <gtry *> (stmt);
Alexandre Oliva
committed
stmt = gimple_seq_last_nondebug_stmt (gimple_try_eval (try_stmt));
gimple *last_eval = last_stmt_in_scope (stmt);
if (gimple_stmt_may_fallthru (last_eval)
&& (last_eval == NULL
|| !gimple_call_internal_p (last_eval, IFN_FALLTHROUGH))
&& gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
{
Alexandre Oliva
committed
stmt = gimple_seq_last_nondebug_stmt (gimple_try_cleanup (try_stmt));
return last_stmt_in_scope (stmt);
}
else
return last_eval;
}
Alexandre Oliva
committed
case GIMPLE_DEBUG:
gcc_unreachable ();
default:
return stmt;
}
}
/* Collect labels that may fall through into LABELS and return the statement
preceding another case label, or a user-defined label. Store a location
useful to give warnings at *PREVLOC (usually the location of the returned
static gimple *
collect_fallthrough_labels (gimple_stmt_iterator *gsi_p,
auto_vec <struct label_entry> *labels,
location_t *prevloc)
*prevloc = UNKNOWN_LOCATION;
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_BIND)
{
/* Recognize the special GIMPLE_BIND added by gimplify_switch_expr,
which starts on a GIMPLE_SWITCH and ends with a break label.
Handle that as a single statement that can fall through. */
gbind *bind = as_a <gbind *> (gsi_stmt (*gsi_p));
gimple *first = gimple_seq_first_stmt (gimple_bind_body (bind));
gimple *last = gimple_seq_last_stmt (gimple_bind_body (bind));
if (last
&& gimple_code (first) == GIMPLE_SWITCH
&& gimple_code (last) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (last));
if (SWITCH_BREAK_LABEL_P (label))
{
prev = bind;
gsi_next (gsi_p);
continue;
}
}
}
if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_BIND
|| gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_TRY)
{
/* Nested scope. Only look at the last statement of
the innermost scope. */
location_t bind_loc = gimple_location (gsi_stmt (*gsi_p));
gimple *last = last_stmt_in_scope (gsi_stmt (*gsi_p));
if (last)
{
prev = last;
/* It might be a label without a location. Use the
location of the scope then. */
if (!gimple_has_location (prev))
*prevloc = bind_loc;
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
}
gsi_next (gsi_p);
continue;
}
/* Ifs are tricky. */
if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_COND)
{
gcond *cond_stmt = as_a <gcond *> (gsi_stmt (*gsi_p));
tree false_lab = gimple_cond_false_label (cond_stmt);
location_t if_loc = gimple_location (cond_stmt);
/* If we have e.g.
if (i > 1) goto <D.2259>; else goto D;
we can't do much with the else-branch. */
if (!DECL_ARTIFICIAL (false_lab))
break;
/* Go on until the false label, then one step back. */
for (; !gsi_end_p (*gsi_p); gsi_next (gsi_p))
{
gimple *stmt = gsi_stmt (*gsi_p);
if (gimple_code (stmt) == GIMPLE_LABEL
&& gimple_label_label (as_a <glabel *> (stmt)) == false_lab)
break;
}
/* Not found? Oops. */
if (gsi_end_p (*gsi_p))
break;
/* A dead label can't fall through. */
if (!UNUSED_LABEL_P (false_lab))
{
struct label_entry l = { false_lab, if_loc };
labels->safe_push (l);
}
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
/* Go to the last statement of the then branch. */
gsi_prev (gsi_p);
/* if (i != 0) goto <D.1759>; else goto <D.1760>;
<D.1759>:
<stmt>;
goto <D.1761>;
<D.1760>:
*/
if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO
&& !gimple_has_location (gsi_stmt (*gsi_p)))
{
/* Look at the statement before, it might be
attribute fallthrough, in which case don't warn. */
gsi_prev (gsi_p);
bool fallthru_before_dest
= gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_FALLTHROUGH);
gsi_next (gsi_p);
tree goto_dest = gimple_goto_dest (gsi_stmt (*gsi_p));
if (!fallthru_before_dest)
{
struct label_entry l = { goto_dest, if_loc };
labels->safe_push (l);
}
}
/* This case is about
if (1 != 0) goto <D.2022>; else goto <D.2023>;
<D.2022>:
n = n + 1; // #1
<D.2023>: // #2
<D.1988>: // #3
where #2 is UNUSED_LABEL_P and we want to warn about #1 falling
through to #3. So set PREV to #1. */
else if (UNUSED_LABEL_P (false_lab))
prev = gsi_stmt (*gsi_p);
/* And move back. */
gsi_next (gsi_p);
}
/* Remember the last statement. Skip labels that are of no interest
to us. */
if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (*gsi_p)));
if (find_label_entry (labels, label))
prev = gsi_stmt (*gsi_p);
}
else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK))
;
Jakub Jelinek
committed
else if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_PREDICT)
;
Alexandre Oliva
committed
else if (!is_gimple_debug (gsi_stmt (*gsi_p)))
prev = gsi_stmt (*gsi_p);
gsi_next (gsi_p);
}
while (!gsi_end_p (*gsi_p)
/* Stop if we find a case or a user-defined label. */
&& (gimple_code (gsi_stmt (*gsi_p)) != GIMPLE_LABEL
|| !gimple_has_location (gsi_stmt (*gsi_p))));
if (prev && gimple_has_location (prev))
*prevloc = gimple_location (prev);
return prev;
}
/* Return true if the switch fallthough warning should occur. LABEL is
the label statement that we're falling through to. */
static bool
should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
{
gimple_stmt_iterator gsi = *gsi_p;
Marek Polacek
committed
/* Don't warn if the label is marked with a "falls through" comment. */
if (FALLTHROUGH_LABEL_P (label))
return false;
Marek Polacek
committed
/* Don't warn for non-case labels followed by a statement:
case 0:
foo ();
label:
bar ();
as these are likely intentional. */
if (!case_label_p (&gimplify_ctxp->case_labels, label))
{
Marek Polacek
committed
tree l;
while (!gsi_end_p (gsi)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
&& (l = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi))))
&& !case_label_p (&gimplify_ctxp->case_labels, l))
Alexandre Oliva
committed
gsi_next_nondebug (&gsi);
if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
return false;
}
/* Don't warn for terminated branches, i.e. when the subsequent case labels
immediately breaks. */
gsi = *gsi_p;
/* Skip all immediately following labels. */
while (!gsi_end_p (gsi)
&& (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT))
Alexandre Oliva
committed
gsi_next_nondebug (&gsi);
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
/* { ... something; default:; } */
if (gsi_end_p (gsi)
/* { ... something; default: break; } or
{ ... something; default: goto L; } */
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_GOTO
/* { ... something; default: return; } */
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN)
return false;
return true;
}
/* Callback for walk_gimple_seq. */
static tree
warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
struct walk_stmt_info *)
{
gimple *stmt = gsi_stmt (*gsi_p);
*handled_ops_p = true;
switch (gimple_code (stmt))
{
case GIMPLE_TRY:
case GIMPLE_BIND:
case GIMPLE_CATCH:
case GIMPLE_EH_FILTER:
case GIMPLE_TRANSACTION:
/* Walk the sub-statements. */
*handled_ops_p = false;
break;
/* Find a sequence of form:
GIMPLE_LABEL
[...]
<may fallthru stmt>
GIMPLE_LABEL
and possibly warn. */
case GIMPLE_LABEL:
{
/* Found a label. Skip all immediately following labels. */
while (!gsi_end_p (*gsi_p)
&& gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL)
Alexandre Oliva
committed
gsi_next_nondebug (gsi_p);
/* There might be no more statements. */
if (gsi_end_p (*gsi_p))
return integer_zero_node;
/* Vector of labels that fall through. */
auto_vec <struct label_entry> labels;
location_t prevloc;
gimple *prev = collect_fallthrough_labels (gsi_p, &labels, &prevloc);
/* There might be no more statements. */
if (gsi_end_p (*gsi_p))
return integer_zero_node;
gimple *next = gsi_stmt (*gsi_p);
tree label;
/* If what follows is a label, then we may have a fallthrough. */
if (gimple_code (next) == GIMPLE_LABEL
&& gimple_has_location (next)
&& (label = gimple_label_label (as_a <glabel *> (next)))
&& prev != NULL)
{
struct label_entry *l;
bool warned_p = false;
auto_diagnostic_group d;
if (!should_warn_for_implicit_fallthrough (gsi_p, label))
/* Quiet. */;
else if (gimple_code (prev) == GIMPLE_LABEL
&& (label = gimple_label_label (as_a <glabel *> (prev)))
&& (l = find_label_entry (&labels, label)))
"this statement may fall through");
else if (!gimple_call_internal_p (prev, IFN_FALLTHROUGH)
/* Try to be clever and don't warn when the statement
can't actually fall through. */
&& gimple_stmt_may_fallthru (prev)
&& prevloc != UNKNOWN_LOCATION)
warned_p = warning_at (prevloc,
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
"this statement may fall through");
if (warned_p)
inform (gimple_location (next), "here");
/* Mark this label as processed so as to prevent multiple
warnings in nested switches. */
FALLTHROUGH_LABEL_P (label) = true;
/* So that next warn_implicit_fallthrough_r will start looking for
a new sequence starting with this label. */
gsi_prev (gsi_p);
}
}
break;
default:
break;
}
return NULL_TREE;
}
/* Warn when a switch case falls through. */
static void
maybe_warn_implicit_fallthrough (gimple_seq seq)
{
if (!warn_implicit_fallthrough)
return;
/* This warning is meant for C/C++/ObjC/ObjC++ only. */
if (!(lang_GNU_C ()
|| lang_GNU_CXX ()
|| lang_GNU_OBJC ()))
return;
struct walk_stmt_info wi;
memset (&wi, 0, sizeof (wi));
walk_gimple_seq (seq, warn_implicit_fallthrough_r, NULL, &wi);
}
/* Callback for walk_gimple_seq. */
static tree
expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
struct walk_stmt_info *wi)
{
gimple *stmt = gsi_stmt (*gsi_p);
*handled_ops_p = true;
switch (gimple_code (stmt))
{
case GIMPLE_TRY:
case GIMPLE_BIND:
case GIMPLE_CATCH:
case GIMPLE_EH_FILTER:
case GIMPLE_TRANSACTION:
/* Walk the sub-statements. */
*handled_ops_p = false;
break;
case GIMPLE_CALL:
if (gimple_call_internal_p (stmt, IFN_FALLTHROUGH))
{
gsi_remove (gsi_p, true);
if (gsi_end_p (*gsi_p))
{
*static_cast<location_t *>(wi->info) = gimple_location (stmt);
return integer_zero_node;
}
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
bool found = false;
location_t loc = gimple_location (stmt);
gimple_stmt_iterator gsi2 = *gsi_p;
stmt = gsi_stmt (gsi2);
if (gimple_code (stmt) == GIMPLE_GOTO && !gimple_has_location (stmt))
{
/* Go on until the artificial label. */
tree goto_dest = gimple_goto_dest (stmt);
for (; !gsi_end_p (gsi2); gsi_next (&gsi2))
{
if (gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL
&& gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2)))
== goto_dest)
break;
}
/* Not found? Stop. */
if (gsi_end_p (gsi2))
break;
/* Look one past it. */
gsi_next (&gsi2);
}
/* We're looking for a case label or default label here. */
while (!gsi_end_p (gsi2))
{
stmt = gsi_stmt (gsi2);
if (gimple_code (stmt) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (stmt));
if (gimple_has_location (stmt) && DECL_ARTIFICIAL (label))
{
found = true;
break;
}
}
else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
Martin Liska
committed
;
Alexandre Oliva
committed
else if (!is_gimple_debug (stmt))
/* Anything else is not expected. */
break;
gsi_next (&gsi2);
}
if (!found)
pedwarn (loc, 0, "attribute %<fallthrough%> not preceding "
"a case label or default label");
}
break;
default:
break;
}
return NULL_TREE;
}
/* Expand all FALLTHROUGH () calls in SEQ. */
static void
expand_FALLTHROUGH (gimple_seq *seq_p)
{
struct walk_stmt_info wi;
location_t loc;
wi.info = (void *) &loc;
walk_gimple_seq_mod (seq_p, expand_FALLTHROUGH_r, NULL, &wi);
if (wi.callback_result == integer_zero_node)
/* We've found [[fallthrough]]; at the end of a switch, which the C++
standard says is ill-formed; see [dcl.attr.fallthrough]. */
pedwarn (loc, 0, "attribute %<fallthrough%> not preceding "
"a case label or default label");
/* Gimplify a SWITCH_EXPR, and collect the vector of labels it can
branch to. */
static enum gimplify_status
gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
{
tree switch_expr = *expr_p;
gimple_seq switch_body_seq = NULL;
enum gimplify_status ret;
tree index_type = TREE_TYPE (switch_expr);
if (index_type == NULL_TREE)
index_type = TREE_TYPE (SWITCH_COND (switch_expr));
ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, is_gimple_val,
fb_rvalue);
if (ret == GS_ERROR || ret == GS_UNHANDLED)
return ret;
if (SWITCH_BODY (switch_expr))
{
Diego Novillo
committed
vec<tree> labels;
vec<tree> saved_labels;
hash_set<tree> *saved_live_switch_vars = NULL;
tree default_case = NULL_TREE;
gswitch *switch_stmt;
/* Save old labels, get new ones from body, then restore the old
labels. Save all the things from the switch body to append after. */
saved_labels = gimplify_ctxp->case_labels;
Diego Novillo
committed
gimplify_ctxp->case_labels.create (8);
/* Do not create live_switch_vars if SWITCH_BODY is not a BIND_EXPR. */
saved_live_switch_vars = gimplify_ctxp->live_switch_vars;
Martin Liska
committed
tree_code body_type = TREE_CODE (SWITCH_BODY (switch_expr));
if (body_type == BIND_EXPR || body_type == STATEMENT_LIST)
gimplify_ctxp->live_switch_vars = new hash_set<tree> (4);
else
gimplify_ctxp->live_switch_vars = NULL;
bool old_in_switch_expr = gimplify_ctxp->in_switch_expr;
gimplify_ctxp->in_switch_expr = true;
gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq);
Marek Polacek
committed
gimplify_ctxp->in_switch_expr = old_in_switch_expr;
maybe_warn_switch_unreachable_and_auto_init (switch_body_seq);
maybe_warn_implicit_fallthrough (switch_body_seq);
/* Only do this for the outermost GIMPLE_SWITCH. */
if (!gimplify_ctxp->in_switch_expr)
expand_FALLTHROUGH (&switch_body_seq);
Marek Polacek
committed
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
if (gimplify_ctxp->live_switch_vars)
{
gcc_assert (gimplify_ctxp->live_switch_vars->is_empty ());
delete gimplify_ctxp->live_switch_vars;
}
gimplify_ctxp->live_switch_vars = saved_live_switch_vars;
preprocess_case_label_vec_for_gimple (labels, index_type,
&default_case);
bool add_bind = false;
if (!default_case)
default_case
= build_case_label (NULL_TREE, NULL_TREE,
create_artificial_label (UNKNOWN_LOCATION));
if (old_in_switch_expr)
{
SWITCH_BREAK_LABEL_P (CASE_LABEL (default_case)) = 1;
add_bind = true;
}
new_default = gimple_build_label (CASE_LABEL (default_case));
gimplify_seq_add_stmt (&switch_body_seq, new_default);
}
else if (old_in_switch_expr)
{
gimple *last = gimple_seq_last_stmt (switch_body_seq);
if (last && gimple_code (last) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (last));
if (SWITCH_BREAK_LABEL_P (label))
add_bind = true;
}
}
switch_stmt = gimple_build_switch (SWITCH_COND (switch_expr),
default_case, labels);
/* For the benefit of -Wimplicit-fallthrough, if switch_body_seq
ends with a GIMPLE_LABEL holding SWITCH_BREAK_LABEL_P LABEL_DECL,
wrap the GIMPLE_SWITCH up to that GIMPLE_LABEL into a GIMPLE_BIND,
so that we can easily find the start and end of the switch
statement. */
if (add_bind)
{
gimple_seq bind_body = NULL;
gimplify_seq_add_stmt (&bind_body, switch_stmt);
gimple_seq_add_seq (&bind_body, switch_body_seq);
gbind *bind = gimple_build_bind (NULL_TREE, bind_body, NULL_TREE);
gimple_set_location (bind, EXPR_LOCATION (switch_expr));
gimplify_seq_add_stmt (pre_p, bind);
}
else
{
gimplify_seq_add_stmt (pre_p, switch_stmt);
gimplify_seq_add_seq (pre_p, switch_body_seq);
}
Diego Novillo
committed
labels.release ();
gcc_unreachable ();
return GS_ALL_DONE;
/* Gimplify the LABEL_EXPR pointed to by EXPR_P. */
static enum gimplify_status
gimplify_label_expr (tree *expr_p, gimple_seq *pre_p)
{
gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
== current_function_decl);
tree label = LABEL_EXPR_LABEL (*expr_p);
glabel *label_stmt = gimple_build_label (label);
gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p));
gimplify_seq_add_stmt (pre_p, label_stmt);
if (lookup_attribute ("cold", DECL_ATTRIBUTES (label)))
gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_COLD_LABEL,
NOT_TAKEN));
else if (lookup_attribute ("hot", DECL_ATTRIBUTES (label)))
gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_HOT_LABEL,
TAKEN));
/* Gimplify the CASE_LABEL_EXPR pointed to by EXPR_P. */
static enum gimplify_status
gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p)
/* Invalid programs can play Duff's Device type games with, for example,
#pragma omp parallel. At least in the C front end, we don't
detect such invalid branches until after gimplification, in the
diagnose_omp_blocks pass. */
for (ctxp = gimplify_ctxp; ; ctxp = ctxp->prev_context)
Diego Novillo
committed
if (ctxp->case_labels.exists ())
tree label = CASE_LABEL (*expr_p);
label_stmt = gimple_build_label (label);
gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p));
Diego Novillo
committed
ctxp->case_labels.safe_push (*expr_p);
gimplify_seq_add_stmt (pre_p, label_stmt);
if (lookup_attribute ("cold", DECL_ATTRIBUTES (label)))
gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_COLD_LABEL,
NOT_TAKEN));
else if (lookup_attribute ("hot", DECL_ATTRIBUTES (label)))
gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_HOT_LABEL,
TAKEN));
return GS_ALL_DONE;
}
/* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first
if necessary. */
tree
build_and_jump (tree *label_p)
{
if (label_p == NULL)
/* If there's nowhere to jump, just fall through. */
return NULL_TREE;
if (*label_p == NULL_TREE)
{
tree label = create_artificial_label (UNKNOWN_LOCATION);
*label_p = label;
}
return build1 (GOTO_EXPR, void_type_node, *label_p);
}
/* Gimplify an EXIT_EXPR by converting to a GOTO_EXPR inside a COND_EXPR.
This also involves building a label to jump to and communicating it to
gimplify_loop_expr through gimplify_ctxp->exit_label. */
static enum gimplify_status
gimplify_exit_expr (tree *expr_p)
{
tree cond = TREE_OPERAND (*expr_p, 0);
tree expr;
expr = build_and_jump (&gimplify_ctxp->exit_label);
expr = build3 (COND_EXPR, void_type_node, cond, expr, NULL_TREE);
*expr_p = expr;
return GS_OK;
}
Richard Henderson
committed
/* *EXPR_P is a COMPONENT_REF being used as an rvalue. If its type is
different from its canonical type, wrap the whole thing inside a
NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
type.
Richard Henderson
committed
The canonical type of a COMPONENT_REF is the type of the field being
referenced--unless the field is a bit-field which can be read directly
in a smaller mode, in which case the canonical type is the
sign-appropriate type corresponding to that mode. */
Richard Henderson
committed
static void
canonicalize_component_ref (tree *expr_p)
Richard Henderson
committed
tree expr = *expr_p;
tree type;
gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
Richard Henderson
committed
if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
else
type = TREE_TYPE (TREE_OPERAND (expr, 1));
Richard Guenther
committed
/* One could argue that all the stuff below is not necessary for
the non-bitfield case and declare it a FE error if type
adjustment would be needed. */
Richard Henderson
committed
if (TREE_TYPE (expr) != type)
Richard Guenther
committed
#ifdef ENABLE_TYPES_CHECKING
Richard Henderson
committed
tree old_type = TREE_TYPE (expr);
Richard Guenther
committed
#endif
int type_quals;
/* We need to preserve qualifiers and propagate them from
operand 0. */
type_quals = TYPE_QUALS (type)
| TYPE_QUALS (TREE_TYPE (TREE_OPERAND (expr, 0)));
if (TYPE_QUALS (type) != type_quals)
type = build_qualified_type (TYPE_MAIN_VARIANT (type), type_quals);
Richard Henderson
committed
/* Set the type of the COMPONENT_REF to the underlying type. */
TREE_TYPE (expr) = type;
Richard Guenther
committed
#ifdef ENABLE_TYPES_CHECKING
/* It is now a FE error, if the conversion from the canonical
type to the original expression type is not useless. */
gcc_assert (useless_type_conversion_p (old_type, type));
#endif
Richard Henderson
committed
}
}
Richard Henderson
committed
/* If a NOP conversion is changing a pointer to array of foo to a pointer
to foo, embed that change in the ADDR_EXPR by converting
Richard Henderson
committed
T array[U];
(T *)&array
==>
&array[L]
where L is the lower bound. For simplicity, only do this for constant
Richard Guenther
committed
lower bound.
The constraint is that the type of &array[L] is trivially convertible
to T *. */
Richard Henderson
committed
static void
canonicalize_addr_expr (tree *expr_p)
{
tree expr = *expr_p;
tree addr_expr = TREE_OPERAND (expr, 0);
Richard Guenther
committed
tree datype, ddatype, pddatype;
Richard Guenther
committed
/* We simplify only conversions from an ADDR_EXPR to a pointer type. */
if (!POINTER_TYPE_P (TREE_TYPE (expr))
|| TREE_CODE (addr_expr) != ADDR_EXPR)
Richard Henderson
committed
return;
Richard Henderson
committed
/* The addr_expr type should be a pointer to an array. */
Richard Guenther
committed
datype = TREE_TYPE (TREE_TYPE (addr_expr));
Richard Henderson
committed
if (TREE_CODE (datype) != ARRAY_TYPE)
return;
Richard Guenther
committed
/* The pointer to element type shall be trivially convertible to
the expression pointer type. */
Richard Henderson
committed
ddatype = TREE_TYPE (datype);
Richard Guenther
committed
pddatype = build_pointer_type (ddatype);
if (!useless_type_conversion_p (TYPE_MAIN_VARIANT (TREE_TYPE (expr)),
pddatype))
Richard Henderson
committed
return;
Richard Henderson
committed
/* The lower bound and element sizes must be constant. */
Richard Guenther
committed
if (!TYPE_SIZE_UNIT (ddatype)
|| TREE_CODE (TYPE_SIZE_UNIT (ddatype)) != INTEGER_CST
Richard Henderson
committed
|| !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
|| TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
return;
Richard Henderson
committed
/* All checks succeeded. Build a new node to merge the cast. */
Richard Guenther
committed
*expr_p = build4 (ARRAY_REF, ddatype, TREE_OPERAND (addr_expr, 0),
Richard Henderson
committed
TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
Richard Guenther
committed
NULL_TREE, NULL_TREE);
Richard Guenther
committed
*expr_p = build1 (ADDR_EXPR, pddatype, *expr_p);
/* We can have stripped a required restrict qualifier above. */
if (!useless_type_conversion_p (TREE_TYPE (expr), TREE_TYPE (*expr_p)))
*expr_p = fold_convert (TREE_TYPE (expr), *expr_p);
Richard Henderson
committed
}
Richard Henderson
committed
/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions
underneath as appropriate. */
Richard Henderson
committed
static enum gimplify_status
gimplify_conversion (tree *expr_p)
location_t loc = EXPR_LOCATION (*expr_p);
gcc_assert (CONVERT_EXPR_P (*expr_p));
/* Then strip away all but the outermost conversion. */
STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));