]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR c/68966 - atomic_fetch_* on atomic_bool not diagnosed
authorMartin Sebor <msebor@redhat.com>
Fri, 8 Jan 2016 01:00:25 +0000 (01:00 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Fri, 8 Jan 2016 01:00:25 +0000 (18:00 -0700)
gcc/ChangeLog:
* doc/extend.texi (__atomic Builtins, __sync Builtins): Document
constraint on the type of arguments.

gcc/c-family/ChangeLog:
* c-common.c (sync_resolve_size): Reject first argument when it's
a pointer to _Bool.

gcc/testsuite/ChangeLog:
* gcc.dg/atomic-fetch-bool.c: New test.
* gcc.dg/sync-fetch-bool.c: New test.

From-SVN: r232147

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/atomic-fetch-bool.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/sync-fetch-bool.c [new file with mode: 0644]

index ad44844071a35ef8429f54889eb79f0d0658d272..73315996c08fcd495ecc28984a0b7bb9244973de 100644 (file)
@@ -1,3 +1,9 @@
+2016-01-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/68966
+       * doc/extend.texi (__atomic Builtins, __sync Builtins): Document
+       constraint on the type of arguments.
+
 2016-01-07  Andreas Tobler  <andreast@gcc.gnu.org>
 
        * config/arm/freebsd.h: Rename SUBTARGET_OVERRIDE_OPTIONS to
index 7bae1a7649d46c9b2dac072e0bd36477b67bf433..a2743d8f8d94ffdddac81269279846239a7b9043 100644 (file)
@@ -1,3 +1,10 @@
+gcc/c-family/ChangeLog:
+2016-01-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/68966
+       * c-common.c (sync_resolve_size): Reject first argument when it's
+       a pointer to _Bool.
+
 2016-01-05  David Malcolm  <dmalcolm@redhat.com>
 
        PR c/69122
index a46e52b693fa198ede684928e77b9071cf862239..0fd37b5c6df2d75acb6bcae44d9822601860ddbf 100644 (file)
@@ -10657,11 +10657,16 @@ builtin_type_for_size (int size, bool unsignedp)
 /* A helper function for resolve_overloaded_builtin in resolving the
    overloaded __sync_ builtins.  Returns a positive power of 2 if the
    first operand of PARAMS is a pointer to a supported data type.
-   Returns 0 if an error is encountered.  */
+   Returns 0 if an error is encountered.
+   FETCH is true when FUNCTION is one of the _FETCH_OP_ or _OP_FETCH_
+   built-ins.  */
 
 static int
-sync_resolve_size (tree function, vec<tree, va_gc> *params)
+sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch)
 {
+  /* Type of the argument.  */
+  tree argtype;
+  /* Type the argument points to.  */
   tree type;
   int size;
 
@@ -10671,7 +10676,7 @@ sync_resolve_size (tree function, vec<tree, va_gc> *params)
       return 0;
     }
 
-  type = TREE_TYPE ((*params)[0]);
+  argtype = type = TREE_TYPE ((*params)[0]);
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
       /* Force array-to-pointer decay for C++.  */
@@ -10686,12 +10691,16 @@ sync_resolve_size (tree function, vec<tree, va_gc> *params)
   if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
     goto incompatible;
 
+  if (fetch && TREE_CODE (type) == BOOLEAN_TYPE)
+    goto incompatible;
+
   size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
   if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
     return size;
 
  incompatible:
-  error ("incompatible type for argument %d of %qE", 1, function);
+  error ("operand type %qT is incompatible with argument %d of %qE",
+        argtype, 1, function);
   return 0;
 }
 
@@ -11250,6 +11259,11 @@ resolve_overloaded_builtin (location_t loc, tree function,
                            vec<tree, va_gc> *params)
 {
   enum built_in_function orig_code = DECL_FUNCTION_CODE (function);
+
+  /* Is function one of the _FETCH_OP_ or _OP_FETCH_ built-ins?
+     Those are not valid to call with a pointer to _Bool (or C++ bool)
+     and so must be rejected.  */
+  bool fetch_op = true;
   bool orig_format = true;
   tree new_return = NULL_TREE;
 
@@ -11325,6 +11339,10 @@ resolve_overloaded_builtin (location_t loc, tree function,
     case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N:
     case BUILT_IN_ATOMIC_LOAD_N:
     case BUILT_IN_ATOMIC_STORE_N:
+      {
+       fetch_op = false;
+       /* Fallthrough to further processing.  */
+      }
     case BUILT_IN_ATOMIC_ADD_FETCH_N:
     case BUILT_IN_ATOMIC_SUB_FETCH_N:
     case BUILT_IN_ATOMIC_AND_FETCH_N:
@@ -11358,7 +11376,16 @@ resolve_overloaded_builtin (location_t loc, tree function,
     case BUILT_IN_SYNC_LOCK_TEST_AND_SET_N:
     case BUILT_IN_SYNC_LOCK_RELEASE_N:
       {
-       int n = sync_resolve_size (function, params);
+       /* The following are not _FETCH_OPs and must be accepted with
+          pointers to _Bool (or C++ bool).  */
+       if (fetch_op)
+         fetch_op =
+           (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
+            && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
+            && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
+            && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
+
+       int n = sync_resolve_size (function, params, fetch_op);
        tree new_function, first_param, result;
        enum built_in_function fncode;
 
index 35d7e57038242d5014b15cbc23222e5eeb1883a6..8122c4cff059ff79b1270ba36737b7c705c50cd1 100644 (file)
@@ -9316,6 +9316,9 @@ returns the value that had previously been in memory.  That is,
 @{ tmp = *ptr; *ptr = ~(tmp & value); return tmp; @}   // nand
 @end smallexample
 
+The object pointed to by the first argument must be of integer or pointer
+type.  It must not be a Boolean type.
+
 @emph{Note:} GCC 4.4 and later implement @code{__sync_fetch_and_nand}
 as @code{*ptr = ~(tmp & value)} instead of @code{*ptr = ~tmp & value}.
 
@@ -9339,6 +9342,9 @@ return the new value.  That is,
 @{ *ptr = ~(*ptr & value); return *ptr; @}   // nand
 @end smallexample
 
+The same constraints on arguments apply as for the corresponding
+@code{__sync_op_and_fetch} built-in functions.
+
 @emph{Note:} GCC 4.4 and later implement @code{__sync_nand_and_fetch}
 as @code{*ptr = ~(*ptr & value)} instead of
 @code{*ptr = ~*ptr & value}.
@@ -9585,13 +9591,14 @@ pointer.
 @deftypefnx {Built-in Function} @var{type} __atomic_or_fetch (@var{type} *ptr, @var{type} val, int memorder)
 @deftypefnx {Built-in Function} @var{type} __atomic_nand_fetch (@var{type} *ptr, @var{type} val, int memorder)
 These built-in functions perform the operation suggested by the name, and
-return the result of the operation. That is,
+return the result of the operation.  That is,
 
 @smallexample
 @{ *ptr @var{op}= val; return *ptr; @}
 @end smallexample
 
-All memory orders are valid.
+The object pointed to by the first argument must be of integer or pointer
+type.  It must not be a Boolean type.  All memory orders are valid.
 
 @end deftypefn
 
@@ -9608,7 +9615,8 @@ return the value that had previously been in @code{*@var{ptr}}.  That is,
 @{ tmp = *ptr; *ptr @var{op}= val; return tmp; @}
 @end smallexample
 
-All memory orders are valid.
+The same constraints on arguments apply as for the corresponding
+@code{__atomic_op_fetch} built-in functions.  All memory orders are valid.
 
 @end deftypefn
 
index 52e54c7b19b3039d84303d63f079c5c2f34ab44a..5840815a918782a9b21c775ac589e478f1085605 100644 (file)
@@ -1,3 +1,9 @@
+2016-01-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/68966
+       * gcc.dg/atomic-fetch-bool.c: New test.
+       * gcc.dg/sync-fetch-bool.c: New test.
+
 2016-01-07  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR fortran/66680
diff --git a/gcc/testsuite/gcc.dg/atomic-fetch-bool.c b/gcc/testsuite/gcc.dg/atomic-fetch-bool.c
new file mode 100644 (file)
index 0000000..f7af11f
--- /dev/null
@@ -0,0 +1,64 @@
+/* PR c/68966 - atomic_fetch_* on atomic_bool not diagnosed
+   Test to verify that calls to __atomic_fetch_op funcions with a _Bool
+   argument are rejected.  This is necessary because GCC expects that
+   all initialized _Bool objects have a specific representation and
+   allowing atomic operations to change it would break the invariant.  */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors -std=c11" } */
+
+
+void test_atomic_bool (_Atomic _Bool *a)
+{
+  enum { SEQ_CST = __ATOMIC_SEQ_CST };
+  
+  __atomic_fetch_add (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_add." } */
+  __atomic_fetch_sub (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_sub." } */
+  __atomic_fetch_and (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_and." } */
+  __atomic_fetch_xor (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_xor." } */
+  __atomic_fetch_or (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_or." } */
+  __atomic_fetch_nand (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_nand." } */
+
+  __atomic_add_fetch (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_add_fetch." } */
+  __atomic_sub_fetch (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_sub_fetch." } */
+  __atomic_and_fetch (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_and_fetch." } */
+  __atomic_xor_fetch (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_xor_fetch." } */
+  __atomic_or_fetch (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_or_fetch." } */
+  __atomic_nand_fetch (a, 1, SEQ_CST);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_nand_fetch." } */
+
+  /* The following are valid and must be accepted.  */
+  _Bool val = 0, ret = 0;
+  __atomic_exchange (a, &val, &ret, SEQ_CST);
+  __atomic_exchange_n (a, val, SEQ_CST);
+  __atomic_compare_exchange (a, &val, &ret, !1, SEQ_CST, SEQ_CST);
+  __atomic_compare_exchange_n (a, &val, ret, !1, SEQ_CST, SEQ_CST);
+  __atomic_test_and_set (a, SEQ_CST);
+  __atomic_clear (a, SEQ_CST);
+}
+
+void test_bool (_Bool *b)
+{
+  enum { SEQ_CST = __ATOMIC_SEQ_CST };
+  
+  __atomic_fetch_add (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_fetch_add." } */
+  __atomic_fetch_sub (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_fetch_sub." } */
+  __atomic_fetch_and (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_fetch_and." } */
+  __atomic_fetch_xor (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_fetch_xor." } */
+  __atomic_fetch_or (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_fetch_or." } */
+  __atomic_fetch_nand (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_fetch_nand." } */
+
+  __atomic_add_fetch (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_add_fetch." } */
+  __atomic_sub_fetch (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_sub_fetch." } */
+  __atomic_and_fetch (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_and_fetch." } */
+  __atomic_xor_fetch (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_xor_fetch." } */
+  __atomic_or_fetch (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_or_fetch." } */
+  __atomic_nand_fetch (b, 1, SEQ_CST);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__atomic_nand_fetch." } */
+
+  /* The following are valid and must be accepted.  */
+  _Bool val = 0, ret = 0;
+  __atomic_exchange (b, &val, &ret, SEQ_CST);
+  __atomic_exchange_n (b, val, SEQ_CST);
+  __atomic_compare_exchange (b, &val, &ret, !1, SEQ_CST, SEQ_CST);
+  __atomic_compare_exchange_n (b, &val, ret, !1, SEQ_CST, SEQ_CST);
+  __atomic_test_and_set (b, SEQ_CST);
+  __atomic_clear (b, SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.dg/sync-fetch-bool.c b/gcc/testsuite/gcc.dg/sync-fetch-bool.c
new file mode 100644 (file)
index 0000000..1d156a9
--- /dev/null
@@ -0,0 +1,54 @@
+/* PR c/68966 - atomic_fetch_* on atomic_bool not diagnosed
+   Test to verify that calls to __sync_fetch_op funcions with a _Bool
+   argument are rejected.  This is necessary because GCC expects that
+   all initialized _Bool objects have a specific representation and
+   allowing atomic operations to change it would break the invariant.  */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors -std=c11" } */
+
+
+void test_sync_atomic_bool (_Atomic _Bool *a)
+{
+  __sync_fetch_and_add (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_add." } */
+  __sync_fetch_and_sub (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_sub." } */
+  __sync_fetch_and_and (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_and." } */
+  __sync_fetch_and_xor (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_xor." } */
+  __sync_fetch_and_or (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_or." } */
+  __sync_fetch_and_nand (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_nand." } */
+  
+  __sync_add_and_fetch (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_add_and_fetch." } */
+  __sync_sub_and_fetch (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_sub_and_fetch." } */
+  __sync_and_and_fetch (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_and_and_fetch." } */
+  __sync_xor_and_fetch (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_xor_and_fetch." } */
+  __sync_or_and_fetch (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_or_and_fetch." } */
+  __sync_nand_and_fetch (a, 1);   /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__sync_nand_and_fetch." } */
+
+  /* The following are valid and must be accepted.  */
+  __sync_bool_compare_and_swap (a, 0, 1);
+  __sync_val_compare_and_swap (a, 0, 1);
+  __sync_lock_test_and_set (a, 1);
+  __sync_lock_release (a);
+}
+
+void test_sync_bool (_Bool *b)
+{
+  __sync_fetch_and_add (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_add." } */
+  __sync_fetch_and_sub (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_sub." } */
+  __sync_fetch_and_and (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_and." } */
+  __sync_fetch_and_xor (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_xor." } */
+  __sync_fetch_and_or (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_or." } */
+  __sync_fetch_and_nand (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_fetch_and_nand." } */
+  
+  __sync_add_and_fetch (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_add_and_fetch." } */
+  __sync_sub_and_fetch (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_sub_and_fetch." } */
+  __sync_and_and_fetch (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_and_and_fetch." } */
+  __sync_xor_and_fetch (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_xor_and_fetch." } */
+  __sync_or_and_fetch (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_or_and_fetch." } */
+  __sync_nand_and_fetch (b, 1);   /* { dg-error "operand type ._Bool \\*. is incompatible with argument 1 of .__sync_nand_and_fetch." } */
+
+  /* The following are valid and must be accepted.  */
+  __sync_bool_compare_and_swap (b, 0, 1);
+  __sync_val_compare_and_swap (b, 0, 1);
+  __sync_lock_test_and_set (b, 1);
+  __sync_lock_release (b);
+}