===================================================================
@@ -5667,39 +5667,6 @@ check_compound_literal_type (location_t
"defining a type in a compound literal is invalid in C++");
}
-/* Determine whether TYPE is a structure with a flexible array member,
- or a union containing such a structure (possibly recursively). */
-
-static bool
-flexible_array_type_p (tree type)
-{
- tree x;
- switch (TREE_CODE (type))
- {
- case RECORD_TYPE:
- x = TYPE_FIELDS (type);
- if (x == NULL_TREE)
- return false;
- while (DECL_CHAIN (x) != NULL_TREE)
- x = DECL_CHAIN (x);
- if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
- && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
- && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
- && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
- return true;
- return false;
- case UNION_TYPE:
- for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
- {
- if (flexible_array_type_p (TREE_TYPE (x)))
- return true;
- }
- return false;
- default:
- return false;
- }
-}
-
/* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME,
replacing with appropriate values if they are invalid. */
===================================================================
@@ -796,7 +796,7 @@ alpha_in_small_data_p (const_tree exp)
}
else
{
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT size = fixed_int_size_in_bytes (TREE_TYPE (exp));
/* If this is an incomplete type with size 0, then we can't put it
in sdata because it might be too big when completed. */
===================================================================
@@ -8643,7 +8643,7 @@ arc_in_small_data_p (const_tree decl)
section. */
else if (TREE_PUBLIC (decl))
{
- size = int_size_in_bytes (TREE_TYPE (decl));
+ size = fixed_int_size_in_bytes (TREE_TYPE (decl));
return (size > 0 && size <= g_switch_value);
}
return false;
===================================================================
@@ -9319,7 +9319,7 @@ frv_in_small_data_p (const_tree decl)
return false;
}
- size = int_size_in_bytes (TREE_TYPE (decl));
+ size = fixed_int_size_in_bytes (TREE_TYPE (decl));
if (size > 0 && size <= g_switch_value)
return true;
===================================================================
@@ -10016,7 +10016,7 @@ ia64_in_small_data_p (const_tree exp)
}
else
{
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT size = fixed_int_size_in_bytes (TREE_TYPE (exp));
/* If this is an incomplete type with size 0, then we can't put it
in sdata because it might be too big when completed. */
===================================================================
@@ -795,7 +795,7 @@ lm32_in_small_data_p (const_tree exp)
}
else
{
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT size = fixed_int_size_in_bytes (TREE_TYPE (exp));
/* If this is an incomplete type with size 0, then we can't put it
in sdata because it might be too big when completed. */
===================================================================
@@ -513,7 +513,7 @@ m32r_in_small_data_p (const_tree decl)
{
if (! TREE_READONLY (decl) && ! TARGET_SDATA_NONE)
{
- int size = int_size_in_bytes (TREE_TYPE (decl));
+ int size = fixed_int_size_in_bytes (TREE_TYPE (decl));
if (size > 0 && size <= g_switch_value)
return true;
===================================================================
@@ -3236,7 +3236,7 @@ microblaze_elf_in_small_data_p (const_tr
return true;
}
- size = int_size_in_bytes (TREE_TYPE (decl));
+ size = fixed_int_size_in_bytes (TREE_TYPE (decl));
return (size > 0 && size <= microblaze_section_threshold);
}
===================================================================
@@ -9399,7 +9399,7 @@ mips_in_small_data_p (const_tree decl)
/* We have traditionally not treated zero-sized objects as small data,
so this is now effectively part of the ABI. */
- size = int_size_in_bytes (TREE_TYPE (decl));
+ size = fixed_int_size_in_bytes (TREE_TYPE (decl));
return size > 0 && size <= mips_small_data_threshold;
}
===================================================================
@@ -2375,7 +2375,7 @@ nios2_in_small_data_p (const_tree exp)
}
else
{
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT size = fixed_int_size_in_bytes (TREE_TYPE (exp));
/* If this is an incomplete type with size 0, then we can't put it
in sdata because it might be too big when completed. */
===================================================================
@@ -3377,7 +3377,7 @@ riscv_in_small_data_p (const_tree x)
return strcmp (sec, ".sdata") == 0 || strcmp (sec, ".sbss") == 0;
}
- return riscv_size_ok_for_small_data_p (int_size_in_bytes (TREE_TYPE (x)));
+ return riscv_size_ok_for_small_data_p (fixed_int_size_in_bytes (TREE_TYPE (x)));
}
/* Switch to the appropriate section for output of DECL. */
===================================================================
@@ -19442,7 +19442,7 @@ rs6000_elf_in_small_data_p (const_tree d
&& !rs6000_readonly_in_sdata)
return false;
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+ HOST_WIDE_INT size = fixed_int_size_in_bytes (TREE_TYPE (decl));
if (size > 0
&& size <= g_switch_value
===================================================================
@@ -2289,7 +2289,7 @@ rx_in_small_data (const_tree decl)
if (section)
return (strcmp (section, "D_2") == 0) || (strcmp (section, "B_2") == 0);
- size = int_size_in_bytes (TREE_TYPE (decl));
+ size = fixed_int_size_in_bytes (TREE_TYPE (decl));
return (size > 0) && (size <= rx_small_data_limit);
}
===================================================================
@@ -0,0 +1,67 @@
+/* PR target/92499 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+enum { size = 100 };
+
+struct flexible
+{
+ int length;
+ int data[];
+};
+
+struct inflexible
+{
+ int length;
+ int data[size];
+};
+
+static struct flexible flexible =
+ {
+ .data = { [size - 1] = 0, }
+ };
+
+static struct flexible flexible_nonzero =
+ {
+ .length = size,
+ .data = { [size - 1] = 0, }
+ };
+
+static struct inflexible inflexible =
+ {
+ .data = { [size - 1] = 0, }
+ };
+
+struct flexible *
+get_flexible (void)
+{
+ return &flexible;
+}
+
+struct flexible *
+get_flexible_nonzero (void)
+{
+ return &flexible_nonzero;
+}
+
+struct inflexible *
+get_inflexible (void)
+{
+ return &inflexible;
+}
+
+/* Check that variables containing flexible array elements are not placed
+ in small data. Almost all targets that support small data sections use
+ the canonical names for them. */
+/* { dg-final { scan-assembler-not "\\.sdata" } } */
+/* { dg-final { scan-assembler-not "\\.sbss" } } */
+/* { dg-final { scan-assembler-not "\\.section D_2" { target rx*-*-* } } } */
+/* { dg-final { scan-assembler-not "\\.section B_2" { target rx*-*-* } } } */
+
+/* Also check that GP-relative addressing is not used to reference any
+ of the variables, on targets that support that form of addressing for
+ small data. Since the assembler syntax varies on the targets that support
+ this, we need to list the targets individually. This list is not a
+ complete set. */
+/* { dg-final { scan-assembler-not "%gp_rel\(.*flexible.*\)" { target mips*-*-* } } } */
+/* { dg-final { scan-assembler-not "%gprel\(.*flexible.*\)" { target nios2*-*-* } } } */
===================================================================
@@ -3266,7 +3266,10 @@ size_in_bytes_loc (location_t loc, const
}
/* Return the size of TYPE (in bytes) as a wide integer
- or return -1 if the size can vary or is larger than an integer. */
+ or return -1 if the size can vary or is larger than an integer.
+ Note that this function returns the non-variable size for objects
+ containing flexible array members (like the C sizeof operator
+ does) instead of -1; see fixed_int_size_in_bytes below. */
HOST_WIDE_INT
int_size_in_bytes (const_tree type)
@@ -15000,6 +15003,54 @@ default_is_empty_record (const_tree type
return default_is_empty_type (TYPE_MAIN_VARIANT (type));
}
+/* Determine whether TYPE is a structure with a flexible array member,
+ or a union containing such a structure (possibly recursively). */
+
+bool
+flexible_array_type_p (const_tree type)
+{
+ tree x, last;
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ last = NULL_TREE;
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ if (TREE_CODE (x) == FIELD_DECL)
+ last = x;
+ if (last == NULL_TREE)
+ return false;
+ if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
+ && TYPE_SIZE (TREE_TYPE (last)) == NULL_TREE
+ && TYPE_DOMAIN (TREE_TYPE (last)) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (last))) == NULL_TREE)
+ return true;
+ return false;
+ case UNION_TYPE:
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ {
+ if (TREE_CODE (x) == FIELD_DECL
+ && flexible_array_type_p (TREE_TYPE (x)))
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+/* Like int_size_in_bytes, but also return -1 for flexible array
+ types, so that it only returns a positive value for types with a
+ fixed size. */
+
+HOST_WIDE_INT
+fixed_int_size_in_bytes (const_tree type)
+{
+ if (flexible_array_type_p (type))
+ return -1;
+ else
+ return int_size_in_bytes (type);
+}
+
/* Like int_size_in_bytes, but handle empty records specially. */
HOST_WIDE_INT
===================================================================
@@ -6077,6 +6077,8 @@ extern void gt_pch_nx (tree &, gt_pointe
extern bool nonnull_arg_p (const_tree);
extern bool default_is_empty_record (const_tree);
+extern bool flexible_array_type_p (const_tree);
+extern HOST_WIDE_INT fixed_int_size_in_bytes (const_tree);
extern HOST_WIDE_INT arg_int_size_in_bytes (const_tree);
extern tree arg_size_in_bytes (const_tree);
extern bool expr_type_first_operand_type_p (tree_code);