aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/flags.h8
-rw-r--r--gcc/invoke.texi31
-rw-r--r--gcc/stor-layout.c118
-rw-r--r--gcc/toplev.c14
5 files changed, 161 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 51af97f..2fbc072 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+Thu Dec 2 21:22:45 1999 Greg McGary <gkm@gnu.org>
+ Geoffrey Keating <geoffk@cygnus.com>
+
+ * flags.h (warn_padded, warn_packed): Add global var decls.
+ * toplev.c (warn_padded, warn_packed): Add global var defns.
+ (W_options): Add warnings `-Wpacked' and `-Wpadded'.
+ * stor-layout.c (layout_record): Add local variable `type'
+ to hold often-used TREE_TYPE (field). Add local variable
+ `unpacked_align' to hold alignment that would be in force
+ if no `packed' attribute were present. Warn if `packed' attribute
+ is unnecessary, or even harmful. Warn when gcc inserts padding
+ to satisfy alignment requirements of members. Use NULL_TREE
+ when checking whether var_size is set.
+ * invoke.texi: Document new flags.
+
1999-12-03 Nathan Sidwell <nathan@acm.org>
* frame.c (fde_split): Reimplement to avoid variable sized array.
diff --git a/gcc/flags.h b/gcc/flags.h
index 1cca481..c93784c 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -141,6 +141,14 @@ extern unsigned larger_than_size;
extern int warn_aggregate_return;
+/* Warn if packed attribute on struct is unnecessary and inefficient. */
+
+extern int warn_packed;
+
+/* Warn when gcc pads a structure to an alignment boundary. */
+
+extern int warn_padded;
+
/* Nonzero if generating code to do profiling. */
extern int profile_flag;
diff --git a/gcc/invoke.texi b/gcc/invoke.texi
index 7e76139..ea90467 100644
--- a/gcc/invoke.texi
+++ b/gcc/invoke.texi
@@ -128,7 +128,7 @@ in the following sections.
-Werror-implicit-function-declaration -Wfloat-equal -Winline
-Wlarger-than-@var{len} -Wlong-long
-Wmain -Wmissing-declarations -Wmissing-noreturn
--Wmultichar -Wno-import
+-Wmultichar -Wno-import -Wpacked -Wpadded
-Wparentheses -Wpointer-arith -Wredundant-decls
-Wreturn-type -Wshadow -Wsign-compare -Wswitch
-Wtrigraphs -Wundef -Wuninitialized -Wunknown-pragmas -Wunreachable-code
@@ -1430,7 +1430,7 @@ arguments, two, or three arguments of appropriate types.
Warn if a multicharacter constant (@samp{'FOOF'}) is used. Usually they
indicate a typo in the user's code, as they have implementation-defined
values, and should not be used in portable code.
-
+
@item -Wparentheses
Warn if parentheses are omitted in certain contexts, such
as when there is an assignment in a context where a truth value
@@ -1798,6 +1798,33 @@ be taken to manually verify functions actually do not ever return before
adding the @code{noreturn} attribute, otherwise subtle code generation
bugs could be introduced.
+@item -Wpacked
+Warn if a structure is given the packed attribute, but the packed
+attribute has no effect on the layout or size of the structure.
+Such structures may be mis-aligned for little benefit. For
+instance, in this code, the variable @code{f.x} in @code{struct bar}
+will be misaligned even though @code{struct bar} does not itself
+have the packed attribute:
+
+@smallexample
+@group
+struct foo @{
+ int x;
+ char a, b, c, d;
+@} __attribute__((packed));
+struct bar @{
+ char z;
+ struct foo f;
+@};
+@end group
+@end smallexample
+
+@item -Wpadded
+Warn if padding is included in a structure, either to align an element
+of the structure or to align the whole structure. Sometimes when this
+happens it is possible to rearrange the fields of the structure to
+reduce the padding and so make the structure smaller.
+
@item -Wredundant-decls
Warn if anything is declared more than once in the same scope, even in
cases where multiple declaration is valid and changes nothing.
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 1433e8b..1688fc3 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -347,6 +347,7 @@ layout_record (rec)
{
register tree field;
unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
+ unsigned unpacked_align = record_align;
/* These must be laid out *after* the record is. */
tree pending_statics = NULL_TREE;
/* Record size so far is CONST_SIZE + VAR_SIZE bits,
@@ -354,11 +355,12 @@ layout_record (rec)
and VAR_SIZE is a tree expression.
If VAR_SIZE is null, the size is just CONST_SIZE.
Naturally we try to avoid using VAR_SIZE. */
- register HOST_WIDE_INT const_size = 0;
+ register HOST_WIDE_INT const_size = 0;
register tree var_size = 0;
/* Once we start using VAR_SIZE, this is the maximum alignment
that we know VAR_SIZE has. */
register int var_align = BITS_PER_UNIT;
+ int packed_maybe_necessary = 0;
#ifdef STRUCTURE_SIZE_BOUNDARY
/* Packed structures don't need to have minimum size. */
@@ -370,6 +372,7 @@ layout_record (rec)
{
register int known_align = var_size ? var_align : const_size;
register int desired_align = 0;
+ tree type = TREE_TYPE (field);
/* If FIELD is static, then treat it like a separate variable,
not really like a structure field.
@@ -408,12 +411,10 @@ layout_record (rec)
Otherwise, the alignment of the field within the record
is meaningless. */
-#ifndef PCC_BITFIELD_TYPE_MATTERS
- record_align = MAX (record_align, desired_align);
-#else
- if (PCC_BITFIELD_TYPE_MATTERS && TREE_TYPE (field) != error_mark_node
+#ifdef PCC_BITFIELD_TYPE_MATTERS
+ if (PCC_BITFIELD_TYPE_MATTERS && type != error_mark_node
&& DECL_BIT_FIELD_TYPE (field)
- && ! integer_zerop (TYPE_SIZE (TREE_TYPE (field))))
+ && ! integer_zerop (TYPE_SIZE (type)))
{
/* For these machines, a zero-length field does not
affect the alignment of the structure as a whole.
@@ -422,23 +423,47 @@ layout_record (rec)
if (! integer_zerop (DECL_SIZE (field)))
record_align = MAX ((int)record_align, desired_align);
else if (! DECL_PACKED (field))
- desired_align = TYPE_ALIGN (TREE_TYPE (field));
+ desired_align = TYPE_ALIGN (type);
/* A named bit field of declared type `int'
forces the entire structure to have `int' alignment. */
if (DECL_NAME (field) != 0)
{
- int type_align = TYPE_ALIGN (TREE_TYPE (field));
+ int type_align = TYPE_ALIGN (type);
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
else if (DECL_PACKED (field))
type_align = MIN (type_align, BITS_PER_UNIT);
- record_align = MAX ((int)record_align, type_align);
+ record_align = MAX ((int) record_align, type_align);
+ if (warn_packed)
+ unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
}
}
else
- record_align = MAX ((int)record_align, desired_align);
#endif
+ {
+ record_align = MAX ((int) record_align, desired_align);
+ if (warn_packed)
+ unpacked_align = MAX (unpacked_align, TYPE_ALIGN (type));
+ }
+
+ if (warn_packed && DECL_PACKED (field))
+ {
+ if (const_size % TYPE_ALIGN (type) == 0
+ || (var_align % TYPE_ALIGN (type) == 0
+ && var_size != NULL_TREE))
+ {
+ if (TYPE_ALIGN (type) > desired_align)
+ {
+ if (STRICT_ALIGNMENT)
+ warning_with_decl (field, "packed attribute causes inefficient alignment for `%s'");
+ else
+ warning_with_decl (field, "packed attribute is unnecessary for `%s'");
+ }
+ }
+ else
+ packed_maybe_necessary = 1;
+ }
/* Does this field automatically have alignment it needs
by virtue of the fields that precede it and the record's
@@ -446,12 +471,15 @@ layout_record (rec)
if (const_size % desired_align != 0
|| (var_align % desired_align != 0
- && var_size != 0))
+ && var_size != NULL_TREE))
{
/* No, we need to skip space before this field.
Bump the cumulative size to multiple of field alignment. */
- if (var_size == 0
+ if (warn_padded)
+ warning_with_decl (field, "padding struct to align `%s'");
+
+ if (var_size == NULL_TREE
|| var_align % desired_align == 0)
const_size
= CEIL (const_size, desired_align) * desired_align;
@@ -469,13 +497,13 @@ layout_record (rec)
#ifdef PCC_BITFIELD_TYPE_MATTERS
if (PCC_BITFIELD_TYPE_MATTERS
&& TREE_CODE (field) == FIELD_DECL
- && TREE_TYPE (field) != error_mark_node
+ && type != error_mark_node
&& DECL_BIT_FIELD_TYPE (field)
&& !DECL_PACKED (field)
&& maximum_field_alignment == 0
&& !integer_zerop (DECL_SIZE (field)))
{
- int type_align = TYPE_ALIGN (TREE_TYPE (field));
+ int type_align = TYPE_ALIGN (type);
register tree dsize = DECL_SIZE (field);
int field_size = TREE_INT_CST_LOW (dsize);
@@ -493,12 +521,12 @@ layout_record (rec)
#ifdef BITFIELD_NBYTES_LIMITED
if (BITFIELD_NBYTES_LIMITED
&& TREE_CODE (field) == FIELD_DECL
- && TREE_TYPE (field) != error_mark_node
+ && type != error_mark_node
&& DECL_BIT_FIELD_TYPE (field)
&& !DECL_PACKED (field)
&& !integer_zerop (DECL_SIZE (field)))
{
- int type_align = TYPE_ALIGN (TREE_TYPE (field));
+ int type_align = TYPE_ALIGN (type);
register tree dsize = DECL_SIZE (field);
int field_size = TREE_INT_CST_LOW (dsize);
@@ -556,7 +584,7 @@ layout_record (rec)
const_size += TREE_INT_CST_LOW (dsize);
else
{
- if (var_size == 0)
+ if (var_size == NULL_TREE)
var_size = dsize;
else
var_size = size_binop (PLUS_EXPR, var_size, dsize);
@@ -568,7 +596,7 @@ layout_record (rec)
as one expression and store in the record type.
Round it up to a multiple of the record's alignment. */
- if (var_size == 0)
+ if (var_size == NULL_TREE)
{
TYPE_SIZE (rec) = bitsize_int (const_size, 0L);
}
@@ -591,13 +619,59 @@ layout_record (rec)
the size of TYPE_BINFO to make sure that BINFO_SIZE is available. */
if (TYPE_BINFO (rec) && TREE_VEC_LENGTH (TYPE_BINFO (rec)) > 6)
TYPE_BINFO_SIZE (rec) = TYPE_SIZE (rec);
-
+
+ {
+ tree unpadded_size = TYPE_SIZE (rec);
#ifdef ROUND_TYPE_SIZE
- TYPE_SIZE (rec) = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), TYPE_ALIGN (rec));
+ TYPE_SIZE (rec) = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), TYPE_ALIGN (rec));
#else
- /* Round the size up to be a multiple of the required alignment */
- TYPE_SIZE (rec) = round_up (TYPE_SIZE (rec), TYPE_ALIGN (rec));
+ /* Round the size up to be a multiple of the required alignment */
+ TYPE_SIZE (rec) = round_up (TYPE_SIZE (rec), TYPE_ALIGN (rec));
#endif
+ if (warn_padded && var_size == NULL_TREE
+ && simple_cst_equal (unpadded_size, TYPE_SIZE (rec)) == 0)
+ warning ("padding struct size to alignment boundary");
+ }
+
+ if (warn_packed && TYPE_PACKED (rec) && !packed_maybe_necessary
+ && var_size == NULL_TREE)
+ {
+ tree unpacked_size;
+ TYPE_PACKED (rec) = 0;
+#ifdef ROUND_TYPE_ALIGN
+ unpacked_align = ROUND_TYPE_ALIGN (rec, TYPE_ALIGN (rec), unpacked_align);
+#else
+ unpacked_align = MAX (TYPE_ALIGN (rec), unpacked_align);
+#endif
+#ifdef ROUND_TYPE_SIZE
+ unpacked_size = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), unpacked_align);
+#else
+ unpacked_size = round_up (TYPE_SIZE (rec), unpacked_align);
+#endif
+ if (simple_cst_equal (unpacked_size, TYPE_SIZE (rec)))
+ {
+ if (TYPE_NAME (rec))
+ {
+ char *name;
+ if (TREE_CODE (TYPE_NAME (rec)) == IDENTIFIER_NODE)
+ name = IDENTIFIER_POINTER (TYPE_NAME (rec));
+ else
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (rec)));
+ if (STRICT_ALIGNMENT)
+ warning ("packed attribute causes inefficient alignment for `%s'", name);
+ else
+ warning ("packed attribute is unnecessary for `%s'", name);
+ }
+ else
+ {
+ if (STRICT_ALIGNMENT)
+ warning ("packed attribute causes inefficient alignment");
+ else
+ warning ("packed attribute is unnecessary");
+ }
+ }
+ TYPE_PACKED (rec) = 1;
+ }
return pending_statics;
}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 0678915..70ea2a1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1258,6 +1258,14 @@ int warn_inline;
int warn_aggregate_return;
+/* Warn if packed attribute on struct is unnecessary and inefficient. */
+
+int warn_packed;
+
+/* Warn when gcc pads a structure to an alignment boundary. */
+
+int warn_padded;
+
/* Likewise for -W. */
lang_independent_options W_options[] =
@@ -1276,7 +1284,11 @@ lang_independent_options W_options[] =
{"uninitialized", &warn_uninitialized, 1,
"Warn about unitialized automatic variables"},
{"inline", &warn_inline, 1,
- "Warn when an inlined function cannot be inlined"}
+ "Warn when an inlined function cannot be inlined"},
+ {"packed", &warn_packed, 1,
+ "Warn when the packed attribute has no effect on struct layout"},
+ {"padded", &warn_padded, 1,
+ "Warn when padding is required to align struct members"}
};
/* Output files for assembler code (real compiler output)