[C11-atomic] Miscellaneous fixes 2/n

Joseph S. Myers joseph@codesourcery.com
Sat Oct 19 05:23:00 GMT 2013


I've applied this patch to C11-atomic branch with more miscellaneous
fixes.  stdatomic.h had more typo fixes, and a substantive definition
of kill_dependency that I hope is right (it seems to match libstdc++,
and I think it matches the standard).  Atomic increment and decrement
are made to go through the same paths as atomic compound assignment,
which are adjusted to allow for postincrement/postdecrement
(preincrement/predecrement are exactly the same as += 1 and -= 1).
Atomic compound assignment logic is fixed to make warning and
conversion code, that expected build_modify_expr to have built the
(LHS OP RHS) expression by a certain point, handle atomic operations
that build that expression later; conversions are moved into
build_atomic_assign as needed.  Various code is fixed to avoid
treating _Atomic as a qualifier where that isn't permitted by ISO C.
Testcases are added based on going through parts of C11 for _Atomic
requirements, but I haven't yet finished going through all of the
language parts of C11 so there will be more additions to these
testcases and associated front-end changes yet to come.  The tests did
show up problems with the detection of _Atomic applied to array types
wrongly giving errors for _Atomic applied to the elements of an array,
so that code was fixed accordingly (subject to more validation, since
the relevant negative tests aren't added yet).  Given the compiler
changes, all the new tests pass (on x86_64-unknown-linux-gnu).

(Once I've finished going through the language parts of C11, adding
associated compilation testcases and making the front end handle
_Atomic accordingly, I then propose to check the uses of various
constructs in the front end that indicate places that might need to
handle _Atomic specially, before adding execution tests and the
special handling of floating-point compound assignments.)

2013-10-19  Joseph Myers  <joseph@codesourcery.com>

	* ginclude/stdatomic.h: Add missing semicolons to typedefs.
	(kill_dependency): Use temporary variable.

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

	* c-decl.c (grokdeclarator): Check earlier for _Atomic applied to
	an array type.
	* c-parser.c (c_parser_declspecs): Adjust comment about
	Objective-C atomics cases.
	* c-typeck.c (qualify_type): Don't add _Atomic qualifiers from
	second argument.
	(comp_target_types): Do not allow _Atomic mismatches.
	(build_unary_op): Use build_atomic_assign for atomic increment and
	decrement.
	(build_conditional_expr): Do not treat _Atomic void as a qualified
	version of void.
	(build_modify_expr): Adjust warnings and conversions for case of
	atomic compound assignment not having had rhs updated for compound
	operation.
	(build_binary_op): Do not treat _Atomic void as a qualified
	version of void.
	(build_atomic_assign): Add argument RETURN_OLD_P.  All callers
	changed.  Correct type used to store original rhs.  Use
	convert_for_assignment on computed rhs value.

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

	* gcc.dg/c90-atomic-1.c, gcc.dg/c99-atomic-1.c,
	gcc.dg/c11-atomic-1.c, gcc.dg/c11-atomic-2.c,
	gcc.dg/c11-atomic-3.c: New tests.

Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 203801)
+++ gcc/c/c-decl.c	(working copy)
@@ -5107,6 +5107,13 @@ grokdeclarator (const struct c_declarator *declara
 		| (atomicp ? TYPE_QUAL_ATOMIC : 0)
 		| ENCODE_QUAL_ADDR_SPACE (address_space));
 
+  /* Applying the _Atomic qualifier to an array type (through the use
+     of typedefs or typeof) must be detected here.  If the qualifier
+     is introduced later, any appearance of applying it to an array is
+     actually applying it to an element of that array.  */
+  if (atomicp && TREE_CODE (type) == ARRAY_TYPE)
+    error_at (loc, "%<_Atomic%>-qualified array type");
+
   /* Warn about storage classes that are invalid for certain
      kinds of declarations (parameters, typenames, etc.).  */
 
@@ -5679,13 +5686,6 @@ grokdeclarator (const struct c_declarator *declara
 			  "%<_Atomic%>-qualified function type");
 		type_quals &= ~TYPE_QUAL_ATOMIC;
 	      }
-	    else if ((type_quals & TYPE_QUAL_ATOMIC)
-		&& TREE_CODE (type) == ARRAY_TYPE)
-	      {
-		error_at (loc,
-			  "%<_Atomic%>-qualified array type");
-		type_quals &= ~TYPE_QUAL_ATOMIC;
-	      }
 	    else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
 		     && type_quals)
 	      pedwarn (loc, OPT_Wpedantic,
@@ -5871,13 +5871,6 @@ grokdeclarator (const struct c_declarator *declara
 		    "%<_Atomic%>-qualified function type");
 	  type_quals &= ~TYPE_QUAL_ATOMIC;
 	}
-      else if ((type_quals & TYPE_QUAL_ATOMIC)
-	       && TREE_CODE (type) == ARRAY_TYPE)
-	{
-	  error_at (loc,
-		    "%<_Atomic%>-qualified array type");
-	  type_quals &= ~TYPE_QUAL_ATOMIC;
-	}
       else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
 	       && type_quals)
 	pedwarn (loc, OPT_Wpedantic,
@@ -5931,13 +5924,6 @@ grokdeclarator (const struct c_declarator *declara
 		    "%<_Atomic%>-qualified function type");
 	  type_quals &= ~TYPE_QUAL_ATOMIC;
 	}
