diff mbox

[C11-atomic] Miscellaneous fixes 3/n

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

Commit Message

Joseph Myers Oct. 24, 2013, 12:53 a.m. UTC
I've committed this patch to C11-atomic branch with further
miscellaneous fixes.  The testcases are expanded to cover everything I
found in going through the language parts of C11 for atomics issues
that can be covered through compile rather than execute tests.
Corresponding compiler fixes are made for issues found (as well as
some other cleanups).

I think the next steps will be checking the C front-end code for
particular constructs likely to need updating for atomics, in case any
relevant places have been missed so far, adding execution tests, and
adding support for the special floating-point handling in compound
assignment.

c:
2013-10-24  Joseph Myers  <joseph@codesourcery.com>

	* c-decl.c (validate_proto_after_old_defn): Do not remove atomic
	qualifiers when compating types.
	(start_decl): Use c_type_promotes_to when promoting argument
	types.
	(check_bitfield_type_and_width): Don't check for atomic qualifiers
	here.
	(grokdeclarator): Check for atomic qualifiers on bit-fields here.
	*store_parm_decls_oldstyle): Do not remove atomic qualifiers when
	comparing types.  Use c_type_promotes_to when promoting argument
	types.
	(finish_function) Use c_type_promotes_to when promoting argument
	types.
	* c-parser.c (c_parser_typeof_specifier): Use TYPE_ATOMIC instead
	of testing TYPE_QUAL_ATOMIC in TYPE_QUALS.
	* c-typeck.c (c_type_promotes_to): Promote atomic types to
	corresponding atomic types.
	(type_lists_compatible_p, find_anonymous_field_with_type)
	(convert_to_anonymous_field, convert_for_assignment): Do not
	remove atomic qualifiers when comparing types.

testsuite:
2013-10-24  Joseph Myers  <joseph@codesourcery.com>

	* gcc.dg/c11-atomic-1.c, gcc.dg/c11-atomic-3.c: Add more tests.
diff mbox

Patch

Index: gcc/testsuite/gcc.dg/c11-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-1.c	(revision 203840)
+++ gcc/testsuite/gcc.dg/c11-atomic-1.c	(working copy)
@@ -179,3 +179,79 @@  func7 (void)
      expressions with other pointer types.  */
   (void) (r ? xaip1 : (r ? xaip1 : xvp1));
 }
+
+/* Pointer += and -= integer is valid.  */
+void
+func8 (void)
+{
+  b += 1;
+  b -= 2ULL;
+  ap += 3;
+}
+
+/* Various other cases of simple assignment are valid (some already
+   tested above).  */
+void
+func9 (void)
+{
+  ap = 0;
+  ap = (void *) 0;
+  xvp1 = atp1;
+  atp1 = xvp1;
+}
+
+/* Test compatibility of function types in cases where _Atomic matches
+   (see c11-atomic-3.c for corresponding cases where it doesn't
+   match).  */
+void fc0a (int const);
+void fc0a (int);
+void fc0b (int _Atomic);
+void fc0b (int _Atomic);
+void fc1a (int);
+void
+fc1a (x)
+     volatile int x;
+{
+}
+void fc1b (_Atomic int);
+void
+fc1b (x)
+     volatile _Atomic int x;
+{
+}
+void
+fc2a (x)
+     const int x;
+{
+}
+void fc2a (int); /* { dg-warning "follows non-prototype" } */
+void
+fc2b (x)
+     _Atomic int x;
+{
+}
+void fc2b (_Atomic int); /* { dg-warning "follows non-prototype" } */
+void fc3a (int);
+void
+fc3a (x)
+     volatile short x;
+{
+}
+void fc3b (_Atomic int);
+void
+fc3b (x)
+     _Atomic short x;
+{
+}
+void
+fc4a (x)
+     const short x;
+{
+}
+void fc4a (int); /* { dg-warning "follows non-prototype" } */
+void
+fc4b (x)
+     _Atomic short x;
+{
+}
+void fc4b (_Atomic int); /* { dg-warning "follows non-prototype" } */
Index: gcc/testsuite/gcc.dg/c11-atomic-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-3.c	(revision 203840)
+++ gcc/testsuite/gcc.dg/c11-atomic-3.c	(working copy)
@@ -64,3 +64,94 @@  func2 (void)
   (void) (r ? pai : pav); /* { dg-error "pointer type mismatch" } */
   (void) (r ? pav : pai); /* { dg-error "pointer type mismatch" } */
 }
