[C] Detect all variably modified types [PR108375]

Message ID 90d59cd87874bf1c281f1c1ff8d7ab3074434ce2.camel@tugraz.at
State Accepted
Headers
Series [C] Detect all variably modified types [PR108375] |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Martin Uecker Feb. 17, 2023, 6:17 p.m. UTC
  Here is a patch for PR108375.

Bootstrapped and regession tested on x86_64-linux-gnu


Also there is a middle-end patch for PR107557 and PR108423:
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611562.html
and another C FE patch for PR105660:
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611817.html

All regressions.



    C: Detect all variably modified types [PR108375]
    
    Some variably modified types were not detected correctly.
    Define C_TYPE_VARIABLY_MODIFIED via TYPE_LANG_FLAG 6 in the CFE.
    This flag records whether a type is variably modified and is
    set for all such types including arrays with variably modified
    element type or structures and unions with variably modified
    members. This is then used to detect such types in the C FE
    and middle-end (via the existing language hook).
    
            PR 108375
    
    gcc/c/
    
            * c/c-decl.c (decl_jump_unsafe): Use c_type_variably_modified_p.
            (diagnose_mismatched_decl): Dito.
            (warn_about_goto): Dito:
            (c_check_switch_jump_warnings): Dito.
            (finish_decl): Dito.
            (finish_struct): Dito.
            (grokdeclarator): Set C_TYPE_VARIABLY_MODIFIED.
            (finish_struct): Set C_TYPE_VARIABLY_MODIFIED.
            * c/c-objc-common.cc (c_var_mod_p): New function.
            (c_var_unspec_p): Remove.
            * c/c-objc-common.h: Set lang hook.
            * c/c-parser.cc (c_parser_declararion_or_fndef): Use c_type_variably_modified_p.
            (c_parser_typeof_specifier): Dito.
            (c_parser_has_attribute_expression): Dito.
            (c_parser_generic_selection): Dito.
            * c/c-tree.h: Define C_TYPE_VARIABLY_MODIFIED and define c_var_mode_p.
            * c/c-typeck.h: Remove c_vla_mod_p and use C_TYPE_VARIABLY_MODIFIED.
    
    gcc/testsuite/
    
            * gcc.dg/pr108375-1.c: New test.
            * gcc.dg/pr108375-2.c: New test.
  

Comments

Joseph Myers Feb. 17, 2023, 10:22 p.m. UTC | #1
On Fri, 17 Feb 2023, Martin Uecker via Gcc-patches wrote:

> Here is a patch for PR108375.

This patch is OK.

> and another C FE patch for PR105660:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611817.html

This one is also OK.
  

Patch

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 20e7d1855bf..08078eadeb8 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 0350733250b..e4aed61ed00 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 3861093d9e4..d31dacb9dd4 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 43427886ad4..21bc3167ce2 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 e5eefe6bbba..e6b6fe9a40e 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 e37b0973cd6..45bacc06c47 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 00000000000..1cbb05b03ce
--- /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 00000000000..0401ead5b21
--- /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 : ;
+}
+
+