aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c/c-decl.cc34
-rw-r--r--gcc/c/c-objc-common.cc6
-rw-r--r--gcc/c/c-objc-common.h2
-rw-r--r--gcc/c/c-parser.cc13
-rw-r--r--gcc/c/c-tree.h16
-rw-r--r--gcc/c/c-typeck.cc20
-rw-r--r--gcc/testsuite/gcc.dg/pr108375-1.c14
-rw-r--r--gcc/testsuite/gcc.dg/pr108375-2.c15
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 : ;
+}
+
+