https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90574
--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> --- Related testcase: int main(int argc, char **argv) { switch (argc) { case 0: { foo:; } case 1:; } return 0; } breaking on the foo: line stops. Fixing this is a two-edged sword - we do try to build an optimized CFG (esp. for case label merging), creating more blocks defeats this. It might be possible to move cleanup_dead_labels after make_edges so that we can split blocks again when we make edges - but for switch stmts that would be quite expensive as well. But to fix these issues building more blocks is a requirement. The following does this: Index: gcc/tree-cfg.c =================================================================== --- gcc/tree-cfg.c (revision 271990) +++ gcc/tree-cfg.c (working copy) @@ -2722,10 +2722,10 @@ stmt_starts_bb_p (gimple *stmt, gimple * || FORCED_LABEL (gimple_label_label (label_stmt))) return true; - if (prev_stmt && gimple_code (prev_stmt) == GIMPLE_LABEL) + if (glabel *plabel = safe_dyn_cast <glabel *> (prev_stmt)) { - if (DECL_NONLOCAL (gimple_label_label ( - as_a <glabel *> (prev_stmt)))) + if (DECL_NONLOCAL (gimple_label_label (plabel)) + || !DECL_ARTIFICIAL (gimple_label_label (plabel))) return true; cfg_stats.num_merged_labels++; it will ensure new BBs for consecutive user labels and artificial labels following a user label assuming that is the target of a goto. It prevents case merging for the above testcase during CFG build when not optimizing CFG cleanup merges them though and in the correct fasion, deleting the user label, when optimizing. The debug experience is that gdb no longer stops at the line with the label but setting a breakpoint on its line will stop at some other line (that's a consumer issue I guess?).