-      else if ((type_quals & TYPE_QUAL_ATOMIC)
-	       && TREE_CODE (type) == ARRAY_TYPE)
-	{
-	  error_at (loc,
-		    "%<_Atomic%>-qualified array type");
-	  type_quals &= ~TYPE_QUAL_ATOMIC;
-	}
       else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
 	       && type_quals)
 	pedwarn (loc, OPT_Wpedantic,
@@ -5987,12 +5973,6 @@ grokdeclarator (const struct c_declarator *declara
 
 	if (TREE_CODE (type) == ARRAY_TYPE)
 	  {
-	    if (type_quals & TYPE_QUAL_ATOMIC)
-	      {
-		error_at (loc,
-			  "%<_Atomic%>-qualified array type");
-		type_quals &= ~TYPE_QUAL_ATOMIC;
-	      }
 	    /* Transfer const-ness of array into that of type pointed to.  */
 	    type = TREE_TYPE (type);
 	    if (type_quals)
@@ -6072,12 +6052,6 @@ grokdeclarator (const struct c_declarator *declara
 	      error_at (loc, "unnamed field has incomplete type");
 	    type = error_mark_node;
 	  }
-	if (TREE_CODE (type) == ARRAY_TYPE && (type_quals & TYPE_QUAL_ATOMIC))
-	  {
-	    error_at (loc,
-		      "%<_Atomic%>-qualified function type");
-	    type_quals &= ~TYPE_QUAL_ATOMIC;
-	  }
 	type = c_build_qualified_type (type, type_quals);
 	decl = build_decl (declarator->id_loc,
 			   FIELD_DECL, declarator->u.id, type);
@@ -6193,12 +6167,6 @@ grokdeclarator (const struct c_declarator *declara
 	/* An uninitialized decl with `extern' is a reference.  */
 	int extern_ref = !initialized && storage_class == csc_extern;
 
-	if (TREE_CODE (type) == ARRAY_TYPE && type_quals & TYPE_QUAL_ATOMIC)
-	  {
-	    error_at (loc,
-		      "%<_Atomic%>-qualified array type");
-	    type_quals &= ~TYPE_QUAL_ATOMIC;
-	  }
 	type = c_build_qualified_type (type, type_quals);
 
 	/* C99 6.2.2p7: It is invalid (compile-time undefined
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 203801)
+++ gcc/c/c-parser.c	(working copy)
@@ -2185,7 +2185,9 @@ c_parser_declspecs (c_parser *parser, struct c_dec
 	  /* C parser handling of Objective-C constructs needs
 	     checking for correct lvalue-to-rvalue conversions, and
 	     the code in build_modify_expr handling various
-	     Objective-C cases also needs updating.  */
+	     Objective-C cases, and that in build_unary_op handling
+	     Objective-C cases for increment / decrement, also needs
+	     updating.  */
 	  if (c_dialect_objc ())
 	    sorry ("%<_Atomic%> in Objective-C");
 	  /* C parser handling of OpenMP constructs needs checking for
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 203801)
+++ gcc/c/c-typeck.c	(working copy)
@@ -104,7 +104,7 @@ static void readonly_warning (tree, enum lvalue_us
 static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
 static int comptypes_internal (const_tree, const_tree, bool *, bool *);
-static tree build_atomic_assign (location_t, tree, enum tree_code, tree);
+static tree build_atomic_assign (location_t, tree, enum tree_code, tree, bool);
 
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
@@ -327,7 +327,7 @@ qualify_type (tree type, tree like)
 
   return c_build_qualified_type (type,
 				 TYPE_QUALS_NO_ADDR_SPACE (type)
-				 | TYPE_QUALS_NO_ADDR_SPACE (like)
+				 | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
 				 | ENCODE_QUAL_ADDR_SPACE (as_common));
 }
 
@@ -1214,9 +1214,13 @@ comp_target_types (location_t location, tree ttl,
   /* Do not lose qualifiers on element types of array types that are
      pointer targets by taking their TYPE_MAIN_VARIANT.  */
   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));
   enum_and_int_p = false;
   val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
 
@@ -3713,6 +3717,9 @@ build_unary_op (location_t location,
       /* Ensure the argument is fully folded inside any SAVE_EXPR.  */
       arg = c_fully_fold (arg, false, NULL);
 
+      bool atomic_op;
+      atomic_op = really_atomic_lvalue (arg);
+
       /* Increment or decrement the real part of the value,
 	 and don't change the imaginary part.  */
       if (typecode == COMPLEX_TYPE)
@@ -3722,21 +3729,25 @@ build_unary_op (location_t location,
 	  pedwarn (location, OPT_Wpedantic,
 		   "ISO C does not support %<++%> and %<--%> on complex types");
 
-	  arg = stabilize_reference (arg);
-	  real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
-	  imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
-	  real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
-	  if (real == error_mark_node || imag == error_mark_node)
-	    return error_mark_node;
-	  ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
-			real, imag);
-	  goto return_build_unary_op;
+	  if (!atomic_op)
+	    {
+	      arg = stabilize_reference (arg);
+	      real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
+	      imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
+	      real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
+	      if (real == error_mark_node || imag == error_mark_node)
+		return error_mark_node;
+	      ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
+			    real, imag);
+	      goto return_build_unary_op;
+	    }
 	}
 
       /* Report invalid types.  */
 
       if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
-	  && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
+	  && typecode != INTEGER_TYPE && typecode != REAL_TYPE
+	  && typecode != COMPLEX_TYPE)
 	{
 	  if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
 	    error_at (location, "wrong type argument to increment");
@@ -3827,6 +3838,24 @@ build_unary_op (location_t location,
 			      || code == POSTINCREMENT_EXPR)
 			     ? lv_increment : lv_decrement));
 
+	/* If the argument is atomic, use the special code sequences for
+	   atomic compound assignment.  */
+	if (atomic_op)
+	  {
+	    arg = stabilize_reference (arg);
+	    ret = build_atomic_assign (location, arg,
+				       ((code == PREINCREMENT_EXPR
+					 || code == POSTINCREMENT_EXPR)
+					? PLUS_EXPR
+					: MINUS_EXPR),
+				       (FRACT_MODE_P (TYPE_MODE (argtype))
+					? inc
+					: integer_one_node),
+				       (code == POSTINCREMENT_EXPR
+					|| code == POSTDECREMENT_EXPR));
+	    goto return_build_unary_op;
+	  }
+
 	if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
 	  val = boolean_increment (code, arg);
 	else
@@ -4337,7 +4366,8 @@ build_conditional_expr (location_t colon_loc, tree
 		    "used in conditional expression");
 	  return error_mark_node;
 	}
-      else if (VOID_TYPE_P (TREE_TYPE (type1)))
+      else if (VOID_TYPE_P (TREE_TYPE (type1))
+	       && !TYPE_ATOMIC (TREE_TYPE (type1)))
 	{
 	  if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
 	    pedwarn (colon_loc, OPT_Wpedantic,
@@ -4346,7 +4376,8 @@ build_conditional_expr (location_t colon_loc, tree
 	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
 							  TREE_TYPE (type2)));
 	}
-      else if (VOID_TYPE_P (TREE_TYPE (type2)))
+      else if (VOID_TYPE_P (TREE_TYPE (type2))
+	       && !TYPE_ATOMIC (TREE_TYPE (type2)))
 	{
 	  if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
 	    pedwarn (colon_loc, OPT_Wpedantic,
@@ -5037,7 +5068,8 @@ build_modify_expr (location_t location, tree lhs,
 			? rhs_origtype
 			: TREE_TYPE (rhs));
       if (checktype != error_mark_node
-	  && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype))
+	  && (TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype)
+	      || (is_atomic_op && modifycode != NOP_EXPR)))
 	warning_at (location, OPT_Wc___compat,
 		    "enum conversion in assignment is invalid in C++");
     }