+
+/* Likewise for pointer assignment.  */
+void
+func3 (void)
+{
+  pai = pi; /* { dg-error "incompatible pointer type" } */
+  pi = pai; /* { dg-error "incompatible pointer type" } */
+  pav = pai; /* { dg-error "incompatible pointer type" } */
+  pai = pav; /* { dg-error "incompatible pointer type" } */
+}
+
+/* Cases that are invalid for normal assignments are just as invalid
+   (and should not ICE) when the LHS is atomic.  */
+void
+func4 (void)
+{
+  as = acf; /* { dg-error "incompatible types" } */
+  apv = as; /* { dg-error "incompatible types" } */
+  as += 1; /* { dg-error "invalid operands" } */
+  apv -= 1; /* { dg-error "pointer of type" } */
+  apv *= 1; /* { dg-error "invalid operands" } */
+  apv /= 1; /* { dg-error "invalid operands" } */
+  apv %= 1; /* { dg-error "invalid operands" } */
+  apv <<= 1; /* { dg-error "invalid operands" } */
+  apv >>= 1; /* { dg-error "invalid operands" } */
+  apv &= 1; /* { dg-error "invalid operands" } */
+  apv ^= 1; /* { dg-error "invalid operands" } */
+  apv |= 1; /* { dg-error "invalid operands" } */
+}
+
+/* We don't allow atomic bit-fields in GCC (implementation-defined
+   whether they are permitted).  */
+struct abf
+{
+  _Atomic int i : 1; /* { dg-error "atomic type" } */
+  _Atomic int : 0; /* { dg-error "atomic type" } */
+};
+
+/* _Atomic (type-name) may not use a name for an array, function,
+   qualified or atomic type.  */
+_Atomic (int [2]) v0; /* { dg-error "array type" } */
+_Atomic (void (void)) v1; /* { dg-error "function type" } */
+_Atomic (_Atomic int) v2; /* { dg-error "applied to a qualified type" } */
+_Atomic (const int) v3; /* { dg-error "applied to a qualified type" } */
+_Atomic (volatile int) v4; /* { dg-error "applied to a qualified type" } */
+_Atomic (int *restrict) v5; /* { dg-error "applied to a qualified type" } */
+
+/* _Atomic, used as a qualifier, may not be applied to a function or
+   array type.  */
+typedef int arraytype[2];
+typedef void functiontype (void);
+_Atomic arraytype v6; /* { dg-error "array type" } */
+_Atomic arraytype *v7; /* { dg-error "array type" } */
+typedef _Atomic arraytype v8; /* { dg-error "array type" } */
+int v9 = sizeof (_Atomic arraytype); /* { dg-error "array type" } */
+void v10 (_Atomic arraytype parm); /* { dg-error "array type" } */
+struct v11 { _Atomic arraytype f; }; /* { dg-error "array type" } */
+_Atomic functiontype v12; /* { dg-error "function type" } */
+_Atomic functiontype *v13; /* { dg-error "function type" } */
+typedef _Atomic functiontype *v14; /* { dg-error "function type" } */
+void v15 (_Atomic functiontype parm); /* { dg-error "function type" } */
+
+/* Function parameters, when function types are required to be
+   compatible, may not differ in the presence of _Atomic.  See
+   c11-atomic-1.c for corresponding tests where _Atomic matches.  */
+void fc0 (int _Atomic); /* { dg-message "previous declaration" } */
+void fc0 (int); /* { dg-error "conflicting types" } */
+void fc1 (int); /* { dg-message "prototype declaration" } */
+void
+fc1 (x)
+     _Atomic int x; /* { dg-error "match prototype" } */
+{
+}
+void
+fc2 (x) /* { dg-message "previous definition" } */
+     _Atomic int x;
+{
+}
+void fc2 (int); /* { dg-error "incompatible type" } */
+void fc3 (int); /* { dg-message "prototype declaration" } */
+void
+fc3 (x)
+     _Atomic short x; /* { dg-error "match prototype" } */
+{
+}
+void
+fc4 (x) /* { dg-message "previous definition" } */
+     _Atomic short x;
+{
+}
+void fc4 (int); /* { dg-error "incompatible type" } */
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 203840)
+++ gcc/c/c-parser.c	(working copy)
@@ -2837,8 +2837,7 @@  c_parser_typeof_specifier (c_parser *parser)
 	 all qualifiers should be removed; const can be an issue for
 	 more macros using typeof than just the <stdatomic.h>
 	 ones.)  */
