diff mbox

Make C11 _Alignof return least not greatest alignment for a type (PR c/52023)

Message ID Pine.LNX.4.64.1312042257070.21433@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers Dec. 4, 2013, 10:57 p.m. UTC
As noted in PR 52023, C11 _Alignof should return the *least* alignment
required for a type in any context - meaning that on 32-bit x86,
_Alignof (double) and _Alignof (long long) should be 4 not 8 because
of the reduced alignment inside structures.  (C++11 defines alignment
requirements differently to be the requirement for a complete object
of the given type, with an example involving virtual bases, so this
issue doesn't apply to C++11 alignof.)

As far as I can tell there isn't anything in the compiler to compute
this least alignment at present (it's the alignment you should be able
to assume for an arbitrary pointer to the type, for example - except
that actually trying to assume such alignments has been liable to run
into problems, both because people expect small integers cast to
pointer types to work as magic constants even if not properly aligned,
and because people widely assume that badly aligned pointers will
generally work on non-strict-alignment targets such as x86).  This
patch implements checks using BIGGEST_ALIGNMENT,
BIGGEST_FIELD_ALIGNMENT and then calling ADJUST_FIELD_ALIGN on a
synthetic FIELD_DECL - which, while not necessarily fully general,
will I believe give the correct results for all ADJUST_FIELD_ALIGN
definitions we have at present.  Similarly, the testcase inherently
needs to use __alignof__ (expression) or otherwise depend on things
outside C11 as C11 doesn't provide a way to examine how aligned a
given object is.

The change is only made for C11 _Alignof (and _Alignas which is
defined in terms of _Alignof), not for GNU __alignof__ to avoid
breaking compatibility with uses of __alignof__ to define
naturally-aligned fields on targets with this field-alignment
peculiarity.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu (and
spot-checked alignment values with -m32).  Applied to mainline.

c-family:
2013-12-04  Joseph Myers  <joseph@codesourcery.com>

	PR c/52023
	* c-common.c (c_sizeof_or_alignof_type): Add parameter min_alignof
	and check field alignment if set.
	* c-common.h (c_sizeof_or_alignof_type): Update prototype.
	(c_sizeof, c_alignof): Update calls to c_sizeof_or_alignof_type.

c:
2013-12-04  Joseph Myers  <joseph@codesourcery.com>

	PR c/52023
	* c-parser.c (c_parser_alignas_specifier): Use
	c_sizeof_or_alignof_type instead of c_alignof.
	(c_parser_alignof_expression): Likewise, with min_alignof
	parameter depending on alignof spelling used.

cp:
2013-12-04  Joseph Myers  <joseph@codesourcery.com>

	PR c/52023
	* typeck.c (cxx_sizeof_or_alignof_type): Update call to
	c_sizeof_or_alignof_type.

objc:
2013-12-04  Joseph Myers  <joseph@codesourcery.com>

	PR c/52023
	* objc-act.c (objc_synthesize_getter): Update calls to
	c_sizeof_or_alignof_type.

testsuite:
2013-12-04  Joseph Myers  <joseph@codesourcery.com>

	PR c/52023
	* gcc.dg/c11-align-6.c: New test.

Comments

Bin.Cheng Dec. 5, 2013, 9:16 a.m. UTC | #1
On Thu, Dec 5, 2013 at 6:57 AM, Joseph S. Myers <joseph@codesourcery.com> wrote:

> Index: c-family/c-common.c
> ===================================================================
> --- c-family/c-common.c (revision 205668)
> +++ c-family/c-common.c (working copy)
> @@ -4921,14 +4921,17 @@ c_common_get_alias_set (tree t)
>  }
>
>  /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
> -   the second parameter indicates which OPERATOR is being applied.
> +   the IS_SIZEOF parameter indicates which operator is being applied.
>     The COMPLAIN flag controls whether we should diagnose possibly
>     ill-formed constructs or not.  LOC is the location of the SIZEOF or
> -   TYPEOF operator.  */
> +   TYPEOF operator.  If MIN_ALIGNOF, the least alignment required for
> +   a type in any context should be returned, rather than the normal
> +   alignment for that type.  */
>
>  tree
>  c_sizeof_or_alignof_type (location_t loc,
> -                         tree type, bool is_sizeof, int complain)
> +                         tree type, bool is_sizeof, bool min_alignof,
> +                         int complain)
>  {
>    const char *op_name;
>    tree value = NULL;
> @@ -4994,6 +4997,22 @@ c_sizeof_or_alignof_type (location_t loc,
>         value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
>                                 size_int (TYPE_PRECISION (char_type_node)
>                                           / BITS_PER_UNIT));
> +      else if (min_alignof)
> +       {
> +         unsigned int align = TYPE_ALIGN (type);
> +         align = MIN (align, BIGGEST_ALIGNMENT);
> +#ifdef BIGGEST_FIELD_ALIGNMENT
> +         align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
> +#endif
> +         tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
> +                                  type);
> +         unsigned int field_align = align;
> +#ifdef ADJUST_FIELD_ALIGN
> +         field_align = ADJUST_FIELD_ALIGN (field, field_align);
> +#endif

Won't *field* be unused if ADJUST_FIELD_ALIGN not defined?

Thanks,
bin
Jan-Benedict Glaw Dec. 5, 2013, 9:20 a.m. UTC | #2
On Thu, 2013-12-05 17:16:53 +0800, Bin.Cheng <amker.cheng@gmail.com> wrote:
> On Thu, Dec 5, 2013 at 6:57 AM, Joseph S. Myers <joseph@codesourcery.com> wrote:
> > Index: c-family/c-common.c
> > ===================================================================
> > --- c-family/c-common.c (revision 205668)
> > +++ c-family/c-common.c (working copy)
> > @@ -4921,14 +4921,17 @@ c_common_get_alias_set (tree t)
> >  }
> >
> >  /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
> > -   the second parameter indicates which OPERATOR is being applied.
> > +   the IS_SIZEOF parameter indicates which operator is being applied.
> >     The COMPLAIN flag controls whether we should diagnose possibly
> >     ill-formed constructs or not.  LOC is the location of the SIZEOF or
> > -   TYPEOF operator.  */
> > +   TYPEOF operator.  If MIN_ALIGNOF, the least alignment required for
> > +   a type in any context should be returned, rather than the normal
> > +   alignment for that type.  */
> >
> >  tree
> >  c_sizeof_or_alignof_type (location_t loc,
> > -                         tree type, bool is_sizeof, int complain)
> > +                         tree type, bool is_sizeof, bool min_alignof,
> > +                         int complain)
> >  {
> >    const char *op_name;
> >    tree value = NULL;
> > @@ -4994,6 +4997,22 @@ c_sizeof_or_alignof_type (location_t loc,
> >         value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
> >                                 size_int (TYPE_PRECISION (char_type_node)
> >                                           / BITS_PER_UNIT));
> > +      else if (min_alignof)
> > +       {
> > +         unsigned int align = TYPE_ALIGN (type);
> > +         align = MIN (align, BIGGEST_ALIGNMENT);
> > +#ifdef BIGGEST_FIELD_ALIGNMENT
> > +         align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
> > +#endif
> > +         tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
> > +                                  type);
> > +         unsigned int field_align = align;
> > +#ifdef ADJUST_FIELD_ALIGN
> > +         field_align = ADJUST_FIELD_ALIGN (field, field_align);
> > +#endif
> 
> Won't *field* be unused if ADJUST_FIELD_ALIGN not defined?

You're right:

g++ -c  -DIN_GCC_FRONTEND -DIN_GCC_FRONTEND -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -Werror -fno-common  -DHAVE_CONFIG_H -I. -Ic-family -I../../../gcc/gcc -I../../../gcc/gcc/c-family -I../../../gcc/gcc/../include -I../../../gcc/gcc/../libcpp/include -I/opt/cfarm/mpc/include  -I../../../gcc/gcc/../libdecnumber -I../../../gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I../../../gcc/gcc/../libbacktrace    -o c-family/c-common.o -MT c-family/c-common.o -MMD -MP -MF c-family/.deps/c-common.TPo ../../../gcc/gcc/c-family/c-common.c
../../../gcc/gcc/c-family/c-common.c: In function ‘tree_node* c_sizeof_or_alignof_type(location_t, tree, bool, bool, int)’:
../../../gcc/gcc/c-family/c-common.c:5007:9: error: unused variable ‘field’ [-Werror=unused-variable]
    tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
         ^
cc1plus: all warnings being treated as errors
make[2]: *** [c-family/c-common.o] Error 1

This is m68k-elf, see eg.
http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=50551 ,
but other targets are also affected.

MfG, JBG
Andreas Schwab Dec. 5, 2013, 11:22 a.m. UTC | #3
"Joseph S. Myers" <joseph@codesourcery.com> writes:

> @@ -4994,6 +4997,22 @@ c_sizeof_or_alignof_type (location_t loc,
>  	value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
>  				size_int (TYPE_PRECISION (char_type_node)
>  					  / BITS_PER_UNIT));
> +      else if (min_alignof)
> +	{
> +	  unsigned int align = TYPE_ALIGN (type);
> +	  align = MIN (align, BIGGEST_ALIGNMENT);
> +#ifdef BIGGEST_FIELD_ALIGNMENT
> +	  align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
> +#endif
> +	  tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
> +				   type);
> +	  unsigned int field_align = align;
> +#ifdef ADJUST_FIELD_ALIGN
> +	  field_align = ADJUST_FIELD_ALIGN (field, field_align);
> +#endif
> +	  align = MIN (align, field_align);
> +	  value = size_int (align / BITS_PER_UNIT);
> +	}
>        else
>  	value = size_int (TYPE_ALIGN_UNIT (type));
>      }

../../gcc/c-family/c-common.c: In function ‘tree_node* c_sizeof_or_alignof_type(location_t, tree, bool, bool, int)’:
../../gcc/c-family/c-common.c:5007:9: error: unused variable ‘field’ [-Werror=unused-variable]
    tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
         ^

Andreas.
diff mbox

Patch

Index: objc/objc-act.c
===================================================================
--- objc/objc-act.c	(revision 205668)
+++ objc/objc-act.c	(working copy)
@@ -7273,6 +7273,7 @@  objc_synthesize_getter (tree klass, tree class_met
 	     the same type, there is no need to lookup the ivar.  */
 	  size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
 					      true /* is_sizeof */,
+					      false /* min_alignof */,
 					      false /* complain */);
 
 	  if (PROPERTY_NONATOMIC (property))
@@ -7474,6 +7475,7 @@  objc_synthesize_setter (tree klass, tree class_met
 	     the same type, there is no need to lookup the ivar.  */
 	  size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
 					      true /* is_sizeof */,
+					      false /* min_alignof */,
 					      false /* complain */);
 
 	  if (PROPERTY_NONATOMIC (property))
Index: c/c-parser.c
===================================================================
--- c/c-parser.c	(revision 205668)
+++ c/c-parser.c	(working copy)
@@ -3045,7 +3045,8 @@  c_parser_alignas_specifier (c_parser * parser)
     {
       struct c_type_name *type = c_parser_type_name (parser);
       if (type != NULL)
-	ret = c_alignof (loc, groktypename (type, NULL, NULL));
+	ret = c_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL),
+					false, true, 1);
     }
   else
     ret = c_parser_expr_no_commas (parser, NULL).value;
@@ -6446,11 +6447,12 @@  c_parser_alignof_expression (c_parser *parser)
   location_t loc = c_parser_peek_token (parser)->location;
   tree alignof_spelling = c_parser_peek_token (parser)->value;
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+  bool is_c11_alignof = strcmp (IDENTIFIER_POINTER (alignof_spelling),
+				"_Alignof") == 0;
   /* A diagnostic is not required for the use of this identifier in
      the implementation namespace; only diagnose it for the C11
      spelling because of existing code using the other spellings.  */
-  if (!flag_isoc11
-      && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0)
+  if (!flag_isoc11 && is_c11_alignof)
     {
       if (flag_isoc99)
 	pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %qE",
@@ -6494,7 +6496,9 @@  c_parser_alignof_expression (c_parser *parser)
       /* alignof ( type-name ).  */
       c_inhibit_evaluation_warnings--;
       in_alignof--;
-      ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL));
+      ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name,
+							       NULL, NULL),
+					    false, is_c11_alignof, 1);
       ret.original_code = ERROR_MARK;
       ret.original_type = NULL;
       return ret;
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 205668)
+++ cp/typeck.c	(working copy)
@@ -1562,7 +1562,7 @@  cxx_sizeof_or_alignof_type (tree type, enum tree_c
     }
 
   return c_sizeof_or_alignof_type (input_location, complete_type (type),
-				   op == SIZEOF_EXPR,
+				   op == SIZEOF_EXPR, false,
 				   complain);
 }
 
Index: c-family/c-common.c
===================================================================
--- c-family/c-common.c	(revision 205668)
+++ c-family/c-common.c	(working copy)
@@ -4921,14 +4921,17 @@  c_common_get_alias_set (tree t)
 }
 
 /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
-   the second parameter indicates which OPERATOR is being applied.
+   the IS_SIZEOF parameter indicates which operator is being applied.
    The COMPLAIN flag controls whether we should diagnose possibly
    ill-formed constructs or not.  LOC is the location of the SIZEOF or
-   TYPEOF operator.  */
+   TYPEOF operator.  If MIN_ALIGNOF, the least alignment required for
+   a type in any context should be returned, rather than the normal
+   alignment for that type.  */
 
 tree
 c_sizeof_or_alignof_type (location_t loc,
-			  tree type, bool is_sizeof, int complain)
+			  tree type, bool is_sizeof, bool min_alignof,
+			  int complain)
 {
   const char *op_name;
   tree value = NULL;
@@ -4994,6 +4997,22 @@  c_sizeof_or_alignof_type (location_t loc,
 	value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
 				size_int (TYPE_PRECISION (char_type_node)
 					  / BITS_PER_UNIT));
+      else if (min_alignof)
+	{
+	  unsigned int align = TYPE_ALIGN (type);
+	  align = MIN (align, BIGGEST_ALIGNMENT);
+#ifdef BIGGEST_FIELD_ALIGNMENT
+	  align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
+#endif
+	  tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
+				   type);
+	  unsigned int field_align = align;
+#ifdef ADJUST_FIELD_ALIGN
+	  field_align = ADJUST_FIELD_ALIGN (field, field_align);
+#endif
+	  align = MIN (align, field_align);
+	  value = size_int (align / BITS_PER_UNIT);
+	}
       else
 	value = size_int (TYPE_ALIGN_UNIT (type));
     }
Index: c-family/c-common.h
===================================================================
--- c-family/c-common.h	(revision 205668)
+++ c-family/c-common.h	(working copy)
@@ -759,7 +759,7 @@  extern tree c_wrap_maybe_const (tree, bool);
 extern tree c_save_expr (tree);
 extern tree c_common_truthvalue_conversion (location_t, tree);
 extern void c_apply_type_quals_to_decl (int, tree);
-extern tree c_sizeof_or_alignof_type (location_t, tree, bool, int);
+extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
 extern tree c_alignof_expr (location_t, tree);
 /* Print an error message for invalid operands to arith operation CODE.
    NOP_EXPR is used as a special case (see truthvalue_conversion).  */
@@ -792,8 +792,8 @@  extern bool keyword_is_type_qualifier (enum rid);
 extern bool keyword_is_decl_specifier (enum rid);
 extern bool cxx_fundamental_alignment_p (unsigned);
 
-#define c_sizeof(LOC, T)  c_sizeof_or_alignof_type (LOC, T, true, 1)
-#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1)
+#define c_sizeof(LOC, T)  c_sizeof_or_alignof_type (LOC, T, true, false, 1)
+#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1)
 
 /* Subroutine of build_binary_op, used for certain operations.  */
 extern tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise);
Index: testsuite/gcc.dg/c11-align-6.c
===================================================================
--- testsuite/gcc.dg/c11-align-6.c	(revision 0)
+++ testsuite/gcc.dg/c11-align-6.c	(revision 0)
@@ -0,0 +1,40 @@ 
+/* Test C11 _Alignof returning minimum alignment for a type.  PR
+   52023.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11" } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define CHECK_ALIGN(TYPE)			\
+  do						\
+    {						\
+      struct { char c; TYPE v; } x;		\
+      if (_Alignof (TYPE) > __alignof__ (x.v))	\
+	abort ();				\
+    }						\
+  while (0)
+
+int
+main (void)
+{
+  CHECK_ALIGN (_Bool);
+  CHECK_ALIGN (char);
+  CHECK_ALIGN (signed char);
+  CHECK_ALIGN (unsigned char);
+  CHECK_ALIGN (signed short);
+  CHECK_ALIGN (unsigned short);
+  CHECK_ALIGN (signed int);
+  CHECK_ALIGN (unsigned int);
+  CHECK_ALIGN (signed long);
+  CHECK_ALIGN (unsigned long);
+  CHECK_ALIGN (signed long long);
+  CHECK_ALIGN (unsigned long long);
+  CHECK_ALIGN (float);
+  CHECK_ALIGN (double);
+  CHECK_ALIGN (long double);
+  CHECK_ALIGN (_Complex float);
+  CHECK_ALIGN (_Complex double);
+  CHECK_ALIGN (_Complex long double);
+  exit (0);
+}