@@ -5057,14 +5089,18 @@ build_modify_expr (location_t location, tree lhs,
      restore any excess precision information, for the sake of
      conversion warnings.  */
 
-  npc = null_pointer_constant_p (newrhs);
-  newrhs = c_fully_fold (newrhs, false, NULL);
-  if (rhs_semantic_type)
-    newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
-  newrhs = convert_for_assignment (location, lhstype, newrhs, rhs_origtype,
-				   ic_assign, npc, NULL_TREE, NULL_TREE, 0);
-  if (TREE_CODE (newrhs) == ERROR_MARK)
-    return error_mark_node;
+  if (!(is_atomic_op && modifycode != NOP_EXPR))
+    {
+      npc = null_pointer_constant_p (newrhs);
+      newrhs = c_fully_fold (newrhs, false, NULL);
+      if (rhs_semantic_type)
+	newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+      newrhs = convert_for_assignment (location, lhstype, newrhs, rhs_origtype,
+				       ic_assign, npc, NULL_TREE,
+				       NULL_TREE, 0);
+      if (TREE_CODE (newrhs) == ERROR_MARK)
+	return error_mark_node;
+    }
 
   /* Emit ObjC write barrier, if necessary.  */
   if (c_dialect_objc () && flag_objc_gc)
@@ -5080,7 +5116,7 @@ build_modify_expr (location_t location, tree lhs,
   /* Scan operands.  */
 
   if (is_atomic_op)
-    result = build_atomic_assign (location, lhs, modifycode, newrhs);
+    result = build_atomic_assign (location, lhs, modifycode, newrhs, false);
   else
     {
       result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
@@ -10185,13 +10221,13 @@ build_binary_op (location_t location, enum tree_co
 			"disjoint address spaces");
 	      return error_mark_node;
 	    }
-	  else if (VOID_TYPE_P (tt0))
+	  else if (VOID_TYPE_P (tt0) && !TYPE_ATOMIC (tt0))
 	    {
 	      if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
 		pedwarn (location, OPT_Wpedantic, "ISO C forbids "
 			 "comparison of %<void *%> with function pointer");
 	    }
-	  else if (VOID_TYPE_P (tt1))
+	  else if (VOID_TYPE_P (tt1) && !TYPE_ATOMIC (tt1))
 	    {
 	      if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
 		pedwarn (location, OPT_Wpedantic, "ISO C forbids "
@@ -11179,16 +11215,18 @@ done:
 
 */
 
-/* Build an atomic assignment at LOC, expanding into the proper sequence to
-   store LHS MODIFYCODE= RHS.  Return a value representing the result of 
-   the operation.  */
-tree
+/* Build an atomic assignment at LOC, expanding into the proper
+   sequence to store LHS MODIFYCODE= RHS.  Return a value representing
+   the result of the operation, unless RETURN_OLD_P in which case
+   return the old value of LHS (this is only for postincrement and
+   postdecrement).  */
+static tree
 build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode,
-		     tree rhs)
+		     tree rhs, bool return_old_p)
 {
   tree fndecl, func_call;
   vec<tree, va_gc> *params;
-  tree val, nonatomic_type, newval, newval_addr;
+  tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr;
   tree old, old_addr;
   tree compound_stmt;
   tree stmt, goto_stmt;
@@ -11197,9 +11235,13 @@ build_atomic_assign (location_t loc, tree lhs, enu
   tree lhs_type = TREE_TYPE (lhs);
   tree lhs_addr = build_unary_op (loc, ADDR_EXPR, lhs, 0);
   tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
+  tree rhs_type = TREE_TYPE (rhs);
 
   gcc_assert (TYPE_ATOMIC (lhs_type));
 
+  if (return_old_p)
+    gcc_assert (modifycode == PLUS_EXPR || modifycode == MINUS_EXPR);
+
   /* Allocate enough vector items for a compare_exchange.  */
   vec_alloc (params, 6);
 
@@ -11209,10 +11251,11 @@ build_atomic_assign (location_t loc, tree lhs, enu
 
   /* Remove the qualifiers for the rest of the expressions and create
      the VAL temp variable to hold the RHS.  */
-  nonatomic_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED);
-  val = create_tmp_var (nonatomic_type, NULL);
+  nonatomic_lhs_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED);
+  nonatomic_rhs_type = build_qualified_type (rhs_type, TYPE_UNQUALIFIED);
+  val = create_tmp_var (nonatomic_rhs_type, NULL);
   TREE_ADDRESSABLE (val) = 1;
-  rhs = build2 (MODIFY_EXPR, nonatomic_type, val, rhs);
+  rhs = build2 (MODIFY_EXPR, nonatomic_rhs_type, val, rhs);
   SET_EXPR_LOCATION (rhs, loc);
   add_stmt (rhs);
 
@@ -11234,15 +11277,15 @@ build_atomic_assign (location_t loc, tree lhs, enu
 
       /* VAL is the value which was stored, return a COMPOUND_STMT of
 	 the statement and that value.  */
-      return build2 (COMPOUND_EXPR, nonatomic_type, compound_stmt, val);
+      return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, val);
     }
 
   /* Create the variables and labels required for the op= form.  */
-  old = create_tmp_var (nonatomic_type, NULL);
+  old = create_tmp_var (nonatomic_lhs_type, NULL);
   old_addr = build_unary_op (loc, ADDR_EXPR, old, 0);
   TREE_ADDRESSABLE (val) = 1;
 
-  newval = create_tmp_var (nonatomic_type, NULL);
+  newval = create_tmp_var (nonatomic_lhs_type, NULL);
   newval_addr = build_unary_op (loc, ADDR_EXPR, newval, 0);
   TREE_ADDRESSABLE (newval) = 1;
 
@@ -11268,9 +11311,15 @@ build_atomic_assign (location_t loc, tree lhs, enu
 
   /* newval = old + val;  */
   rhs = build_binary_op (loc, modifycode, old, val, 1);
-  rhs = build2 (MODIFY_EXPR, nonatomic_type, newval, rhs);
-  SET_EXPR_LOCATION (rhs, loc);
-  add_stmt (rhs);
+  rhs = convert_for_assignment (loc, nonatomic_lhs_type, rhs, NULL_TREE,
+				ic_assign, false, NULL_TREE,
+				NULL_TREE, 0);
+  if (rhs != error_mark_node)
+    {
+      rhs = build2 (MODIFY_EXPR, nonatomic_lhs_type, newval, rhs);
+      SET_EXPR_LOCATION (rhs, loc);
+      add_stmt (rhs);
+    }
 
   /* if (__atomic_compare_exchange (addr, &old, &new, false, SEQ_CST, SEQ_CST))
        goto done;  */
@@ -11305,7 +11354,8 @@ build_atomic_assign (location_t loc, tree lhs, enu
   /* Finish the compound statement.  */
   compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
 
-  /* Newval is the value that was successfully stored, return a
-     COMPOUND_EXPR of the statement and that value.  */
-  return build2 (COMPOUND_EXPR, nonatomic_type, compound_stmt, newval);
+  /* NEWVAL is the value that was successfully stored, return a
+     COMPOUND_EXPR of the statement and the appropriate value.  */
+  return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt,
+		 return_old_p ? old : newval);
 }
Index: gcc/ginclude/stdatomic.h
===================================================================
--- gcc/ginclude/stdatomic.h	(revision 203801)
+++ gcc/ginclude/stdatomic.h	(working copy)
@@ -50,38 +50,39 @@ typedef _Atomic long           atomic_long;
 typedef _Atomic unsigned long  atomic_ulong;
 typedef _Atomic long long      atomic_llong;
 typedef _Atomic unsigned long long atomic_ullong;
-typedef _Atomic __CHAR16_TYPE__ atomic_char16_t
-typedef _Atomic __CHAR32_TYPE__ atomic_char32_t
-typedef _Atomic __WCHAR_TYPE__  atomic_wchar_t
-typedef _Atomic __INT_LEAST8_TYPE__   atomic_int_least8_t
-typedef _Atomic __UINT_LEAST8_TYPE__  atomic_uint_least8_t
-typedef _Atomic __INT_LEAST16_TYPE__  atomic_int_least16_t
-typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t
-typedef _Atomic __INT_LEAST32_TYPE__  atomic_int_least32_t
-typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t
-typedef _Atomic __INT_LEAST64_TYPE__  atomic_int_least64_t
-typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t
-typedef _Atomic __INT_FAST8_TYPE__    atomic_int_fast8_t
-typedef _Atomic __UINT_FAST8_TYPE__   atomic_uint_fast8_t
-typedef _Atomic __INT_FAST16_TYPE__   atomic_int_fast16_t
-typedef _Atomic __UINT_FAST16_TYPE__  atomic_uint_fast16_t
-typedef _Atomic __INT_FAST32_TYPE__   atomic_int_fast32_t
-typedef _Atomic __UINT_FAST32_TYPE__  atomic_uint_fast32_t
-typedef _Atomic __INT_FAST64_TYPE__   atomic_int_fast64_t
-typedef _Atomic __UINT_FAST64_TYPE__  atomic_uint_fast64_t
-typedef _Atomic __INTPTR_TYPE__       atomic_intptr_t
-typedef _Atomic __UINTPTR_TYPE__      atomic_uintptr_t
-typedef _Atomic __SIZE_TYPE__         atomic_size_t
-typedef _Atomic __PTRDIFF_TYPE__      atomic_ptrdiff_t
-typedef _Atomic __INTMAX_TYPE__       atomic_intmax_t
-typedef _Atomic __UINTMAX_TYPE__      atomic_uintmax_t        
+typedef _Atomic __CHAR16_TYPE__ atomic_char16_t;
+typedef _Atomic __CHAR32_TYPE__ atomic_char32_t;
+typedef _Atomic __WCHAR_TYPE__  atomic_wchar_t;
+typedef _Atomic __INT_LEAST8_TYPE__   atomic_int_least8_t;
+typedef _Atomic __UINT_LEAST8_TYPE__  atomic_uint_least8_t;
+typedef _Atomic __INT_LEAST16_TYPE__  atomic_int_least16_t;
+typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t;
+typedef _Atomic __INT_LEAST32_TYPE__  atomic_int_least32_t;
+typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t;
+typedef _Atomic __INT_LEAST64_TYPE__  atomic_int_least64_t;
+typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t;
+typedef _Atomic __INT_FAST8_TYPE__    atomic_int_fast8_t;
+typedef _Atomic __UINT_FAST8_TYPE__   atomic_uint_fast8_t;
+typedef _Atomic __INT_FAST16_TYPE__   atomic_int_fast16_t;
+typedef _Atomic __UINT_FAST16_TYPE__  atomic_uint_fast16_t;
+typedef _Atomic __INT_FAST32_TYPE__   atomic_int_fast32_t;
+typedef _Atomic __UINT_FAST32_TYPE__  atomic_uint_fast32_t;
+typedef _Atomic __INT_FAST64_TYPE__   atomic_int_fast64_t;
+typedef _Atomic __UINT_FAST64_TYPE__  atomic_uint_fast64_t;
+typedef _Atomic __INTPTR_TYPE__       atomic_intptr_t;
+typedef _Atomic __UINTPTR_TYPE__      atomic_uintptr_t;
+typedef _Atomic __SIZE_TYPE__         atomic_size_t;
+typedef _Atomic __PTRDIFF_TYPE__      atomic_ptrdiff_t;
+typedef _Atomic __INTMAX_TYPE__       atomic_intmax_t;
+typedef _Atomic __UINTMAX_TYPE__      atomic_uintmax_t;        
 
 
 #define ATOMIC_VAR_INIT(VALUE)	(VALUE)
 #define atomic_init(PTR, VAL)	{ *(PTR) = (VAL); }
 
-/* TODO actually kill the dependency.  */
-#define kill_dependency(Y)	(Y)
+#define kill_dependency(Y)	__extension__ ({ \
+  __typeof__ (Y) __tmp = (Y); \
+  __tmp; })
 
 #define atomic_thread_fence 	__atomic_thread_fence
 #define atomic_signal_fence 	__atomic_signal_fence 
