diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 47e4e6c42e1..fd13b180a2b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,89 @@ +2009-06-15 Ian Lance Taylor + + * df-problems.c (df_simulate_one_insn_forwards): Fix braces in + switch. + * gcov.c (read_count_file): Add braces around variables declared + before label. + + * c.opt (Wjump-misses-init): New warning. + * c-opts.c (c_common_handle_option): Set warn_jump_misses_init for + -Wall and -Wc++-compat if not already set. + (c_common_post_options): Clear warn_jump_misses_init if it was not + set. + * c-decl.c (struct c_binding): Change type field to a union with + new label field. Make it the first field in the struct. Update + references to type to use u.type instead. + (struct c_spot_bindings): Define. + (struct c_goto_bindings): Define. + (c_goto_bindings_p): Define, along with VECs. + (struct c_label_vars): Define. + (struct c_scope): Add has_label_bindings field. + (bind_label, set_spot_bindings): New static functions. + (decl_jump_unsafe, update_spot_bindings): New static functions. + (update_label_decls): New static function. + (pop_scope): Call update_label_decls. Don't call c_end_vm_scope. + Update binding u.label field to shadowed field. + (c_binding_start_stmt_expr): New function. + (c_binding_end_stmt_expr): New function. + (pushdecl): Don't call c_begin_vm_scope. + (make_label): Add defining and p_label_vars parameters. Change + all callers. + (lookup_label): Correct test for whether a label has not yet been + defined. Call bind_label rather than bind. + (warn_about_goto): New static function. + (lookup_label_for_goto): New function. + (declare_label): Call bind_label rather than bind. + (check_earlier_gotos): New static function. + (define_label): Don't give errors about jumping into statement + expressions or scopes of variably modified types. Call + set_spot_bindings and check_earlier_gotos. Call bind_label + instead of bind. Don't set label_context_stack_se or + label_context_stack_vm. + (c_get_switch_bindings): New function. + (c_release_switch_bindings): New function. + (c_check_switch_jump_warnings): New function. + (start_function): Don't set label_context_stack_se or + label_context_stack_vm. + (finish_function): Likewise. + * c-typeck.c (label_context_stack_se): Don't define. + (label_context_stack_vm): Don't define. + (c_finish_goto_label): Call lookup_label_for_goto rather than + lookup_label. Don't give errors about jumping into a statement + expression or the scope of a variably modified type. Don't set + label_context_stack_se or label_context_stack_vm. + (struct c_switch): Remove blocked_stmt_expr and blocked_vm + fields. Add bindings field. + (c_start_case): Don't set deleted fields. Set bindings field. + (do_case): Rework order of tests. Don't check blocked_stmt_expr + or blocked_vm. Call c_check_switch_jump_warnings. + (c_finish_case): Don't test blocked_stmt_expr field. Call + c_release_switch_bindings. + (c_begin_stmt_expr): Don't increment blocked_stmt_expr in + c_switch_stack. Don't walk label_context_stack_se labels. Don't + set label_context_stack_se. Call c_bindings_start_stmt_expr. + (c_finish_stmt_expr): Don't decrement blocked_stmt_expr in + c_switch_stack. Don't walk label_context_stack_se labels. Don't + set label_context_stack_se. Call c_bindings_end_stmt_expr. + (c_begin_vm_scope, c_end_vm_scope): Don't define. + * c-tree.h (C_DECL_UNJUMPABLE_STMT_EXPR): Don't define. + (C_DECL_UNDEFINABLE_STMT_EXPR): Don't define. + (C_DECL_UNJUMPABLE_VM): Don't define. + (C_DECL_UNDEFINABLE_VM): Don't define. + (struct c_label_list): Don't define. + (struct c_label_context_se): Don't define. + (struct c_label_context_vm): Don't define. + (struct c_spot_bindings): Declare. + (c_bindings_start_stmt_expr): Declare. + (c_bindings_end_stmt_expr): Declare. + (lookup_label_for_goto): Declare. + (c_get_switch_bindings, c_release_switch_bindings): Declare. + (c_check_switch_jump_warnings): Declare. + (label_context_stack_se, label_context_stack_vm): Don't declare. + (c_finish_goto_label): Update declaration. + (c_begin_vm_scope, c_end_vm_scope): Don't declare. + * doc/invoke.texi (Option Summary): Mention -Wjump-misses-init. + (Warning Options): Document -Wjump-misses-init. + 2009-06-15 Jakub Jelinek * tree-object-size.c (addr_object_size): Fix a pasto in the last diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 03d6dbd892b..c2c2a890c9d 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -188,7 +188,7 @@ bool c_override_global_bindings_to_false; suppress further errors about that identifier in the current function. - The ->type field stores the type of the declaration in this scope; + The ->u.type field stores the type of the declaration in this scope; if NULL, the type is the type of the ->decl field. This is only of relevance for objects with external or internal linkage which may be redeclared in inner scopes, forming composite types that only @@ -198,6 +198,9 @@ bool c_override_global_bindings_to_false; scope) stores whether an incomplete array type at file scope was completed at an inner scope to an array size other than 1. + The ->u.label field is used for labels. It points to a structure + which stores additional information used for warnings. + The depth field is copied from the scope structure that holds this decl. It is used to preserve the proper ordering of the ->shadowed field (see bind()) and also for a handful of special-case checks. @@ -208,8 +211,11 @@ bool c_override_global_bindings_to_false; invisible bit true. */ struct GTY((chain_next ("%h.prev"))) c_binding { + union GTY(()) { /* first so GTY desc can use decl */ + tree GTY((tag ("0"))) type; /* the type in this scope */ + struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */ + } GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u; tree decl; /* the decl bound */ - tree type; /* the type in this scope */ tree id; /* the identifier it's bound to */ struct c_binding *prev; /* the previous decl in this scope */ struct c_binding *shadowed; /* the innermost decl shadowed by this one */ @@ -266,6 +272,67 @@ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), struct lang_identifier GTY ((tag ("1"))) identifier; }; +/* Track bindings and other things that matter for goto warnings. For + efficiency, we do not gather all the decls at the point of + definition. Instead, we point into the bindings structure. As + scopes are popped, we update these structures and gather the decls + that matter at that time. */ + +struct GTY(()) c_spot_bindings { + /* The currently open scope which holds bindings defined when the + label was defined or the goto statement was found. */ + struct c_scope *scope; + /* The bindings in the scope field which were defined at the point + of the label or goto. This lets us look at older or newer + bindings in the scope, as appropriate. */ + struct c_binding *bindings_in_scope; + /* The number of statement expressions that have started since this + label or goto statement was defined. This is zero if we are at + the same statement expression level. It is positive if we are in + a statement expression started since this spot. It is negative + if this spot was in a statement expression and we have left + it. */ + int stmt_exprs; + /* Whether we started in a statement expression but are no longer in + it. This is set to true if stmt_exprs ever goes negative. */ + bool left_stmt_expr; +}; + +/* This structure is used to keep track of bindings seen when a goto + statement is defined. This is only used if we see the goto + statement before we see the label. */ + +struct GTY(()) c_goto_bindings { + /* The location of the goto statement. */ + location_t loc; + /* The bindings of the goto statement. */ + struct c_spot_bindings goto_bindings; +}; + +typedef struct c_goto_bindings *c_goto_bindings_p; +DEF_VEC_P(c_goto_bindings_p); +DEF_VEC_ALLOC_P(c_goto_bindings_p,gc); + +/* The additional information we keep track of for a label binding. + These fields are updated as scopes are popped. */ + +struct GTY(()) c_label_vars { + /* The shadowed c_label_vars, when one label shadows another (which + can only happen using a __label__ declaration). */ + struct c_label_vars *shadowed; + /* The bindings when the label was defined. */ + struct c_spot_bindings label_bindings; + /* A list of decls that we care about: decls about which we should + warn if a goto branches to this label from later in the function. + Decls are added to this list as scopes are popped. We only add + the decls that matter. */ + VEC(tree,gc) *decls_in_scope; + /* A list of goto statements to this label. This is only used for + goto statements seen before the label was defined, so that we can + issue appropriate warnings for them. */ + VEC(c_goto_bindings_p,gc) *gotos; +}; + /* Each c_scope structure describes the complete contents of one scope. Four scopes are distinguished specially: the innermost or current scope, the innermost function scope, the file scope (always @@ -354,6 +421,11 @@ struct GTY((chain_next ("%h.outer"))) c_scope { /* True means that an unsuffixed float constant is _Decimal64. */ BOOL_BITFIELD float_const_decimal64 : 1; + + /* True if this scope has any label bindings. This is used to speed + up searching for labels when popping scopes, particularly since + labels are normally only found at function scope. */ + BOOL_BITFIELD has_label_bindings : 1; }; /* The scope currently in effect. */ @@ -518,7 +590,7 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible, b->inner_comp = 0; b->locus = locus; - b->type = 0; + b->u.type = NULL; b->prev = scope->bindings; scope->bindings = b; @@ -569,6 +641,24 @@ free_binding_and_advance (struct c_binding *b) return prev; } +/* Bind a label. Like bind, but skip fields which aren't used for + labels, and add the LABEL_VARS value. */ +static void +bind_label (tree name, tree label, struct c_scope *scope, + struct c_label_vars *label_vars) +{ + struct c_binding *b; + + bind (name, label, scope, /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + + scope->has_label_bindings = true; + + b = scope->bindings; + gcc_assert (b->decl == label); + label_vars->shadowed = b->u.label; + b->u.label = label_vars; +} /* Hook called at end of compilation to assume 1 elt for a file-scope tentative array defn that wasn't complete before. */ @@ -641,6 +731,73 @@ check_inline_statics (void) c_inline_statics = NULL; } +/* Fill in a c_spot_bindings structure. If DEFINING is true, set it + for the current state, otherwise set it to uninitialized. */ + +static void +set_spot_bindings (struct c_spot_bindings *p, bool defining) +{ + if (defining) + { + p->scope = current_scope; + p->bindings_in_scope = current_scope->bindings; + } + else + { + p->scope = NULL; + p->bindings_in_scope = NULL; + } + p->stmt_exprs = 0; + p->left_stmt_expr = false; +} + +/* Return true if we will want to say something if a goto statement + crosses DECL. */ + +static bool +decl_jump_unsafe (tree decl) +{ + if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node) + return false; + + /* Always warn about crossing variably modified types. */ + if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL) + && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + return true; + + /* Otherwise, only warn if -Wgoto-misses-init and this is an + initialized automatic decl. */ + if (warn_jump_misses_init + && TREE_CODE (decl) == VAR_DECL + && !TREE_STATIC (decl) + && DECL_INITIAL (decl) != NULL_TREE) + return true; + + return false; +} + +/* Update spot bindings P as we pop out of SCOPE. Return true if we + should push decls for a label. */ + +static bool +update_spot_bindings (struct c_scope *scope, struct c_spot_bindings *p) +{ + if (p->scope != scope) + { + /* This label or goto is defined in some other scope, or it is a + label which is not yet defined. There is nothing to + update. */ + return false; + } + + /* Adjust the spot bindings to refer to the bindings already defined + in the enclosing scope. */ + p->scope = scope->outer; + p->bindings_in_scope = p->scope->bindings; + + return true; +} + /* The Objective-C front-end often needs to determine the current scope. */ void * @@ -784,6 +941,67 @@ push_scope (void) } } +/* This is called when we are leaving SCOPE. For each label defined + in SCOPE, add any appropriate decls to its decls_in_scope fields. + These are the decls whose initialization will be skipped by a goto + later in the function. */ + +static void +update_label_decls (struct c_scope *scope) +{ + struct c_scope *s; + + s = scope; + while (s != NULL) + { + if (s->has_label_bindings) + { + struct c_binding *b; + + for (b = s->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + struct c_binding *b1; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + + b1 = label_vars->label_bindings.bindings_in_scope; + if (update_spot_bindings (scope, &label_vars->label_bindings)) + { + /* This label is defined in this scope. */ + for (; b1 != NULL; b1 = b1->prev) + { + /* A goto from later in the function to this + label will never see the initialization of + B1, if any. Save it to issue a warning if + needed. */ + if (decl_jump_unsafe (b1->decl)) + VEC_safe_push (tree, gc, label_vars->decls_in_scope, + b1->decl); + } + } + + /* Update the bindings of any goto statements associated + with this label. */ + for (ix = 0; + VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); + ++ix) + update_spot_bindings (scope, &g->goto_bindings); + } + } + + /* Don't search beyond the current function. */ + if (s == current_function_scope) + break; + + s = s->outer; + } +} + /* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */ static void @@ -809,7 +1027,7 @@ pop_scope (void) bool functionbody = scope->function_body; bool keep = functionbody || scope->keep || scope->bindings; - c_end_vm_scope (scope->depth); + update_label_decls (scope); /* If appropriate, create a BLOCK to record the decls for the life of this function. */ @@ -874,6 +1092,10 @@ pop_scope (void) BLOCK_VARS (block) = p; gcc_assert (I_LABEL_BINDING (b->id) == b); I_LABEL_BINDING (b->id) = b->shadowed; + + /* Also pop back to the shadowed label_vars. */ + release_tree_vector (b->u.label->decls_in_scope); + b->u.label = b->u.label->shadowed; break; case ENUMERAL_TYPE: @@ -999,8 +1221,8 @@ pop_scope (void) { gcc_assert (I_SYMBOL_BINDING (b->id) == b); I_SYMBOL_BINDING (b->id) = b->shadowed; - if (b->shadowed && b->shadowed->type) - TREE_TYPE (b->shadowed->decl) = b->shadowed->type; + if (b->shadowed && b->shadowed->u.type) + TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; } break; @@ -1087,7 +1309,91 @@ pop_file_scope (void) maybe_apply_pending_pragma_weaks (); cgraph_finalize_compilation_unit (); } + +/* Adjust the bindings for the start of a statement expression. */ +void +c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings) +{ + struct c_scope *scope; + + for (scope = current_scope; scope != NULL; scope = scope->outer) + { + struct c_binding *b; + + if (!scope->has_label_bindings) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + ++label_vars->label_bindings.stmt_exprs; + for (ix = 0; + VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); + ++ix) + ++g->goto_bindings.stmt_exprs; + } + } + + if (switch_bindings != NULL) + ++switch_bindings->stmt_exprs; +} + +/* Adjust the bindings for the end of a statement expression. */ + +void +c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings) +{ + struct c_scope *scope; + + for (scope = current_scope; scope != NULL; scope = scope->outer) + { + struct c_binding *b; + + if (!scope->has_label_bindings) + continue; + + for (b = scope->bindings; b != NULL; b = b->prev) + { + struct c_label_vars *label_vars; + unsigned int ix; + struct c_goto_bindings *g; + + if (TREE_CODE (b->decl) != LABEL_DECL) + continue; + label_vars = b->u.label; + --label_vars->label_bindings.stmt_exprs; + if (label_vars->label_bindings.stmt_exprs < 0) + { + label_vars->label_bindings.left_stmt_expr = true; + label_vars->label_bindings.stmt_exprs = 0; + } + for (ix = 0; + VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); + ++ix) + { + --g->goto_bindings.stmt_exprs; + if (g->goto_bindings.stmt_exprs < 0) + { + g->goto_bindings.left_stmt_expr = true; + g->goto_bindings.stmt_exprs = 0; + } + } + } + } + + if (switch_bindings != NULL) + { + --switch_bindings->stmt_exprs; + gcc_assert (switch_bindings->stmt_exprs >= 0); + } +} /* Push a definition or a declaration of struct, union or enum tag "name". "type" should be the type node. @@ -2182,12 +2488,6 @@ pushdecl (tree x) || DECL_INITIAL (x) || !DECL_EXTERNAL (x))) DECL_CONTEXT (x) = current_function_decl; - /* If this is of variably modified type, prevent jumping into its - scope. */ - if ((TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == TYPE_DECL) - && variably_modified_type_p (TREE_TYPE (x), NULL_TREE)) - c_begin_vm_scope (scope->depth); - /* Anonymous decls are just inserted in the scope. */ if (!name) { @@ -2226,8 +2526,8 @@ pushdecl (tree x) if (b_ext) { b_use = b_ext; - if (b_use->type) - TREE_TYPE (b_use->decl) = b_use->type; + if (b_use->u.type) + TREE_TYPE (b_use->decl) = b_use->u.type; } } if (duplicate_decls (x, b_use->decl)) @@ -2241,13 +2541,13 @@ pushdecl (tree x) thistype = composite_type (vistype, type); else thistype = TREE_TYPE (b_use->decl); - b_use->type = TREE_TYPE (b_use->decl); + b_use->u.type = TREE_TYPE (b_use->decl); if (TREE_CODE (b_use->decl) == FUNCTION_DECL && DECL_BUILT_IN (b_use->decl)) thistype = build_type_attribute_variant (thistype, TYPE_ATTRIBUTES - (b_use->type)); + (b_use->u.type)); TREE_TYPE (b_use->decl) = thistype; } return b_use->decl; @@ -2298,7 +2598,7 @@ pushdecl (tree x) their scopes will not have been re-entered. */ if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved) { - b->type = TREE_TYPE (b->decl); + b->u.type = TREE_TYPE (b->decl); type_saved = true; } if (B_IN_FILE_SCOPE (b) @@ -2324,8 +2624,8 @@ pushdecl (tree x) After the consistency checks, it will be reset to the composite of the visible types only. */ if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) - && b->type) - TREE_TYPE (b->decl) = b->type; + && b->u.type) + TREE_TYPE (b->decl) = b->u.type; /* The point of the same_translation_unit_p check here is, we want to detect a duplicate decl for a construct like @@ -2346,11 +2646,11 @@ pushdecl (tree x) } else thistype = type; - b->type = TREE_TYPE (b->decl); + b->u.type = TREE_TYPE (b->decl); if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl)) thistype = build_type_attribute_variant (thistype, - TYPE_ATTRIBUTES (b->type)); + TYPE_ATTRIBUTES (b->u.type)); TREE_TYPE (b->decl) = thistype; bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true, locus); @@ -2500,8 +2800,8 @@ implicitly_declare (location_t loc, tree functionid) else { tree newtype = default_function_type; - if (b->type) - TREE_TYPE (decl) = b->type; + if (b->u.type) + TREE_TYPE (decl) = b->u.type; /* Implicit declaration of a function already declared (somehow) in a different scope, or as a built-in. If this is the first time this has happened, warn; @@ -2531,7 +2831,7 @@ implicitly_declare (location_t loc, tree functionid) locate_old_decl (decl); } } - b->type = TREE_TYPE (decl); + b->u.type = TREE_TYPE (decl); TREE_TYPE (decl) = newtype; bind (functionid, decl, current_scope, /*invisible=*/false, /*nested=*/true, @@ -2603,16 +2903,26 @@ undeclared_variable (location_t loc, tree id) } /* Subroutine of lookup_label, declare_label, define_label: construct a - LABEL_DECL with all the proper frills. */ + LABEL_DECL with all the proper frills. Also create a struct + c_label_vars initialized for the current scope. */ static tree -make_label (location_t location, tree name) +make_label (location_t location, tree name, bool defining, + struct c_label_vars **p_label_vars) { tree label = build_decl (location, LABEL_DECL, name, void_type_node); + struct c_label_vars *label_vars; DECL_CONTEXT (label) = current_function_decl; DECL_MODE (label) = VOIDmode; + label_vars = GGC_NEW (struct c_label_vars); + label_vars->shadowed = NULL; + set_spot_bindings (&label_vars->label_bindings, defining); + label_vars->decls_in_scope = make_tree_vector (); + label_vars->gotos = VEC_alloc (c_goto_bindings_p, gc, 0); + *p_label_vars = label_vars; + return label; } @@ -2625,6 +2935,7 @@ tree lookup_label (tree name) { tree label; + struct c_label_vars *label_vars; if (current_function_decl == 0) { @@ -2642,17 +2953,91 @@ lookup_label (tree name) /* If the label has only been declared, update its apparent location to point here, for better diagnostics if it turns out not to have been defined. */ - if (!TREE_USED (label)) + if (DECL_INITIAL (label) == NULL_TREE) DECL_SOURCE_LOCATION (label) = input_location; return label; } /* No label binding for that identifier; make one. */ - label = make_label (input_location, name); + label = make_label (input_location, name, false, &label_vars); /* Ordinary labels go in the current function scope. */ - bind (name, label, current_function_scope, - /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); + bind_label (name, label, current_function_scope, label_vars); + + return label; +} + +/* Issue a warning about DECL for a goto statement at GOTO_LOC going + to LABEL. */ + +static void +warn_about_goto (location_t goto_loc, tree label, tree decl) +{ + if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + error_at (goto_loc, + "jump into scope of identifier with variably modified type"); + else + warning_at (goto_loc, OPT_Wjump_misses_init, + "jump skips variable initialization"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); + inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); +} + +/* Look up a label because of a goto statement. This is like + lookup_label, but also issues any appropriate warnings. */ + +tree +lookup_label_for_goto (location_t loc, tree name) +{ + tree label; + struct c_label_vars *label_vars; + unsigned int ix; + tree decl; + + label = lookup_label (name); + if (label == NULL_TREE) + return NULL_TREE; + + /* If we are jumping to a different function, we can't issue any + useful warnings. */ + if (DECL_CONTEXT (label) != current_function_decl) + { + gcc_assert (C_DECLARED_LABEL_FLAG (label)); + return label; + } + + label_vars = I_LABEL_BINDING (name)->u.label; + + /* If the label has not yet been defined, then push this goto on a + list for possible later warnings. */ + if (label_vars->label_bindings.scope == NULL) + { + struct c_goto_bindings *g; + + g = GGC_NEW (struct c_goto_bindings); + g->loc = loc; + set_spot_bindings (&g->goto_bindings, true); + VEC_safe_push (c_goto_bindings_p, gc, label_vars->gotos, g); + return label; + } + + /* If there are any decls in label_vars->decls_in_scope, then this + goto has missed the declaration of the decl. This happens for a + case like + int i = 1; + lab: + ... + goto lab; + Issue a warning or error. */ + for (ix = 0; VEC_iterate (tree, label_vars->decls_in_scope, ix, decl); ++ix) + warn_about_goto (loc, label, decl); + + if (label_vars->label_bindings.left_stmt_expr) + { + error_at (loc, "jump into statement expression"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); + } + return label; } @@ -2665,6 +3050,7 @@ declare_label (tree name) { struct c_binding *b = I_LABEL_BINDING (name); tree label; + struct c_label_vars *label_vars; /* Check to make sure that the label hasn't already been declared at this scope */ @@ -2677,15 +3063,74 @@ declare_label (tree name) return b->decl; } - label = make_label (input_location, name); + label = make_label (input_location, name, false, &label_vars); C_DECLARED_LABEL_FLAG (label) = 1; /* Declared labels go in the current scope. */ - bind (name, label, current_scope, - /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); + bind_label (name, label, current_scope, label_vars); + return label; } +/* When we define a label, issue any appropriate warnings if there are + any gotos earlier in the function which jump to this label. */ + +static void +check_earlier_gotos (tree label, struct c_label_vars* label_vars) +{ + unsigned int ix; + struct c_goto_bindings *g; + + for (ix = 0; + VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); + ++ix) + { + struct c_binding *b; + struct c_scope *scope; + + /* We have a goto to this label. The goto is going forward. In + g->scope, the goto is going to skip any binding which was + defined after g->bindings_in_scope. */ + for (b = g->goto_bindings.scope->bindings; + b != g->goto_bindings.bindings_in_scope; + b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + warn_about_goto (g->loc, label, b->decl); + } + + /* We also need to warn about decls defined in any scopes + between the scope of the label and the scope of the goto. */ + for (scope = label_vars->label_bindings.scope; + scope != g->goto_bindings.scope; + scope = scope->outer) + { + gcc_assert (scope != NULL); + if (scope == label_vars->label_bindings.scope) + b = label_vars->label_bindings.bindings_in_scope; + else + b = scope->bindings; + for (; b != NULL; b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + warn_about_goto (g->loc, label, b->decl); + } + } + + if (g->goto_bindings.stmt_exprs > 0) + { + error_at (g->loc, "jump into statement expression"); + inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", + label); + } + } + + /* Now that the label is defined, we will issue warnings about + subsequent gotos to this label when we see them. */ + VEC_truncate (c_goto_bindings_p, label_vars->gotos, 0); + label_vars->gotos = NULL; +} + /* Define a label, specifying the location in the source file. Return the LABEL_DECL node for the label, if the definition is valid. Otherwise return 0. */ @@ -2698,7 +3143,6 @@ define_label (location_t location, tree name) if there is a containing function with a declared label with the same name. */ tree label = I_LABEL_DECL (name); - struct c_label_list *nlist_se, *nlist_vm; if (label && ((DECL_CONTEXT (label) == current_function_decl @@ -2712,24 +3156,27 @@ define_label (location_t location, tree name) } else if (label && DECL_CONTEXT (label) == current_function_decl) { + struct c_label_vars *label_vars = I_LABEL_BINDING (name)->u.label; + /* The label has been used or declared already in this function, but not defined. Update its location to point to this definition. */ - if (C_DECL_UNDEFINABLE_STMT_EXPR (label)) - error_at (location, "jump into statement expression"); - if (C_DECL_UNDEFINABLE_VM (label)) - error_at (location, - "jump into scope of identifier with variably modified type"); DECL_SOURCE_LOCATION (label) = location; + set_spot_bindings (&label_vars->label_bindings, true); + + /* Issue warnings as required about any goto statements from + earlier in the function. */ + check_earlier_gotos (label, label_vars); } else { + struct c_label_vars *label_vars; + /* No label binding for that identifier; make one. */ - label = make_label (location, name); + label = make_label (location, name, true, &label_vars); /* Ordinary labels go in the current function scope. */ - bind (name, label, current_function_scope, - /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); + bind_label (name, label, current_function_scope, label_vars); } if (!in_system_header && lookup_name (name)) @@ -2737,21 +3184,82 @@ define_label (location_t location, tree name) "traditional C lacks a separate namespace " "for labels, identifier %qE conflicts", name); - nlist_se = XOBNEW (&parser_obstack, struct c_label_list); - nlist_se->next = label_context_stack_se->labels_def; - nlist_se->label = label; - label_context_stack_se->labels_def = nlist_se; - - nlist_vm = XOBNEW (&parser_obstack, struct c_label_list); - nlist_vm->next = label_context_stack_vm->labels_def; - nlist_vm->label = label; - label_context_stack_vm->labels_def = nlist_vm; - /* Mark label as having been defined. */ DECL_INITIAL (label) = error_mark_node; return label; } +/* Get the bindings for a new switch statement. This is used to issue + warnings as appropriate for jumps from the switch to case or + default labels. */ + +struct c_spot_bindings * +c_get_switch_bindings (void) +{ + struct c_spot_bindings *switch_bindings; + + switch_bindings = XNEW (struct c_spot_bindings); + set_spot_bindings (switch_bindings, true); + return switch_bindings; +} + +void +c_release_switch_bindings (struct c_spot_bindings *bindings) +{ + gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr); + XDELETE (bindings); +} + +/* This is called at the point of a case or default label to issue + warnings about decls as needed. It returns true if it found an + error, not just a warning. */ + +bool +c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings, + location_t switch_loc, location_t case_loc) +{ + bool saw_error; + struct c_scope *scope; + + saw_error = false; + for (scope = current_scope; + scope != switch_bindings->scope; + scope = scope->outer) + { + struct c_binding *b; + + gcc_assert (scope != NULL); + for (b = scope->bindings; b != NULL; b = b->prev) + { + if (decl_jump_unsafe (b->decl)) + { + if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE)) + { + saw_error = true; + error_at (case_loc, + ("switch jumps into scope of identifier with " + "variably modified type")); + } + else + warning_at (case_loc, OPT_Wjump_misses_init, + "switch jumps over variable initialization"); + inform (switch_loc, "switch starts here"); + inform (DECL_SOURCE_LOCATION (b->decl), "%qD declared here", + b->decl); + } + } + } + + if (switch_bindings->stmt_exprs > 0) + { + saw_error = true; + error_at (case_loc, "switch jumps into statement expression"); + inform (switch_loc, "switch starts here"); + } + + return saw_error; +} + /* Given NAME, an IDENTIFIER_NODE, return the structure (or union or enum) definition for that name. If THISLEVEL_ONLY is nonzero, searches only the current_scope. @@ -3610,10 +4118,10 @@ finish_decl (tree decl, location_t init_loc, tree init, b_ext = b_ext->shadowed; if (b_ext) { - if (b_ext->type) - b_ext->type = composite_type (b_ext->type, type); + if (b_ext->u.type) + b_ext->u.type = composite_type (b_ext->u.type, type); else - b_ext->type = type; + b_ext->u.type = type; } } break; @@ -6610,8 +7118,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, { tree decl1, old_decl; tree restype, resdecl; - struct c_label_context_se *nstack_se; - struct c_label_context_vm *nstack_vm; location_t loc; current_function_returns_value = 0; /* Assume, until we see it does. */ @@ -6620,19 +7126,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, warn_about_return_type = 0; c_switch_stack = NULL; - nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); - nstack_se->labels_def = NULL; - nstack_se->labels_used = NULL; - nstack_se->next = label_context_stack_se; - label_context_stack_se = nstack_se; - - nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm); - nstack_vm->labels_def = NULL; - nstack_vm->labels_used = NULL; - nstack_vm->scope = 0; - nstack_vm->next = label_context_stack_vm; - label_context_stack_vm = nstack_vm; - /* Indicate no valid break/continue context by setting these variables to some non-null, non-label value. We'll notice and emit the proper error message in c_finish_bc_stmt. */ @@ -6644,11 +7137,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, /* If the declarator is not suitable for a function definition, cause a syntax error. */ if (decl1 == 0) - { - label_context_stack_se = label_context_stack_se->next; - label_context_stack_vm = label_context_stack_vm->next; - return 0; - } + return 0; loc = DECL_SOURCE_LOCATION (decl1); @@ -6730,7 +7219,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, { tree ext_decl, ext_type; ext_decl = b->decl; - ext_type = b->type ? b->type : TREE_TYPE (ext_decl); + ext_type = b->u.type ? b->u.type : TREE_TYPE (ext_decl); if (TREE_CODE (ext_type) == FUNCTION_TYPE && comptypes (TREE_TYPE (TREE_TYPE (decl1)), TREE_TYPE (ext_type))) @@ -7282,9 +7771,6 @@ finish_function (void) { tree fndecl = current_function_decl; - label_context_stack_se = label_context_stack_se->next; - label_context_stack_vm = label_context_stack_vm->next; - if (TREE_CODE (fndecl) == FUNCTION_DECL && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) { diff --git a/gcc/c-opts.c b/gcc/c-opts.c index 0050ab55839..4574bb2e920 100644 --- a/gcc/c-opts.c +++ b/gcc/c-opts.c @@ -395,6 +395,8 @@ c_common_handle_option (size_t scode, const char *arg, int value) warn_strict_overflow = value; warn_array_bounds = value; warn_volatile_register_var = value; + if (warn_jump_misses_init == -1) + warn_jump_misses_init = value; /* Only warn about unknown pragmas that are not in system headers. */ @@ -445,6 +447,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) implies -Wenum-compare. */ if (warn_enum_compare == -1 && value) warn_enum_compare = value; + /* Because C++ always warns about a goto which misses an + initialization, -Wc++-compat turns on -Wgoto-misses-init. */ + if (warn_jump_misses_init == -1 && value) + warn_jump_misses_init = value; cpp_opts->warn_cxx_operator_names = value; break; @@ -1084,6 +1090,8 @@ c_common_post_options (const char **pfilename) warn_strict_aliasing = 0; if (warn_strict_overflow == -1) warn_strict_overflow = 0; + if (warn_jump_misses_init == -1) + warn_jump_misses_init = 0; /* -Woverlength-strings is off by default, but is enabled by -pedantic. It is never enabled in C++, as the minimum limit is not normative diff --git a/gcc/c-tree.h b/gcc/c-tree.h index d6062177375..f565df58f31 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -108,29 +108,6 @@ struct GTY(()) lang_type { sizeof and typeof it is set for other function decls as well. */ #define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP)) -/* Record whether a label was defined in a statement expression which - has finished and so can no longer be jumped to. */ -#define C_DECL_UNJUMPABLE_STMT_EXPR(EXP) \ - DECL_LANG_FLAG_6 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a label was the subject of a goto from outside the - current level of statement expression nesting and so cannot be - defined right now. */ -#define C_DECL_UNDEFINABLE_STMT_EXPR(EXP) \ - DECL_LANG_FLAG_7 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a label was defined in the scope of an identifier - with variably modified type which has finished and so can no longer - be jumped to. */ -#define C_DECL_UNJUMPABLE_VM(EXP) \ - DECL_LANG_FLAG_3 (LABEL_DECL_CHECK (EXP)) - -/* Record whether a label was the subject of a goto from outside the - current level of scopes of identifiers with variably modified type - and so cannot be defined right now. */ -#define C_DECL_UNDEFINABLE_VM(EXP) \ - DECL_LANG_FLAG_5 (LABEL_DECL_CHECK (EXP)) - /* Record whether a variable has been declared threadprivate by #pragma omp threadprivate. */ #define C_DECL_THREADPRIVATE_P(DECL) DECL_LANG_FLAG_3 (VAR_DECL_CHECK (DECL)) @@ -421,45 +398,6 @@ struct GTY(()) language_function { int warn_about_return_type; }; -/* Save lists of labels used or defined in particular contexts. - Allocated on the parser obstack. */ - -struct c_label_list -{ - /* The label at the head of the list. */ - tree label; - /* The rest of the list. */ - struct c_label_list *next; -}; - -/* Statement expression context. */ - -struct c_label_context_se -{ - /* The labels defined at this level of nesting. */ - struct c_label_list *labels_def; - /* The labels used at this level of nesting. */ - struct c_label_list *labels_used; - /* The next outermost context. */ - struct c_label_context_se *next; -}; - -/* Context of variably modified declarations. */ - -struct c_label_context_vm -{ - /* The labels defined at this level of nesting. */ - struct c_label_list *labels_def; - /* The labels used at this level of nesting. */ - struct c_label_list *labels_used; - /* The scope of this context. Multiple contexts may be at the same - numbered scope, since each variably modified declaration starts a - new context. */ - unsigned scope; - /* The next outermost context. */ - struct c_label_context_vm *next; -}; - /* Used when parsing an enum. Initialized by start_enum. */ struct c_enum_contents { @@ -491,6 +429,7 @@ extern void c_parse_init (void); extern void gen_aux_info_record (tree, int, int, int); /* in c-decl.c */ +struct c_spot_bindings; extern struct obstack parser_obstack; extern tree c_break_label; extern tree c_cont_label; @@ -498,6 +437,8 @@ extern tree c_cont_label; extern int global_bindings_p (void); extern void push_scope (void); extern tree pop_scope (void); +extern void c_bindings_start_stmt_expr (struct c_spot_bindings *); +extern void c_bindings_end_stmt_expr (struct c_spot_bindings *); extern void record_inline_static (location_t, tree, tree, enum c_inline_static_type); @@ -513,8 +454,13 @@ extern tree check_for_loop_decls (location_t); extern void mark_forward_parm_decls (void); extern void declare_parm_level (void); extern void undeclared_variable (location_t, tree); +extern tree lookup_label_for_goto (location_t, tree); extern tree declare_label (tree); extern tree define_label (location_t, tree); +extern struct c_spot_bindings *c_get_switch_bindings (void); +extern void c_release_switch_bindings (struct c_spot_bindings *); +extern bool c_check_switch_jump_warnings (struct c_spot_bindings *, + location_t, location_t); extern void c_maybe_initialize_eh (void); extern void finish_decl (tree, location_t, tree, tree, tree); extern tree finish_enum (tree, tree, tree); @@ -583,8 +529,6 @@ extern int in_sizeof; extern int in_typeof; extern struct c_switch *c_switch_stack; -extern struct c_label_context_se *label_context_stack_se; -extern struct c_label_context_vm *label_context_stack_vm; extern tree c_objc_common_truthvalue_conversion (location_t, tree); extern tree require_complete_type (tree); @@ -643,8 +587,6 @@ extern tree c_finish_return (location_t, tree, tree); extern tree c_finish_bc_stmt (location_t, tree *, bool); extern tree c_finish_goto_label (location_t, tree); extern tree c_finish_goto_ptr (location_t, tree); -extern void c_begin_vm_scope (unsigned int); -extern void c_end_vm_scope (unsigned int); extern tree c_expr_to_decl (tree, bool *, bool *); extern tree c_begin_omp_parallel (void); extern tree c_finish_omp_parallel (location_t, tree, tree); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 978e95c4b45..0dd97d31983 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -70,9 +70,6 @@ int in_sizeof; /* The level of nesting inside "typeof". */ int in_typeof; -struct c_label_context_se *label_context_stack_se; -struct c_label_context_vm *label_context_stack_vm; - /* Nonzero if we've already printed a "missing braces around initializer" message within this initializer. */ static int missing_braces_mentioned; @@ -7979,46 +7976,9 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, tree c_finish_goto_label (location_t loc, tree label) { - tree decl = lookup_label (label); + tree decl = lookup_label_for_goto (loc, label); if (!decl) return NULL_TREE; - - if (C_DECL_UNJUMPABLE_STMT_EXPR (decl)) - { - error_at (loc, "jump into statement expression"); - return NULL_TREE; - } - - if (C_DECL_UNJUMPABLE_VM (decl)) - { - error_at (loc, - "jump into scope of identifier with variably modified type"); - return NULL_TREE; - } - - if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl)) - { - /* No jump from outside this statement expression context, so - record that there is a jump from within this context. */ - struct c_label_list *nlist; - nlist = XOBNEW (&parser_obstack, struct c_label_list); - nlist->next = label_context_stack_se->labels_used; - nlist->label = decl; - label_context_stack_se->labels_used = nlist; - } - - if (!C_DECL_UNDEFINABLE_VM (decl)) - { - /* No jump from outside this context context of identifiers with - variably modified type, so record that there is a jump from - within this context. */ - struct c_label_list *nlist; - nlist = XOBNEW (&parser_obstack, struct c_label_list); - nlist->next = label_context_stack_vm->labels_used; - nlist->label = decl; - label_context_stack_vm->labels_used = nlist; - } - TREE_USED (decl) = 1; { tree t = build1 (GOTO_EXPR, void_type_node, decl); @@ -8189,15 +8149,9 @@ struct c_switch { of the GNU case range extension. */ splay_tree cases; - /* Number of nested statement expressions within this switch - statement; if nonzero, case and default labels may not - appear. */ - unsigned int blocked_stmt_expr; - - /* Scope of outermost declarations of identifiers with variably - modified type within this switch statement; if nonzero, case and - default labels may not appear. */ - unsigned int blocked_vm; + /* The bindings at the point of the switch. This is used for + warnings crossing decls when branching to a case label. */ + struct c_spot_bindings *bindings; /* The next node on the stack. */ struct c_switch *next; @@ -8261,8 +8215,7 @@ c_start_case (location_t switch_loc, SET_EXPR_LOCATION (cs->switch_expr, switch_loc); cs->orig_type = orig_type; cs->cases = splay_tree_new (case_compare, NULL, NULL); - cs->blocked_stmt_expr = 0; - cs->blocked_vm = 0; + cs->bindings = c_get_switch_bindings (); cs->next = c_switch_stack; c_switch_stack = cs; @@ -8292,40 +8245,26 @@ do_case (location_t loc, tree low_value, tree high_value) "case label is not an integer constant expression"); } - if (c_switch_stack && !c_switch_stack->blocked_stmt_expr - && !c_switch_stack->blocked_vm) - { - label = c_add_case_label (loc, c_switch_stack->cases, - SWITCH_COND (c_switch_stack->switch_expr), - c_switch_stack->orig_type, - low_value, high_value); - if (label == error_mark_node) - label = NULL_TREE; - } - else if (c_switch_stack && c_switch_stack->blocked_stmt_expr) + if (c_switch_stack == NULL) { if (low_value) - error_at (loc, "case label in statement expression not containing " - "enclosing switch statement"); + error_at (loc, "case label not within a switch statement"); else - error_at (loc, "% label in statement expression not containing " - "enclosing switch statement"); + error_at (loc, "% label not within a switch statement"); + return NULL_TREE; } - else if (c_switch_stack && c_switch_stack->blocked_vm) - { - if (low_value) - error_at (loc, "case label in scope of identifier with variably " - "modified type not containing enclosing switch statement"); - else - error_at (loc, "% label in scope of identifier with " - "variably modified type not containing enclosing switch " - "statement"); - } - else if (low_value) - error_at (loc, "case label not within a switch statement"); - else - error_at (loc, "% label not within a switch statement"); + if (c_check_switch_jump_warnings (c_switch_stack->bindings, + EXPR_LOCATION (c_switch_stack->switch_expr), + loc)) + return NULL_TREE; + + label = c_add_case_label (loc, c_switch_stack->cases, + SWITCH_COND (c_switch_stack->switch_expr), + c_switch_stack->orig_type, + low_value, high_value); + if (label == error_mark_node) + label = NULL_TREE; return label; } @@ -8339,11 +8278,6 @@ c_finish_case (tree body) SWITCH_BODY (cs->switch_expr) = body; - /* We must not be within a statement expression nested in the switch - at this point; we might, however, be within the scope of an - identifier with variably modified type nested in the switch. */ - gcc_assert (!cs->blocked_stmt_expr); - /* Emit warnings as needed. */ switch_location = EXPR_LOCATION (cs->switch_expr); c_do_switch_warnings (cs->cases, switch_location, @@ -8353,6 +8287,7 @@ c_finish_case (tree body) /* Pop the stack. */ c_switch_stack = cs->next; splay_tree_delete (cs->cases); + c_release_switch_bindings (cs->bindings); XDELETE (cs); } @@ -8603,30 +8538,16 @@ tree c_begin_stmt_expr (void) { tree ret; - struct c_label_context_se *nstack; - struct c_label_list *glist; /* We must force a BLOCK for this level so that, if it is not expanded later, there is a way to turn off the entire subtree of blocks that are contained in it. */ keep_next_level (); ret = c_begin_compound_stmt (true); - if (c_switch_stack) - { - c_switch_stack->blocked_stmt_expr++; - gcc_assert (c_switch_stack->blocked_stmt_expr != 0); - } - for (glist = label_context_stack_se->labels_used; - glist != NULL; - glist = glist->next) - { - C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1; - } - nstack = XOBNEW (&parser_obstack, struct c_label_context_se); - nstack->labels_def = NULL; - nstack->labels_used = NULL; - nstack->next = label_context_stack_se; - label_context_stack_se = nstack; + + c_bindings_start_stmt_expr (c_switch_stack == NULL + ? NULL + : c_switch_stack->bindings); /* Mark the current statement list as belonging to a statement list. */ STATEMENT_LIST_STMT_EXPR (ret) = 1; @@ -8642,37 +8563,12 @@ c_finish_stmt_expr (location_t loc, tree body) { tree last, type, tmp, val; tree *last_p; - struct c_label_list *dlist, *glist, *glist_prev = NULL; body = c_end_compound_stmt (loc, body, true); - if (c_switch_stack) - { - gcc_assert (c_switch_stack->blocked_stmt_expr != 0); - c_switch_stack->blocked_stmt_expr--; - } - /* It is no longer possible to jump to labels defined within this - statement expression. */ - for (dlist = label_context_stack_se->labels_def; - dlist != NULL; - dlist = dlist->next) - { - C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1; - } - /* It is again possible to define labels with a goto just outside - this statement expression. */ - for (glist = label_context_stack_se->next->labels_used; - glist != NULL; - glist = glist->next) - { - C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0; - glist_prev = glist; - } - if (glist_prev != NULL) - glist_prev->next = label_context_stack_se->labels_used; - else - label_context_stack_se->next->labels_used - = label_context_stack_se->labels_used; - label_context_stack_se = label_context_stack_se->next; + + c_bindings_end_stmt_expr (c_switch_stack == NULL + ? NULL + : c_switch_stack->bindings); /* Locate the last statement in BODY. See c_end_compound_stmt about always returning a BIND_EXPR. */ @@ -8762,80 +8658,6 @@ c_finish_stmt_expr (location_t loc, tree body) return t; } } - -/* Begin the scope of an identifier of variably modified type, scope - number SCOPE. Jumping from outside this scope to inside it is not - permitted. */ - -void -c_begin_vm_scope (unsigned int scope) -{ - struct c_label_context_vm *nstack; - struct c_label_list *glist; - - gcc_assert (scope > 0); - - /* At file_scope, we don't have to do any processing. */ - if (label_context_stack_vm == NULL) - return; - - if (c_switch_stack && !c_switch_stack->blocked_vm) - c_switch_stack->blocked_vm = scope; - for (glist = label_context_stack_vm->labels_used; - glist != NULL; - glist = glist->next) - { - C_DECL_UNDEFINABLE_VM (glist->label) = 1; - } - nstack = XOBNEW (&parser_obstack, struct c_label_context_vm); - nstack->labels_def = NULL; - nstack->labels_used = NULL; - nstack->scope = scope; - nstack->next = label_context_stack_vm; - label_context_stack_vm = nstack; -} - -/* End a scope which may contain identifiers of variably modified - type, scope number SCOPE. */ - -void -c_end_vm_scope (unsigned int scope) -{ - if (label_context_stack_vm == NULL) - return; - if (c_switch_stack && c_switch_stack->blocked_vm == scope) - c_switch_stack->blocked_vm = 0; - /* We may have a number of nested scopes of identifiers with - variably modified type, all at this depth. Pop each in turn. */ - while (label_context_stack_vm->scope == scope) - { - struct c_label_list *dlist, *glist, *glist_prev = NULL; - - /* It is no longer possible to jump to labels defined within this - scope. */ - for (dlist = label_context_stack_vm->labels_def; - dlist != NULL; - dlist = dlist->next) - { - C_DECL_UNJUMPABLE_VM (dlist->label) = 1; - } - /* It is again possible to define labels with a goto just outside - this scope. */ - for (glist = label_context_stack_vm->next->labels_used; - glist != NULL; - glist = glist->next) - { - C_DECL_UNDEFINABLE_VM (glist->label) = 0; - glist_prev = glist; - } - if (glist_prev != NULL) - glist_prev->next = label_context_stack_vm->labels_used; - else - label_context_stack_vm->next->labels_used - = label_context_stack_vm->labels_used; - label_context_stack_vm = label_context_stack_vm->next; - } -} /* Begin and end compound statements. This is as simple as pushing and popping new statement lists from the tree. */ diff --git a/gcc/c.opt b/gcc/c.opt index da1de00d23e..e8a9a31a382 100644 --- a/gcc/c.opt +++ b/gcc/c.opt @@ -284,6 +284,10 @@ Winvalid-pch C ObjC C++ ObjC++ Warning Warn about PCH files that are found but not used +Wjump-misses-init +C Objc Var(warn_jump_misses_init) Init(-1) Warning +Warn when a jump misses a variable initialization + Wlogical-op C ObjC C++ ObjC++ Var(warn_logical_op) Init(0) Warning Warn when a logical operator is suspiciously always evaluating to true or false diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1a0e93519f1..911081ae5ac 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2009-06-15 Ian Lance Taylor + + * parser.c (cp_parser_direct_declarator): Add braces around + variables declared before label. + 2009-06-15 Rafael Avila de Espindola * cp-objcp-common.h (LANG_HOOKS_COMDAT_GROUP): Remove. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 07f0375e26e..0314bb32ea2 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13371,181 +13371,183 @@ cp_parser_direct_declarator (cp_parser* parser, } else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) { - tree qualifying_scope; - tree unqualified_name; - special_function_kind sfk; - bool abstract_ok; - bool pack_expansion_p = false; - cp_token *declarator_id_start_token; + { + tree qualifying_scope; + tree unqualified_name; + special_function_kind sfk; + bool abstract_ok; + bool pack_expansion_p = false; + cp_token *declarator_id_start_token; - /* Parse a declarator-id */ - abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER); - if (abstract_ok) - { - cp_parser_parse_tentatively (parser); + /* Parse a declarator-id */ + abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER); + if (abstract_ok) + { + cp_parser_parse_tentatively (parser); - /* If we see an ellipsis, we should be looking at a - parameter pack. */ - if (token->type == CPP_ELLIPSIS) - { - /* Consume the `...' */ - cp_lexer_consume_token (parser->lexer); + /* If we see an ellipsis, we should be looking at a + parameter pack. */ + if (token->type == CPP_ELLIPSIS) + { + /* Consume the `...' */ + cp_lexer_consume_token (parser->lexer); - pack_expansion_p = true; - } - } + pack_expansion_p = true; + } + } - declarator_id_start_token = cp_lexer_peek_token (parser->lexer); - unqualified_name - = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok); - qualifying_scope = parser->scope; - if (abstract_ok) - { - bool okay = false; + declarator_id_start_token = cp_lexer_peek_token (parser->lexer); + unqualified_name + = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok); + qualifying_scope = parser->scope; + if (abstract_ok) + { + bool okay = false; - if (!unqualified_name && pack_expansion_p) - { - /* Check whether an error occurred. */ - okay = !cp_parser_error_occurred (parser); + if (!unqualified_name && pack_expansion_p) + { + /* Check whether an error occurred. */ + okay = !cp_parser_error_occurred (parser); - /* We already consumed the ellipsis to mark a - parameter pack, but we have no way to report it, - so abort the tentative parse. We will be exiting - immediately anyway. */ - cp_parser_abort_tentative_parse (parser); - } - else - okay = cp_parser_parse_definitely (parser); + /* We already consumed the ellipsis to mark a + parameter pack, but we have no way to report it, + so abort the tentative parse. We will be exiting + immediately anyway. */ + cp_parser_abort_tentative_parse (parser); + } + else + okay = cp_parser_parse_definitely (parser); - if (!okay) - unqualified_name = error_mark_node; - else if (unqualified_name - && (qualifying_scope - || (TREE_CODE (unqualified_name) - != IDENTIFIER_NODE))) - { - cp_parser_error (parser, "expected unqualified-id"); + if (!okay) unqualified_name = error_mark_node; - } - } + else if (unqualified_name + && (qualifying_scope + || (TREE_CODE (unqualified_name) + != IDENTIFIER_NODE))) + { + cp_parser_error (parser, "expected unqualified-id"); + unqualified_name = error_mark_node; + } + } - if (!unqualified_name) - return NULL; - if (unqualified_name == error_mark_node) - { - declarator = cp_error_declarator; - pack_expansion_p = false; - declarator->parameter_pack_p = false; - break; - } + if (!unqualified_name) + return NULL; + if (unqualified_name == error_mark_node) + { + declarator = cp_error_declarator; + pack_expansion_p = false; + declarator->parameter_pack_p = false; + break; + } - if (qualifying_scope && at_namespace_scope_p () - && TREE_CODE (qualifying_scope) == TYPENAME_TYPE) - { - /* In the declaration of a member of a template class - outside of the class itself, the SCOPE will sometimes - be a TYPENAME_TYPE. For example, given: + if (qualifying_scope && at_namespace_scope_p () + && TREE_CODE (qualifying_scope) == TYPENAME_TYPE) + { + /* In the declaration of a member of a template class + outside of the class itself, the SCOPE will sometimes + be a TYPENAME_TYPE. For example, given: - template - int S::R::i = 3; + template + int S::R::i = 3; - the SCOPE will be a TYPENAME_TYPE for `S::R'. In - this context, we must resolve S::R to an ordinary - type, rather than a typename type. + the SCOPE will be a TYPENAME_TYPE for `S::R'. In + this context, we must resolve S::R to an ordinary + type, rather than a typename type. - The reason we normally avoid resolving TYPENAME_TYPEs - is that a specialization of `S' might render - `S::R' not a type. However, if `S' is - specialized, then this `i' will not be used, so there - is no harm in resolving the types here. */ - tree type; + The reason we normally avoid resolving TYPENAME_TYPEs + is that a specialization of `S' might render + `S::R' not a type. However, if `S' is + specialized, then this `i' will not be used, so there + is no harm in resolving the types here. */ + tree type; - /* Resolve the TYPENAME_TYPE. */ - type = resolve_typename_type (qualifying_scope, - /*only_current_p=*/false); - /* If that failed, the declarator is invalid. */ - if (TREE_CODE (type) == TYPENAME_TYPE) - error ("%H%<%T::%E%> is not a type", - &declarator_id_start_token->location, - TYPE_CONTEXT (qualifying_scope), - TYPE_IDENTIFIER (qualifying_scope)); - qualifying_scope = type; - } + /* Resolve the TYPENAME_TYPE. */ + type = resolve_typename_type (qualifying_scope, + /*only_current_p=*/false); + /* If that failed, the declarator is invalid. */ + if (TREE_CODE (type) == TYPENAME_TYPE) + error ("%H%<%T::%E%> is not a type", + &declarator_id_start_token->location, + TYPE_CONTEXT (qualifying_scope), + TYPE_IDENTIFIER (qualifying_scope)); + qualifying_scope = type; + } - sfk = sfk_none; + sfk = sfk_none; - if (unqualified_name) - { - tree class_type; + if (unqualified_name) + { + tree class_type; - if (qualifying_scope - && CLASS_TYPE_P (qualifying_scope)) - class_type = qualifying_scope; - else - class_type = current_class_type; + if (qualifying_scope + && CLASS_TYPE_P (qualifying_scope)) + class_type = qualifying_scope; + else + class_type = current_class_type; - if (TREE_CODE (unqualified_name) == TYPE_DECL) - { - tree name_type = TREE_TYPE (unqualified_name); - if (class_type && same_type_p (name_type, class_type)) - { - if (qualifying_scope - && CLASSTYPE_USE_TEMPLATE (name_type)) - { - error ("%Hinvalid use of constructor as a template", - &declarator_id_start_token->location); - inform (input_location, "use %<%T::%D%> instead of %<%T::%D%> to " - "name the constructor in a qualified name", - class_type, - DECL_NAME (TYPE_TI_TEMPLATE (class_type)), - class_type, name_type); - declarator = cp_error_declarator; - break; - } - else + if (TREE_CODE (unqualified_name) == TYPE_DECL) + { + tree name_type = TREE_TYPE (unqualified_name); + if (class_type && same_type_p (name_type, class_type)) + { + if (qualifying_scope + && CLASSTYPE_USE_TEMPLATE (name_type)) + { + error ("%Hinvalid use of constructor as a template", + &declarator_id_start_token->location); + inform (input_location, "use %<%T::%D%> instead of %<%T::%D%> to " + "name the constructor in a qualified name", + class_type, + DECL_NAME (TYPE_TI_TEMPLATE (class_type)), + class_type, name_type); + declarator = cp_error_declarator; + break; + } + else + unqualified_name = constructor_name (class_type); + } + else + { + /* We do not attempt to print the declarator + here because we do not have enough + information about its original syntactic + form. */ + cp_parser_error (parser, "invalid declarator"); + declarator = cp_error_declarator; + break; + } + } + + if (class_type) + { + if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR) + sfk = sfk_destructor; + else if (IDENTIFIER_TYPENAME_P (unqualified_name)) + sfk = sfk_conversion; + else if (/* There's no way to declare a constructor + for an anonymous type, even if the type + got a name for linkage purposes. */ + !TYPE_WAS_ANONYMOUS (class_type) + && constructor_name_p (unqualified_name, + class_type)) + { unqualified_name = constructor_name (class_type); - } - else - { - /* We do not attempt to print the declarator - here because we do not have enough - information about its original syntactic - form. */ - cp_parser_error (parser, "invalid declarator"); - declarator = cp_error_declarator; - break; - } - } + sfk = sfk_constructor; + } - if (class_type) - { - if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR) - sfk = sfk_destructor; - else if (IDENTIFIER_TYPENAME_P (unqualified_name)) - sfk = sfk_conversion; - else if (/* There's no way to declare a constructor - for an anonymous type, even if the type - got a name for linkage purposes. */ - !TYPE_WAS_ANONYMOUS (class_type) - && constructor_name_p (unqualified_name, - class_type)) - { - unqualified_name = constructor_name (class_type); - sfk = sfk_constructor; - } + if (ctor_dtor_or_conv_p && sfk != sfk_none) + *ctor_dtor_or_conv_p = -1; + } + } + declarator = make_id_declarator (qualifying_scope, + unqualified_name, + sfk); + declarator->id_loc = token->location; + declarator->parameter_pack_p = pack_expansion_p; - if (ctor_dtor_or_conv_p && sfk != sfk_none) - *ctor_dtor_or_conv_p = -1; - } - } - declarator = make_id_declarator (qualifying_scope, - unqualified_name, - sfk); - declarator->id_loc = token->location; - declarator->parameter_pack_p = pack_expansion_p; - - if (pack_expansion_p) - maybe_warn_variadic_templates (); + if (pack_expansion_p) + maybe_warn_variadic_templates (); + } handle_declarator:; scope = get_scope_of_declarator (declarator); diff --git a/gcc/df-problems.c b/gcc/df-problems.c index f48da9bc8dc..1d1dc9c9621 100644 --- a/gcc/df-problems.c +++ b/gcc/df-problems.c @@ -3912,19 +3912,21 @@ df_simulate_one_insn_forwards (basic_block bb, rtx insn, bitmap live) for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) { switch (REG_NOTE_KIND (link)) + { case REG_DEAD: case REG_UNUSED: - { - rtx reg = XEXP (link, 0); - int regno = REGNO (reg); - if (regno < FIRST_PSEUDO_REGISTER) - { - int n = hard_regno_nregs[regno][GET_MODE (reg)]; - while (--n >= 0) - bitmap_clear_bit (live, regno + n); - } - else - bitmap_clear_bit (live, regno); + { + rtx reg = XEXP (link, 0); + int regno = REGNO (reg); + if (regno < FIRST_PSEUDO_REGISTER) + { + int n = hard_regno_nregs[regno][GET_MODE (reg)]; + while (--n >= 0) + bitmap_clear_bit (live, regno + n); + } + else + bitmap_clear_bit (live, regno); + } break; default: break; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8d133d097e6..f75a6a8a021 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -238,7 +238,7 @@ Objective-C and Objective-C++ Dialects}. -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol -Wformat-security -Wformat-y2k @gol --Wframe-larger-than=@var{len} -Wignored-qualifiers @gol +-Wframe-larger-than=@var{len} -Wjump-misses-init -Wignored-qualifiers @gol -Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol -Winit-self -Winline @gol -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol @@ -2973,6 +2973,20 @@ requiring a non-null value by the @code{nonnull} function attribute. @option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}. It can be disabled with the @option{-Wno-nonnull} option. +@item -Wjump-misses-init @r{(C, Objective-C only)} +@opindex Wjump-misses-init +@opindex Wno-jump-misses-init +Warn if a @code{goto} statement or a @code{switch} statement jumps +forward across the initialization of a variable, or jumps backward to a +label after the variable has been initialized. This only warns about +variables which are initialized when they are declared. This warning is +only supported for C and Objective C; in C++ this sort of branch is an +error in any case. + +@option{-Wjump-misses-init} is included in @option{-Wall} and +@option{-Wc++-compat}. It can be disabled with the +@option{-Wno-jump-misses-init} option. + @item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)} @opindex Winit-self @opindex Wno-init-self diff --git a/gcc/gcov.c b/gcc/gcov.c index 61ac7ed6974..4f5c3d4ebba 100644 --- a/gcc/gcov.c +++ b/gcc/gcov.c @@ -1065,27 +1065,29 @@ read_count_file (void) program_count++; else if (tag == GCOV_TAG_FUNCTION) { - unsigned ident = gcov_read_unsigned (); - struct function_info *fn_n = functions; + { + unsigned ident = gcov_read_unsigned (); + struct function_info *fn_n = functions; - /* Try to find the function in the list. - To speed up the search, first start from the last function - found. */ - for (fn = fn ? fn->next : NULL; ; fn = fn->next) - { - if (fn) - ; - else if ((fn = fn_n)) - fn_n = NULL; - else - { - fnotice (stderr, "%s:unknown function '%u'\n", - da_file_name, ident); + /* Try to find the function in the list. + To speed up the search, first start from the last function + found. */ + for (fn = fn ? fn->next : NULL; ; fn = fn->next) + { + if (fn) + ; + else if ((fn = fn_n)) + fn_n = NULL; + else + { + fnotice (stderr, "%s:unknown function '%u'\n", + da_file_name, ident); + break; + } + if (fn->ident == ident) break; - } - if (fn->ident == ident) - break; - } + } + } if (!fn) ; diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 5aaa3b74722..2fe4b25be8c 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,8 @@ +2009-06-15 Ian Lance Taylor + + * objc-act.c (objc_start_function): Don't set + label_context_stack_se or label_context_stack_vm. + 2009-06-12 Aldy Hernandez * objc-act.c (finish_var_decl): Pass location to finish_decl. diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 0c91faa5363..f114b65ef4a 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -8632,19 +8632,6 @@ objc_start_function (tree name, tree type, tree attrs, cplus_decl_attributes (&fndecl, attrs, 0); start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT); #else - struct c_label_context_se *nstack_se; - struct c_label_context_vm *nstack_vm; - nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); - nstack_se->labels_def = NULL; - nstack_se->labels_used = NULL; - nstack_se->next = label_context_stack_se; - label_context_stack_se = nstack_se; - nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm); - nstack_vm->labels_def = NULL; - nstack_vm->labels_used = NULL; - nstack_vm->scope = 0; - nstack_vm->next = label_context_stack_vm; - label_context_stack_vm = nstack_vm; current_function_returns_value = 0; /* Assume, until we see it does. */ current_function_returns_null = 0; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 62874a710d7..c961525e9d7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2009-06-15 Ian Lance Taylor + + * gcc.dg/Wjump-misses-init-1.c: New testcase. + * gcc.dg/Wjump-misses-init-2.c: New testcase. + * gcc.dg/c99-vla-jump-5.c: Adjust expected error messages. + Recognize new notes. + * gcc.dg/stmt-expr-label-2.c: Likewise. + * gcc.dg/c99-vla-jump-1.c: Recognize new notes. Fix column + numbers. + * gcc.dg/c99-vla-jump-2.c: Recognize new notes. + * gcc.dg/c99-vla-jump-3.c: Recognize new notes. + * gcc.dg/c99-vla-jump-4.c: Likewise. + * gcc.dg/stmt-expr-label-1.c: Likewise. + * gcc.dg/stmt-expr-label-3.c: Likewise. + * gcc.dg/vla-8.c: Likewise. Move error message to different + line. + 2009-06-16 Kaveh R. Ghazi * gcc.dg/torture/builtin-math-6.c: Robustify and fix clog cases. diff --git a/gcc/testsuite/gcc.dg/Wjump-misses-init-1.c b/gcc/testsuite/gcc.dg/Wjump-misses-init-1.c new file mode 100644 index 00000000000..86117f1f2f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wjump-misses-init-1.c @@ -0,0 +1,156 @@ +/* { dg-do compile } */ +/* { dg-options "-Wjump-misses-init" } */ +int +f1 (int a) +{ + if (a > 0) + { + int i = 7; /* { dg-message "here" } */ + lab: /* { dg-message "here" } */ + return a; + } + else + { + if (a < 0) + goto lab; /* { dg-warning "jump" } */ + return 1; + } +} + +int +f2 (int a) +{ + if (a > 0) + { + if (a < 0) + goto lab; /* { dg-warning "jump" } */ + return 1; + } + else + { + int i = 7; /* { dg-message "here" } */ + lab: /* { dg-message "here" } */ + return a; + } +} + +int +f3 (int a) +{ + if (a > 0) + { + static int i = 7; + lab: + return a; + } + else + { + if (a < 0) + goto lab; + return 1; + } +} + +int +f4 (int a) +{ + if (a > 0) + { + if (a < 0) + goto lab; + return 1; + } + else + { + static int i = 7; + lab: + return a; + } +} + +int +f5 (int a) +{ + if (a > 0) + { + int b = 1; + if (a < 0) + goto lab; + } + lab: + return a; +} + +int +f6 (int a) +{ + if (a > 0) + { + lab: + return a; + } + else + { + int b = 1; + goto lab; + } +} + +int +f7 (int a) +{ + switch (a) /* { dg-message "switch" } */ + { + int b = 1; /* { dg-message "here" } */ + + case 1: /* { dg-warning "jump" } */ + return a; + } +} + +int +f8 (int a) +{ + switch (a) /* { dg-message "switch" } */ + { + int b = 1; /* { dg-message "here" } */ + + case 1: /* { dg-warning "jump" } */ + goto lab; + } + lab: + return a; +} + +int +f9 (int a) +{ + switch (a) + { + case 0: + { + int b = 1; + return b; + } + case 1: + return a; + } +} + +int +f10 (int a) +{ + switch (a) + { + case 0: + { + int b = 1; + goto lab; + } + + case 1: + goto lab; + } + lab: + return a; +} diff --git a/gcc/testsuite/gcc.dg/Wjump-misses-init-2.c b/gcc/testsuite/gcc.dg/Wjump-misses-init-2.c new file mode 100644 index 00000000000..042c02aa7bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wjump-misses-init-2.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-Wjump-misses-init -std=c99" } */ +extern void f1 (); +int +f2 (int a) +{ + switch (a) /* { dg-message "switch" } */ + { + case 1: + f1 (); + int v2 = 3; /* { dg-message "here" } */ + case 2: /* { dg-warning "jump" } */ + if (v2 == 7) + f1 (); + } + return 0; +} + +int +f3 (int i) +{ + if (i) + goto bad; /* { dg-warning "jump" } */ + int a = f2 (i); /* { dg-message "here" } */ + bad: /* { dg-message "here" } */ + return a; +} + +int +f4 (int a) +{ + switch (a) + { + case 1: + f1 (); + static int v2 = 3; + case 2: + if (v2 == 7) + f1 (); + } + return 0; +} + +int +f5 (int i) +{ + if (i) + goto bad; + static int a = 6; + bad: + return a; +} diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-1.c b/gcc/testsuite/gcc.dg/c99-vla-jump-1.c index 3cfa384d1ca..8e34b100131 100644 --- a/gcc/testsuite/gcc.dg/c99-vla-jump-1.c +++ b/gcc/testsuite/gcc.dg/c99-vla-jump-1.c @@ -15,11 +15,11 @@ /* { dg-options "-std=iso9899:1999 -pedantic-errors" } */ void fa0 (int n) { goto a; a:{ int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } -void fa1 (int n) { goto a; { int b[n]; a:{ int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "41:jump into scope of identifier with variably modified type" } */ -void fa2 (int n) { goto a; { int b[n]; { int c[n]; a:0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "53:jump into scope of identifier with variably modified type" } */ -void fa3 (int n) { goto a; { int b[n]; { int c[n]; 0;} a:{ int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "57:jump into scope of identifier with variably modified type" } */ -void fa4 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; a:0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "69:jump into scope of identifier with variably modified type" } */ -void fa5 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} a:; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "73:jump into scope of identifier with variably modified type" } */ +void fa1 (int n) { goto a; { int b[n]; a:{ int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */ +void fa2 (int n) { goto a; { int b[n]; { int c[n]; a:0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */ +void fa3 (int n) { goto a; { int b[n]; { int c[n]; 0;} a:{ int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */ +void fa4 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; a:0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */ +void fa5 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} a:; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */ void fa6 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; a:0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "jump into scope of identifier with variably modified type" } */ void fa7 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; a:{ int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } void fa8 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; a:{ int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "jump into scope of identifier with variably modified type" } */ @@ -303,3 +303,7 @@ void fa285 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;} void fa286 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; a:; int j[n]; 0; goto a; } void fa287 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; a:0; goto a; } void fa288 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0;a: goto a; } + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ +/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-2.c b/gcc/testsuite/gcc.dg/c99-vla-jump-2.c index 27cecaa604f..2b4d4d56a5d 100644 --- a/gcc/testsuite/gcc.dg/c99-vla-jump-2.c +++ b/gcc/testsuite/gcc.dg/c99-vla-jump-2.c @@ -303,3 +303,7 @@ void fb285 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:g void fb286 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; a:; int j[n]; P03A:goto P03A;0;p03B:goto p03B; goto a; P03B:goto P03B; } void fb287 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; P0C:goto P0C;; int j[n]; a:0;p03B:goto p03B; goto a; P03B:goto P03B; } void fb288 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; P0C:goto P0C;; int j[n]; P03A:goto P03A;0;a: goto a; P03B:goto P03B; } + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ +/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-3.c b/gcc/testsuite/gcc.dg/c99-vla-jump-3.c index 0aff362d61f..ac1ae96c2c9 100644 --- a/gcc/testsuite/gcc.dg/c99-vla-jump-3.c +++ b/gcc/testsuite/gcc.dg/c99-vla-jump-3.c @@ -303,3 +303,7 @@ void fc285 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef void fc286 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; a:; typedef int (*j)[n]; 0; goto a; } void fc287 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; ; typedef int (*j)[n]; a:0; goto a; } void fc288 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; ; typedef int (*j)[n]; 0;a: goto a; } + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ +/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-4.c b/gcc/testsuite/gcc.dg/c99-vla-jump-4.c index e77a14209af..848dfba945c 100644 --- a/gcc/testsuite/gcc.dg/c99-vla-jump-4.c +++ b/gcc/testsuite/gcc.dg/c99-vla-jump-4.c @@ -303,3 +303,7 @@ void fd285 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typede void fd286 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; a:; typedef int (*j)[n]; P03A:goto P03A;0;p03B:goto p03B; goto a; P03B:goto P03B; } void fd287 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; P0C:goto P0C;; typedef int (*j)[n]; a:0;p03B:goto p03B; goto a; P03B:goto P03B; } void fd288 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; P0C:goto P0C;; typedef int (*j)[n]; P03A:goto P03A;0;a: goto a; P03B:goto P03B; } + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ +/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-5.c b/gcc/testsuite/gcc.dg/c99-vla-jump-5.c index ca3f85f5931..683bcf21eb3 100644 --- a/gcc/testsuite/gcc.dg/c99-vla-jump-5.c +++ b/gcc/testsuite/gcc.dg/c99-vla-jump-5.c @@ -16,8 +16,8 @@ f (int a, int b) { switch (a) { int v[b]; - case 2: /* { dg-error "case label in scope of identifier with variably modified type not containing enclosing switch statement" } */ - default: /* { dg-error "'default' label in scope of identifier with variably modified type not containing enclosing switch statement" } */ + case 2: /* { dg-error "switch jumps into scope of identifier with variably modified type" } */ + default: /* { dg-error "switch jumps into scope of identifier with variably modified type" } */ switch (a) { case 4: @@ -28,3 +28,7 @@ f (int a, int b) } } } + +/* Match extra informative notes. */ +/* { dg-message "note: switch starts here" "note: expected" { target *-*-* } 0 } */ +/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/stmt-expr-label-1.c b/gcc/testsuite/gcc.dg/stmt-expr-label-1.c index 57ab34eaab2..a9dd46623f3 100644 --- a/gcc/testsuite/gcc.dg/stmt-expr-label-1.c +++ b/gcc/testsuite/gcc.dg/stmt-expr-label-1.c @@ -402,3 +402,6 @@ void f194 (void) { ({ ({0;}); ({0;}); 0;}); ({ ({0;}); ({0;}); 0;}); a:0; goto a void fa194 (void) { P0A:goto P0A;({ P01A:goto P01A;({P012A:goto P012A;0;}); P01B:goto P01B;({P013A:goto P013A;0;}); P01C:goto P01C;0;}); P0B:goto P0B;({ P02A:goto P02A;({P024A:goto P024A;0;}); P02B:goto P02B;({P025A:goto P025A;0;}); P02C:goto P02C;0;}); a:0;p0D:goto p0D; goto a; P0D:goto P0D; } void f195 (void) { ({ ({0;}); ({0;}); 0;}); ({ ({0;}); ({0;}); 0;}); 0;a: goto a; } void fa195 (void) { P0A:goto P0A;({ P01A:goto P01A;({P012A:goto P012A;0;}); P01B:goto P01B;({P013A:goto P013A;0;}); P01C:goto P01C;0;}); P0B:goto P0B;({ P02A:goto P02A;({P024A:goto P024A;0;}); P02B:goto P02B;({P025A:goto P025A;0;}); P02C:goto P02C;0;}); P0C:goto P0C;0;a: goto a; P0D:goto P0D; } + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/stmt-expr-label-2.c b/gcc/testsuite/gcc.dg/stmt-expr-label-2.c index 35b96e830e5..be7aa521000 100644 --- a/gcc/testsuite/gcc.dg/stmt-expr-label-2.c +++ b/gcc/testsuite/gcc.dg/stmt-expr-label-2.c @@ -8,13 +8,13 @@ void f (int a) { - switch (a) + switch (a) /* { dg-message "here" } */ { case 0: case 1: ({ - case 2: /* { dg-error "case label in statement expression not containing enclosing switch statement" } */ - default: /* { dg-error "'default' label in statement expression not containing enclosing switch statement" } */ + case 2: /* { dg-error "switch jumps into statement expression" } */ + default: /* { dg-error "switch jumps into statement expression" } */ switch (a) { case 3: diff --git a/gcc/testsuite/gcc.dg/stmt-expr-label-3.c b/gcc/testsuite/gcc.dg/stmt-expr-label-3.c index 7b1515f89ac..0a6722283f4 100644 --- a/gcc/testsuite/gcc.dg/stmt-expr-label-3.c +++ b/gcc/testsuite/gcc.dg/stmt-expr-label-3.c @@ -6,3 +6,6 @@ /* { dg-options "-O2" } */ void f(void) { 1 ? 1 : ({ a : 1; 1; }); goto a; } /* { dg-error "jump into statement expression" } */ + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/vla-8.c b/gcc/testsuite/gcc.dg/vla-8.c index 1d31876b9b4..6e14a06875e 100644 --- a/gcc/testsuite/gcc.dg/vla-8.c +++ b/gcc/testsuite/gcc.dg/vla-8.c @@ -23,8 +23,12 @@ void foo1(int n) { } void foo2(int n) { - goto A; + goto A; /* { dg-error "jump into scope of identifier with variably modified type" } */ int (*(*bar2)(void))[n]; - A: /* { dg-error "jump into scope of identifier with variably modified type" } */ + A: ; } + +/* Match extra informative notes. */ +/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */ +/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */