diff options
-rw-r--r-- | gcc/c/c-decl.cc | 34 | ||||
-rw-r--r-- | gcc/c/c-objc-common.cc | 6 | ||||
-rw-r--r-- | gcc/c/c-objc-common.h | 2 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 13 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 16 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr108375-1.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr108375-2.c | 15 |
8 files changed, 79 insertions, 41 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 20e7d18..08078ea 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -683,7 +683,7 @@ decl_jump_unsafe (tree decl) /* Always warn about crossing variably modified types. */ if ((VAR_P (decl) || TREE_CODE (decl) == TYPE_DECL) - && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + && c_type_variably_modified_p (TREE_TYPE (decl))) return true; /* Otherwise, only warn if -Wgoto-misses-init and this is an @@ -2247,7 +2247,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, || warning_suppressed_p (olddecl, OPT_Wpedantic)) return true; /* Allow OLDDECL to continue in use. */ - if (variably_modified_type_p (newtype, NULL)) + if (c_type_variably_modified_p (newtype)) { error ("redefinition of typedef %q+D with variably modified type", newdecl); @@ -3975,7 +3975,7 @@ static void warn_about_goto (location_t goto_loc, tree label, tree decl) { auto_diagnostic_group d; - if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + if (c_type_variably_modified_p (TREE_TYPE (decl))) error_at (goto_loc, "jump into scope of identifier with variably modified type"); else @@ -4249,7 +4249,7 @@ c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings, { auto_diagnostic_group d; bool emitted; - if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE)) + if (c_type_variably_modified_p (TREE_TYPE (b->decl))) { saw_error = true; error_at (case_loc, @@ -5862,7 +5862,7 @@ finish_decl (tree decl, location_t init_loc, tree init, if (TREE_CODE (decl) == TYPE_DECL) { if (!DECL_FILE_SCOPE_P (decl) - && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) + && c_type_variably_modified_p (TREE_TYPE (decl))) add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); @@ -6682,7 +6682,7 @@ grokdeclarator (const struct c_declarator *declarator, if ((decl_context == NORMAL || decl_context == FIELD) && current_scope == file_scope - && variably_modified_type_p (type, NULL_TREE)) + && c_type_variably_modified_p (type)) { if (name) error_at (loc, "variably modified %qE at file scope", name); @@ -6928,6 +6928,8 @@ grokdeclarator (const struct c_declarator *declarator, array_parm_static = false; } + bool varmod = C_TYPE_VARIABLY_MODIFIED (type); + switch (declarator->kind) { case cdk_attrs: @@ -7282,8 +7284,7 @@ grokdeclarator (const struct c_declarator *declarator, variable size, so the enclosing shared array type must too. */ if (size && TREE_CODE (size) == INTEGER_CST) - type - = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); + type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type)); C_TYPE_VARIABLE_SIZE (type) = 1; } @@ -7493,7 +7494,7 @@ grokdeclarator (const struct c_declarator *declarator, the size evaluation prior to the side effects. We therefore use BIND_EXPRs in TYPENAME contexts too. */ if (!TYPE_NAME (type) - && variably_modified_type_p (type, NULL_TREE)) + && c_type_variably_modified_p (type)) { tree bind = NULL_TREE; if (decl_context == TYPENAME || decl_context == PARM) @@ -7534,6 +7535,8 @@ grokdeclarator (const struct c_declarator *declarator, default: gcc_unreachable (); } + if (type != error_mark_node) + C_TYPE_VARIABLY_MODIFIED (type) = varmod || size_varies; } *decl_attrs = chainon (returned_attrs, *decl_attrs); *decl_attrs = chainon (decl_id_attrs, *decl_attrs); @@ -7728,7 +7731,7 @@ grokdeclarator (const struct c_declarator *declarator, } if (pedantic && decl_context == FIELD - && variably_modified_type_p (type, NULL_TREE)) + && c_type_variably_modified_p (type)) { /* C99 6.7.2.1p8 */ pedwarn (loc, OPT_Wpedantic, "a member of a structure or union cannot " @@ -7996,7 +7999,7 @@ grokdeclarator (const struct c_declarator *declarator, have a member with such a qualifier. const qualification is implicitly added, and, at file scope, has internal linkage. */ - if (variably_modified_type_p (type, NULL_TREE)) + if (c_type_variably_modified_p (type)) error_at (loc, "%<constexpr%> object has variably modified " "type"); if (type_quals @@ -8078,7 +8081,7 @@ grokdeclarator (const struct c_declarator *declarator, || (storage_class == csc_none && TREE_CODE (type) == FUNCTION_TYPE && !funcdef_flag)) - && variably_modified_type_p (type, NULL_TREE)) + && c_type_variably_modified_p (type)) { /* C99 6.7.5.2p2 */ if (TREE_CODE (type) == FUNCTION_TYPE) @@ -9233,6 +9236,10 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (C_DECL_VARIABLE_SIZE (x)) C_TYPE_VARIABLE_SIZE (t) = 1; + /* If any field is variably modified, record this fact. */ + if (C_TYPE_VARIABLY_MODIFIED (TREE_TYPE (x))) + C_TYPE_VARIABLY_MODIFIED (t) = 1; + if (DECL_C_BIT_FIELD (x)) { unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x)); @@ -9431,6 +9438,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); C_TYPE_FIELDS_NON_CONSTEXPR (x) = C_TYPE_FIELDS_NON_CONSTEXPR (t); C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); + C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t); C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; } @@ -9447,7 +9455,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, /* If we're inside a function proper, i.e. not file-scope and not still parsing parameters, then arrange for the size of a variable sized type to be bound now. */ - if (building_stmt_list_p () && variably_modified_type_p (t, NULL_TREE)) + if (building_stmt_list_p () && c_type_variably_modified_p(t)) add_stmt (build_stmt (loc, DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index 0350733..e4aed61 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -371,12 +371,12 @@ c_types_compatible_p (tree x, tree y) return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y)); } -/* Determine if the type is a vla type for the backend. */ +/* Determine if the type is a variably modified type for the backend. */ bool -c_vla_unspec_p (tree x, tree fn ATTRIBUTE_UNUSED) +c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED) { - return c_vla_type_p (x); + return C_TYPE_VARIABLY_MODIFIED (x); } /* Special routine to get the alias set of T for C. */ diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index 3861093..d31dacb 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -123,5 +123,5 @@ along with GCC; see the file COPYING3. If not see #define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP c_omp_clause_copy_ctor #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P -#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P c_vla_unspec_p +#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P c_var_mod_p #endif /* GCC_C_OBJC_COMMON */ diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 4342788..21bc316 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -2494,8 +2494,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, init = convert_lvalue_to_rvalue (init_loc, init, true, true, true); tree init_type = TREE_TYPE (init.value); - bool vm_type = variably_modified_type_p (init_type, - NULL_TREE); + bool vm_type = c_type_variably_modified_p (init_type); if (vm_type) init.value = save_expr (init.value); finish_init (); @@ -4143,7 +4142,7 @@ c_parser_typeof_specifier (c_parser *parser) if (type != NULL) { ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); - pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); + pop_maybe_used (c_type_variably_modified_p (ret.spec)); } } else @@ -4158,7 +4157,7 @@ c_parser_typeof_specifier (c_parser *parser) error_at (here, "%<typeof%> applied to a bit-field"); mark_exp_read (expr.value); ret.spec = TREE_TYPE (expr.value); - was_vm = variably_modified_type_p (ret.spec, NULL_TREE); + was_vm = c_type_variably_modified_p (ret.spec); /* This is returned with the type so that when the type is evaluated, this can be evaluated. */ if (was_vm) @@ -9058,7 +9057,7 @@ c_parser_has_attribute_expression (c_parser *parser) if (tname) { oper = groktypename (tname, NULL, NULL); - pop_maybe_used (variably_modified_type_p (oper, NULL_TREE)); + pop_maybe_used (c_type_variably_modified_p (oper)); } } else @@ -9071,7 +9070,7 @@ c_parser_has_attribute_expression (c_parser *parser) mark_exp_read (cexpr.value); oper = cexpr.value; tree etype = TREE_TYPE (oper); - bool was_vm = variably_modified_type_p (etype, NULL_TREE); + bool was_vm = c_type_variably_modified_p (etype); /* This is returned with the type so that when the type is evaluated, this can be evaluated. */ if (was_vm) @@ -9320,7 +9319,7 @@ c_parser_generic_selection (c_parser *parser) error_at (assoc.type_location, "%<_Generic%> association has incomplete type"); - if (variably_modified_type_p (assoc.type, NULL_TREE)) + if (c_type_variably_modified_p (assoc.type)) error_at (assoc.type_location, "%<_Generic%> association has " "variable length type"); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index e5eefe6..e6b6fe9 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -59,6 +59,10 @@ along with GCC; see the file COPYING3. If not see #define C_TYPE_VARIABLE_SIZE(TYPE) TYPE_LANG_FLAG_1 (TYPE) #define C_DECL_VARIABLE_SIZE(TYPE) DECL_LANG_FLAG_0 (TYPE) +/* Record whether a type is variably modified. */ +#define C_TYPE_VARIABLY_MODIFIED(TYPE) TYPE_LANG_FLAG_6 (TYPE) + + /* Record whether a type is defined inside a struct or union type. This is used for -Wc++-compat. */ #define C_TYPE_DEFINED_IN_STRUCT(TYPE) TYPE_LANG_FLAG_2 (TYPE) @@ -714,7 +718,7 @@ extern bool c_objc_common_init (void); extern bool c_missing_noreturn_ok_p (tree); extern bool c_warn_unused_global_decl (const_tree); extern void c_initialize_diagnostics (diagnostic_context *); -extern bool c_vla_unspec_p (tree x, tree fn); +extern bool c_var_mod_p (tree x, tree fn); extern alias_set_type c_get_alias_set (tree); /* in c-typeck.cc */ @@ -729,6 +733,15 @@ extern location_t c_last_sizeof_loc; extern struct c_switch *c_switch_stack; extern bool null_pointer_constant_p (const_tree); + + +inline +bool c_type_variably_modified_p (tree t) +{ + return error_mark_node != t && C_TYPE_VARIABLY_MODIFIED (t); +} + + extern bool char_type_p (tree); extern tree c_objc_common_truthvalue_conversion (location_t, tree); extern tree require_complete_type (location_t, tree); @@ -736,7 +749,6 @@ extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); extern int comptypes_check_enum_int (tree, tree, bool *); -extern bool c_vla_type_p (const_tree); extern bool c_mark_addressable (tree, bool = false); extern void c_incomplete_type_error (location_t, const_tree, const_tree); extern tree c_type_promotes_to (tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index e37b097..45bacc0 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -356,16 +356,6 @@ qualify_type (tree type, tree like) | ENCODE_QUAL_ADDR_SPACE (as_common)); } -/* Return true iff the given tree T is a variable length array. */ - -bool -c_vla_type_p (const_tree t) -{ - if (TREE_CODE (t) == ARRAY_TYPE - && C_TYPE_VARIABLE_SIZE (t)) - return true; - return false; -} /* If NTYPE is a type of a non-variadic function with a prototype and OTYPE is a type of a function without a prototype and ATTRS @@ -471,8 +461,8 @@ composite_type (tree t1, tree t2) d2_variable = (!d2_zero && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); - d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); - d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); + d1_variable = d1_variable || (d1_zero && C_TYPE_VARIABLE_SIZE (t1)); + d2_variable = d2_variable || (d2_zero && C_TYPE_VARIABLE_SIZE (t2)); /* Save space: see if the result is identical to one of the args. */ if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1) @@ -1248,8 +1238,8 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, d2_variable = (!d2_zero && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); - d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1)); - d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2)); + d1_variable = d1_variable || (d1_zero && C_TYPE_VARIABLE_SIZE (t1)); + d2_variable = d2_variable || (d2_zero && C_TYPE_VARIABLE_SIZE (t2)); if (different_types_p != NULL && d1_variable != d2_variable) @@ -3346,7 +3336,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, /* In this improbable scenario, a nested function returns a VM type. Create a TARGET_EXPR so that the call always has a LHS, much as what the C++ FE does for functions returning non-PODs. */ - if (variably_modified_type_p (TREE_TYPE (fntype), NULL_TREE)) + if (C_TYPE_VARIABLY_MODIFIED (TREE_TYPE (fntype))) { tree tmp = create_tmp_var_raw (TREE_TYPE (fntype)); result = build4 (TARGET_EXPR, TREE_TYPE (fntype), tmp, result, diff --git a/gcc/testsuite/gcc.dg/pr108375-1.c b/gcc/testsuite/gcc.dg/pr108375-1.c new file mode 100644 index 0000000..1cbb05b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr108375-1.c @@ -0,0 +1,14 @@ +/* PR 108375 + * { dg-do compile } + * { dg-options "" } + * */ + +void +f (int a) +{ + goto x; /* { dg-error "jump into scope of identifier with variably modified type" } */ + struct { char (*p)[a]; } B; + x : ; +} + + diff --git a/gcc/testsuite/gcc.dg/pr108375-2.c b/gcc/testsuite/gcc.dg/pr108375-2.c new file mode 100644 index 0000000..0401ead --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr108375-2.c @@ -0,0 +1,15 @@ +/* PR 108375 + * { dg-do compile } + * { dg-options "" } + * */ + +void +f (int a) +{ + typedef int A[a]; + goto x; /* { dg-error "jump into scope of identifier with variably modified type" } */ + A *p[2]; + x : ; +} + + |