-      if (ret.spec != error_mark_node
-	  && (TYPE_QUALS (ret.spec) & TYPE_QUAL_ATOMIC))
+      if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec))
 	ret.spec = c_build_qualified_type (ret.spec,
 					   (TYPE_QUALS (ret.spec)
 					    & ~(TYPE_QUAL_ATOMIC
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 203840)
+++ gcc/c/c-typeck.c	(working copy)
@@ -265,18 +265,25 @@  c_incomplete_type_error (const_tree value, const_t
 tree
 c_type_promotes_to (tree type)
 {
+  tree ret = NULL_TREE;
+
   if (TYPE_MAIN_VARIANT (type) == float_type_node)
-    return double_type_node;
-
-  if (c_promoting_integer_type_p (type))
+    ret = double_type_node;
+  else if (c_promoting_integer_type_p (type))
     {
       /* Preserve unsignedness if not really getting any wider.  */
       if (TYPE_UNSIGNED (type)
 	  && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
-	return unsigned_type_node;
-      return integer_type_node;
+	ret = unsigned_type_node;
+      else
+	ret = integer_type_node;
     }
 
+  if (ret != NULL_TREE)
+    return (TYPE_ATOMIC (type)
+	    ? c_build_qualified_type (ret, TYPE_QUAL_ATOMIC)
+	    : ret);
+
   return type;
 }
 
@@ -1637,9 +1644,15 @@  type_lists_compatible_p (const_tree args1, const_t
       mv1 = a1 = TREE_VALUE (args1);
       mv2 = a2 = TREE_VALUE (args2);
       if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
-	mv1 = TYPE_MAIN_VARIANT (mv1);
+	mv1 = (TYPE_ATOMIC (mv1)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv1),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mv1));
       if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
-	mv2 = TYPE_MAIN_VARIANT (mv2);
+	mv2 = (TYPE_ATOMIC (mv2)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv2),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mv2));
       /* A null pointer instead of a type
 	 means there is supposed to be an argument
 	 but nothing is specified about what type it has.
@@ -1682,7 +1695,10 @@  type_lists_compatible_p (const_tree args1, const_t
 		  tree mv3 = TREE_TYPE (memb);
 		  if (mv3 && mv3 != error_mark_node
 		      && TREE_CODE (mv3) != ARRAY_TYPE)
-		    mv3 = TYPE_MAIN_VARIANT (mv3);
+		    mv3 = (TYPE_ATOMIC (mv3)
+			   ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3),
+						     TYPE_QUAL_ATOMIC)
+			   : TYPE_MAIN_VARIANT (mv3));
 		  if (comptypes_internal (mv3, mv2, enum_and_int_p,
 					  different_types_p))
 		    break;
@@ -1704,7 +1720,10 @@  type_lists_compatible_p (const_tree args1, const_t
 		  tree mv3 = TREE_TYPE (memb);
 		  if (mv3 && mv3 != error_mark_node
 		      && TREE_CODE (mv3) != ARRAY_TYPE)
-		    mv3 = TYPE_MAIN_VARIANT (mv3);
+		    mv3 = (TYPE_ATOMIC (mv3)
+			   ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3),
+						     TYPE_QUAL_ATOMIC)
+			   : TYPE_MAIN_VARIANT (mv3));
 		  if (comptypes_internal (mv3, mv1, enum_and_int_p,
 					  different_types_p))
 		    break;
@@ -5154,8 +5173,12 @@  find_anonymous_field_with_type (tree struct_type,
        field != NULL_TREE;
        field = TREE_CHAIN (field))
     {
+      tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field))
+			? c_build_qualified_type (TREE_TYPE (field),
+						  TYPE_QUAL_ATOMIC)
+			: TYPE_MAIN_VARIANT (TREE_TYPE (field)));
       if (DECL_NAME (field) == NULL
-	  && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+	  && comptypes (type, fieldtype))
 	{
 	  if (found)
 	    return false;
@@ -5193,7 +5216,10 @@  convert_to_anonymous_field (location_t location, t
 	      || TREE_CODE (rhs_struct_type) == UNION_TYPE);
 
   gcc_assert (POINTER_TYPE_P (type));
-  lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+  lhs_main_type = (TYPE_ATOMIC (TREE_TYPE (type))
+		   ? c_build_qualified_type (TREE_TYPE (type),
+					     TYPE_QUAL_ATOMIC)
+		   : TYPE_MAIN_VARIANT (TREE_TYPE (type)));
 
   found_field = NULL_TREE;
   found_sub_field = false;
@@ -5205,7 +5231,11 @@  convert_to_anonymous_field (location_t location, t
 	  || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE
 	      && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE))
 	continue;
-      if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+      tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field))
+			? c_build_qualified_type (TREE_TYPE (field),
+						  TYPE_QUAL_ATOMIC)
+			: TYPE_MAIN_VARIANT (TREE_TYPE (field)));
+      if (comptypes (lhs_main_type, fieldtype))
 	{
 	  if (found_field != NULL_TREE)
 	    return NULL_TREE;
@@ -5495,17 +5525,18 @@  convert_for_assignment (location_t location, tree
 		 and vice versa; otherwise, targets must be the same.
 		 Meanwhile, the lhs target must have all the qualifiers of
 		 the rhs.  */
-	      if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+	      if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
+		  || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
 		  || comp_target_types (location, memb_type, rhstype))
 		{
+		  int lquals = TYPE_QUALS (ttl) & ~TYPE_QUAL_ATOMIC;
+		  int rquals = TYPE_QUALS (ttr) & ~TYPE_QUAL_ATOMIC;
 		  /* If this type won't generate any warnings, use it.  */
-		  if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
+		  if (lquals == rquals
 		      || ((TREE_CODE (ttr) == FUNCTION_TYPE
 			   && TREE_CODE (ttl) == FUNCTION_TYPE)
-			  ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
-			     == TYPE_QUALS (ttr))
-			  : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
-			     == TYPE_QUALS (ttl))))
+			  ? ((lquals | rquals) == rquals)
+			  : ((lquals | rquals) == lquals)))
 		    break;
 
 		  /* Keep looking for a better type, but remember this one.  */
@@ -5596,9 +5627,15 @@  convert_for_assignment (location_t location, tree
       addr_space_t asr;
 
       if (TREE_CODE (mvl) != ARRAY_TYPE)
-	mvl = TYPE_MAIN_VARIANT (mvl);
+	mvl = (TYPE_ATOMIC (mvl)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mvl));
       if (TREE_CODE (mvr) != ARRAY_TYPE)
-	mvr = TYPE_MAIN_VARIANT (mvr);
+	mvr = (TYPE_ATOMIC (mvr)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mvr));
       /* Opaque pointers are treated like void pointers.  */
       is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
 
@@ -5699,13 +5736,15 @@  convert_for_assignment (location_t location, tree
       /* Any non-function converts to a [const][volatile] void *
 	 and vice versa; otherwise, targets must be the same.
 	 Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
-      if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+      if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
+	  || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
 	  || (target_cmp = comp_target_types (location, type, rhstype))
 	  || is_opaque_pointer
 	  || ((c_common_unsigned_type (mvl)
 	       == c_common_unsigned_type (mvr))
-	      && c_common_signed_type (mvl)
-		 == c_common_signed_type (mvr)))
+	      && (c_common_signed_type (mvl)
+		  == c_common_signed_type (mvr))
+	      && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr)))
 	{
 	  if (pedantic
 	      && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 203840)
+++ gcc/c/c-decl.c	(working copy)
@@ -1579,8 +1579,14 @@  validate_proto_after_old_defn (tree newdecl, tree
       if (oldargtype == error_mark_node || newargtype == error_mark_node)
 	return false;
 
-      oldargtype = TYPE_MAIN_VARIANT (oldargtype);
-      newargtype = TYPE_MAIN_VARIANT (newargtype);
+      oldargtype = (TYPE_ATOMIC (oldargtype)
+		    ? c_build_qualified_type (TYPE_MAIN_VARIANT (oldargtype),
+					      TYPE_QUAL_ATOMIC)
+		    : TYPE_MAIN_VARIANT (oldargtype));
+      newargtype = (TYPE_ATOMIC (newargtype)
+		    ? c_build_qualified_type (TYPE_MAIN_VARIANT (newargtype),
+					      TYPE_QUAL_ATOMIC)
+		    : TYPE_MAIN_VARIANT (newargtype));
 
       if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype))
 	break;
@@ -4138,7 +4144,7 @@  start_decl (struct c_declarator *declarator, struc
 	      tree type = TREE_TYPE (args);
 	      if (type && INTEGRAL_TYPE_P (type)
 		  && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-		DECL_ARG_TYPE (args) = integer_type_node;
+		DECL_ARG_TYPE (args) = c_type_promotes_to (type);
 	    }
 	}
     }
@@ -4772,15 +4778,6 @@  check_bitfield_type_and_width (tree *type, tree *w
       error ("bit-field %qs has invalid type", name);
       *type = unsigned_type_node;
     }
-  /* C11 makes it implementation-defined (6.7.2.1#5) whether atomic
-     types are permitted for bit-fields; we have no code to make
-     bit-field accesses atomic, so disallow them.  */
-  if (TYPE_QUALS (*type) & TYPE_QUAL_ATOMIC)
-    {
-      error ("bit-field %qs has atomic type", name);
-      *type = c_build_qualified_type (*type,
-				      TYPE_QUALS (*type) & ~TYPE_QUAL_ATOMIC);
-    }
 
   type_mv = TYPE_MAIN_VARIANT (*type);
   if (!in_system_header
@@ -5801,7 +5798,20 @@  grokdeclarator (const struct c_declarator *declara
 
   /* Check the type and width of a bit-field.  */
   if (bitfield)
-    check_bitfield_type_and_width (&type, width, name);
+    {
+      check_bitfield_type_and_width (&type, width, name);
+      /* C11 makes it implementation-defined (6.7.2.1#5) whether
+	 atomic types are permitted for bit-fields; we have no code to
+	 make bit-field accesses atomic, so disallow them.  */
+      if (type_quals & TYPE_QUAL_ATOMIC)
+	{
+	  if (name)
+	    error ("bit-field %qE has atomic type", name);
+	  else
+	    error ("bit-field has atomic type");
+	  type_quals &= ~TYPE_QUAL_ATOMIC;
+	}
+    }
 
   /* Reject invalid uses of _Alignas.  */
   if (declspecs->alignas_p)
@@ -8225,11 +8235,15 @@  store_parm_decls_oldstyle (tree fndecl, const stru
 	     type for parameters declared with qualified type.  */
 	  if (TREE_TYPE (parm) != error_mark_node
 	      && TREE_TYPE (type) != error_mark_node
-	      && !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
-			     TYPE_MAIN_VARIANT (TREE_VALUE (type))))
+	      && ((TYPE_ATOMIC (DECL_ARG_TYPE (parm))
+		   != TYPE_ATOMIC (TREE_VALUE (type)))
+		  || !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
+				 TYPE_MAIN_VARIANT (TREE_VALUE (type)))))
 	    {
-	      if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
-		  == TYPE_MAIN_VARIANT (TREE_VALUE (type)))
+	      if ((TYPE_ATOMIC (DECL_ARG_TYPE (parm))
+		   == TYPE_ATOMIC (TREE_VALUE (type)))
+		  && (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
+		      == TYPE_MAIN_VARIANT (TREE_VALUE (type))))
 		{
 		  /* Adjust argument to match prototype.  E.g. a previous
 		     `int foo(float);' prototype causes
@@ -8242,7 +8256,8 @@  store_parm_decls_oldstyle (tree fndecl, const stru
 		      && INTEGRAL_TYPE_P (TREE_TYPE (parm))
 		      && TYPE_PRECISION (TREE_TYPE (parm))
 		      < TYPE_PRECISION (integer_type_node))
-		    DECL_ARG_TYPE (parm) = integer_type_node;
+		    DECL_ARG_TYPE (parm)
+		      = c_type_promotes_to (TREE_TYPE (parm));
 
 		  /* ??? Is it possible to get here with a
 		     built-in prototype or will it always have
@@ -8406,7 +8421,7 @@  finish_function (void)
 	  tree type = TREE_TYPE (args);
 	  if (INTEGRAL_TYPE_P (type)
 	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-	    DECL_ARG_TYPE (args) = integer_type_node;
+	    DECL_ARG_TYPE (args) = c_type_promotes_to (type);
 	}
     }