Index: gcc/testsuite/gcc.dg/c11-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c11-atomic-1.c	(revision 0)
@@ -0,0 +1,181 @@
+/* Test for _Atomic in C11.  Test of valid code.  See c11-atomic-2.c
+   for more exhaustive tests of assignment cases.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+/* The use of _Atomic as a qualifier, and of _Atomic (type-name), give
+   the same type.  */
+extern _Atomic int a;
+extern _Atomic (int) a;
+extern int *_Atomic b;
+extern _Atomic (int *) b;
+extern void f (int [_Atomic]);
+extern void f (int *_Atomic);
+
+/* _Atomic may be applied to arbitrary types, with or without other
+   qualifiers, and assignments may be made as with non-atomic
+   types.  Structure and union elements may be atomic.  */
+_Atomic int ai1, ai2;
+int i1;
+volatile _Atomic long double ald1;
+const _Atomic long double ald2;
+long double ld1;
+_Atomic _Complex double acd1, acd2;
+_Complex double d1;
+_Atomic volatile _Bool ab1;
+int *p;
+int *_Atomic restrict ap;
+struct s { char c[1000]; };
+_Atomic struct s as1;
+struct s s1;
+struct t { _Atomic int i; };
+_Atomic struct t at1;
+_Atomic struct t *atp1;
+struct t t1;
+union u { char c[1000]; };
+_Atomic union u au1;
+union u u1;
+union v { _Atomic int i; };
+_Atomic union v av1;
+union v v1;
+
+void
+func (_Atomic volatile long al1)
+{
+  ai1 = ai2;
+  ai1 = i1;
+  i1 = ai2;
+  ai1 = ald2;
+  ald1 = d1;
+  ld1 = acd2;
+  acd1 += ab1;
+  acd2 /= ai1;
+  p = ap;
+  ap = p;
+  ab1 = p;
+  as1 = s1;
+  s1 = as1;
+  at1 = t1;
+  t1 = at1;
+  /* It's unclear whether the undefined behavior (6.5.2.3#5) for
+     accessing elements of atomic structures and unions is at
+     translation or execution time; presume here that it's at
+     execution time.  */
+  t1.i = at1.i;
+  at1.i = t1.i;
+  atp1->i = t1.i;
+  au1 = u1;
+  u1 = au1;
+  av1 = v1;
+  v1 = av1;
+  v1.i = av1.i;
+  av1.i = v1.i;
+  /* _Atomic is valid on register variables, even if not particularly
+     useful.  */
+  register _Atomic volatile int ra1 = 1, ra2 = 2;
+  ra1 = ra2;
+  ra2 = ra1;
+  /* And on parameters.  */
+  al1 = ra1;
+  ra2 = al1;
+}
+
+/* A function may return an atomic type.  */
+_Atomic int
+func2 (int i)
+{
+  return i;
+}
+
+/* Casts may specify atomic type.  */
+int
+func3 (int i)
+{
+  return func2 ((_Atomic long) i);
+}
+
+/* The _Atomic void type is valid.  */
+_Atomic void *avp;
+
+/* An array of atomic elements is valid (the elements being atomic,
+   not the array).  */
+_Atomic int aa[10];
+int
+func4 (void)
+{
+  return aa[2];
+}
+
+/* Increment and decrement are valid for atomic types when they are
+   valid for non-atomic types.  */
+void
+func5 (void)
+{
+  ald1++;
+  ald1--;
+  ++ald1;
+  --ald1;
+  ai1++;
+  ai1--;
+  ++ai1;
+  --ai1;
+  ab1++;
+  ab1--;
+  ++ab1;
+  --ab1;
+  ap++;
+  ap--;
+  ++ap;
+  --ap;
+}
+
+/* Compound literals may have atomic type.  */
+_Atomic int *aiclp = &(_Atomic int) { 1 };
+
+/* Test unary & and *.  */
+void
+func6 (void)
+{
+  int i = *aiclp;
+  _Atomic int *p = &ai2;
+}
+
+/* Casts to atomic type are valid (although the _Atomic has little
+   effect because the result is an rvalue).  */
+int i2 = (_Atomic int) 1.0;
+
+/* For pointer subtraction and comparisons, _Atomic does not count as
+   a qualifier.  Likewise for conditional expressions.  */
+_Atomic int *xaip1;
+volatile _Atomic int *xaip2;
+void *xvp1;
+
+void
+func7 (void)
+{
+  int r;
+  r = xaip1 - xaip2;
+  r = xaip1 < xaip2;
+  r = xaip1 > xaip2;
+  r = xaip1 <= xaip2;
+  r = xaip1 >= xaip2;
+  r = xaip1 == xaip2;
+  r = xaip1 != xaip2;
+  r = xaip1 == xvp1;
+  r = xaip1 != xvp1;
+  r = xvp1 == xaip1;
+  r = xvp1 != xaip1;
+  r = xaip1 == 0;
+  r = ((void *) 0) == xaip2;
+  (void) (r ? xaip1 : xaip2);
+  (void) (r ? xvp1 : xaip2);
+  (void) (r ? xaip2 : xvp1);
+  (void) (r ? xaip1 : 0);
+  (void) (r ? 0 : xaip1);
+  /* The result of a conditional expression between a pointer to
+     qualified or unqualified (but not atomic) void, and a pointer to
+     an atomic type, is a pointer to appropriately qualified, not
+     atomic, void.  As such, it is valid to use further in conditional
+     expressions with other pointer types.  */
+  (void) (r ? xaip1 : (r ? xaip1 : xvp1));
+}
Index: gcc/testsuite/gcc.dg/c11-atomic-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c11-atomic-2.c	(revision 0)
@@ -0,0 +1,165 @@
+/* Test for _Atomic in C11.  Test of valid assignment cases for
+   arithmetic types.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+#define TEST_ASSIGN(TYPE1, OP, TYPE2)		\
+  do						\
+    {						\
+      _Atomic TYPE1 a = 0;			\
+      TYPE2 b = 0;				\
+      _Atomic TYPE2 c = 0;			\
+      a OP b;					\
+      a OP c;					\
+    }						\
+  while (0)
+
+#define TEST_ASSIGN_ARITHR(TYPE1, OP)			\
+  do							\
+    {							\
+      TEST_ASSIGN (TYPE1, OP, _Bool);			\
+      TEST_ASSIGN (TYPE1, OP, char);			\
+      TEST_ASSIGN (TYPE1, OP, signed char);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned char);		\
+      TEST_ASSIGN (TYPE1, OP, signed short);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned short);		\
+      TEST_ASSIGN (TYPE1, OP, signed int);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned int);		\
+      TEST_ASSIGN (TYPE1, OP, signed long);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned long);		\
+      TEST_ASSIGN (TYPE1, OP, signed long long);	\
+      TEST_ASSIGN (TYPE1, OP, unsigned long long);	\
+      TEST_ASSIGN (TYPE1, OP, float);			\
+      TEST_ASSIGN (TYPE1, OP, double);			\
+      TEST_ASSIGN (TYPE1, OP, long double);		\
+      TEST_ASSIGN (TYPE1, OP, _Complex float);		\
+      TEST_ASSIGN (TYPE1, OP, _Complex double);		\
+      TEST_ASSIGN (TYPE1, OP, _Complex long double);	\
+    }							\
+  while (0)
+
+#define TEST_ASSIGN_ARITHBOTH(OP)			\
+  do							\
+    {							\
+      TEST_ASSIGN_ARITHR (_Bool, OP);			\
+      TEST_ASSIGN_ARITHR (char, OP);			\
+      TEST_ASSIGN_ARITHR (signed char, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned char, OP);		\
+      TEST_ASSIGN_ARITHR (signed short, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned short, OP);		\
+      TEST_ASSIGN_ARITHR (signed int, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned int, OP);		\
+      TEST_ASSIGN_ARITHR (signed long, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned long, OP);		\
+      TEST_ASSIGN_ARITHR (signed long long, OP);	\
+      TEST_ASSIGN_ARITHR (unsigned long long, OP);	\
+      TEST_ASSIGN_ARITHR (float, OP);			\
+      TEST_ASSIGN_ARITHR (double, OP);			\
+      TEST_ASSIGN_ARITHR (long double, OP);		\
+      TEST_ASSIGN_ARITHR (_Complex float, OP);		\
+      TEST_ASSIGN_ARITHR (_Complex double, OP);		\
+      TEST_ASSIGN_ARITHR (_Complex long double, OP);	\
+    }							\
+  while (0)
+
+#define TEST_ASSIGN_INTR(TYPE1, OP)			\
+  do							\
+    {							\
+      TEST_ASSIGN (TYPE1, OP, _Bool);			\
+      TEST_ASSIGN (TYPE1, OP, char);			\
+      TEST_ASSIGN (TYPE1, OP, signed char);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned char);		\
+      TEST_ASSIGN (TYPE1, OP, signed short);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned short);		\
+      TEST_ASSIGN (TYPE1, OP, signed int);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned int);		\
+      TEST_ASSIGN (TYPE1, OP, signed long);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned long);		\
+      TEST_ASSIGN (TYPE1, OP, signed long long);	\
+      TEST_ASSIGN (TYPE1, OP, unsigned long long);	\
+    }							\
+  while (0)
+
+#define TEST_ASSIGN_INTBOTH(OP)				\
+  do							\
+    {							\
+      TEST_ASSIGN_INTR (_Bool, OP);			\
+      TEST_ASSIGN_INTR (char, OP);			\
+      TEST_ASSIGN_INTR (signed char, OP);		\
+      TEST_ASSIGN_INTR (unsigned char, OP);		\
+      TEST_ASSIGN_INTR (signed short, OP);		\
+      TEST_ASSIGN_INTR (unsigned short, OP);		\
+      TEST_ASSIGN_INTR (signed int, OP);		\
+      TEST_ASSIGN_INTR (unsigned int, OP);		\
+      TEST_ASSIGN_INTR (signed long, OP);		\
+      TEST_ASSIGN_INTR (unsigned long, OP);		\
+      TEST_ASSIGN_INTR (signed long long, OP);		\
+      TEST_ASSIGN_INTR (unsigned long long, OP);	\
+    }							\
+  while (0)
+
+void
+test_simple (void)
+{
+  TEST_ASSIGN_ARITHBOTH (=);
+}
+
+void
+test_mult (void)
+{
+  TEST_ASSIGN_ARITHBOTH (*=);
+}
+
+void
+test_div (void)
+{
+  TEST_ASSIGN_ARITHBOTH (/=);
+}
+
+void
+test_mod (void)
+{
+  TEST_ASSIGN_INTBOTH (%=);
+}
+
+void
+test_plus (void)
+{
+  TEST_ASSIGN_ARITHBOTH (+=);
+}
+
+void
+test_minus (void)
+{
+  TEST_ASSIGN_ARITHBOTH (-=);
+}
+
+void
+test_lshift (void)
+{
+  TEST_ASSIGN_INTBOTH (<<=);
+}
+
+void
+test_rshift (void)
+{
+  TEST_ASSIGN_INTBOTH (>>=);
+}
+
+void
+test_and (void)
+{
+  TEST_ASSIGN_INTBOTH (&=);
+}
+
+void
+test_xor (void)
+{
+  TEST_ASSIGN_INTBOTH (^=);
+}
+
+void
+test_or (void)
+{
+  TEST_ASSIGN_INTBOTH (|=);
+}
Index: gcc/testsuite/gcc.dg/c99-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-atomic-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-atomic-1.c	(revision 0)
@@ -0,0 +1,8 @@
+/* Test for _Atomic: not in C99.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -pedantic-errors" } */
+
+_Atomic int i; /* { dg-error "_Atomic" } */
+_Atomic (int) j; /* { dg-error "_Atomic" } */
+int *_Atomic p; /* { dg-error "_Atomic" } */
+void f (int a[_Atomic]); /* { dg-error "_Atomic" } */
Index: gcc/testsuite/gcc.dg/c11-atomic-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c11-atomic-3.c	(revision 0)
@@ -0,0 +1,66 @@
+/* Test for _Atomic in C11.  Test of invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+/* Increment and decrement are invalid for atomic complex types and
+   atomic pointers to incomplete types, just as for the corresponding
+   non-atomic types.  Likewise for types on which arithmetic is
+   invalid.  */
+_Atomic _Complex float acf;
+void *_Atomic apv;
+struct s *_Atomic aps;
+_Atomic struct t { char c; } as;
+
+void
+func (void)
+{
+  acf++; /* { dg-error "complex types" } */
+  acf--; /* { dg-error "complex types" } */
+  ++acf; /* { dg-error "complex types" } */
+  --acf; /* { dg-error "complex types" } */
+  apv++; /* { dg-error "wrong type|pointer of type" } */
+  apv--; /* { dg-error "wrong type|pointer of type" } */
+  ++apv; /* { dg-error "wrong type|pointer of type" } */
+  --apv; /* { dg-error "wrong type|pointer of type" } */
+  aps++; /* { dg-error "pointer to|invalid use of undefined type" } */
+  aps--; /* { dg-error "pointer to|invalid use of undefined type" } */
+  ++aps; /* { dg-error "pointer to|invalid use of undefined type" } */
+  --aps; /* { dg-error "pointer to|invalid use of undefined type" } */
+  as++; /* { dg-error "wrong type" } */
+  as--; /* { dg-error "wrong type" } */
+  ++as; /* { dg-error "wrong type" } */
+  --as; /* { dg-error "wrong type" } */
+}
+
+/* Pointer subtraction and comparisons differing in _Atomic are
+   invalid where such subtraction and comparisons differing in
+   qualifiers are valid.  There is no special allowance for equality
+   comparisons of pointers to atomic void to pointers to object
+   types.  Likewise for conditional expressions.  */
+int *pi;
+_Atomic int *pai;
+_Atomic void *pav;
+int r;
+
+void
+func2 (void)
+{
+  r = pai - pi; /* { dg-error "invalid operands" } */
+  r = pi - pai; /* { dg-error "invalid operands" } */
+  r = pi < pai; /* { dg-error "distinct pointer types" } */
+  r = pi > pai; /* { dg-error "distinct pointer types" } */
+  r = pi <= pai; /* { dg-error "distinct pointer types" } */
+  r = pi >= pai; /* { dg-error "distinct pointer types" } */
+  r = pai < pi; /* { dg-error "distinct pointer types" } */
+  r = pai > pi; /* { dg-error "distinct pointer types" } */
+  r = pai <= pi; /* { dg-error "distinct pointer types" } */
+  r = pai >= pi; /* { dg-error "distinct pointer types" } */
+  r = pav == pi; /* { dg-error "distinct pointer types" } */
+  r = pav != pi; /* { dg-error "distinct pointer types" } */
+  r = pi == pav; /* { dg-error "distinct pointer types" } */
+  r = pi != pav; /* { dg-error "distinct pointer types" } */
+  (void) (r ? pai : pi); /* { dg-error "pointer type mismatch" } */
+  (void) (r ? pi : pai); /* { dg-error "pointer type mismatch" } */
+  (void) (r ? pai : pav); /* { dg-error "pointer type mismatch" } */
+  (void) (r ? pav : pai); /* { dg-error "pointer type mismatch" } */
+}
Index: gcc/testsuite/gcc.dg/c90-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-atomic-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-atomic-1.c	(revision 0)
@@ -0,0 +1,7 @@
+/* Test for _Atomic: not in C90.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c90 -pedantic-errors" } */
+
+_Atomic int i; /* { dg-error "_Atomic" } */
+_Atomic (int) j; /* { dg-error "_Atomic" } */
+int *_Atomic p; /* { dg-error "_Atomic" } */

-- 
Joseph S. Myers
joseph@codesourcery.com



More information about the Gcc-patches mailing list