diff mbox

[C11-atomic] Miscellaneous fixes 1/n

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

Commit Message

Joseph Myers Oct. 17, 2013, 9:50 p.m. UTC
I've applied this patch to the C11-atomic branch to fix various
miscellaneous issues.

The largest part is implementing lvalue-to-rvalue conversions (which
have the effect of doing atomic loads), in all the various places in
the parser that need them.  I didn't particularly thoroughly check for
where these might be needed in ObjC syntax, so there's a sorry () for
use of _Atomic in ObjC until that is fixed, and didn't at all check in
OpenMP syntax, so there's another sorry () for that (it doesn't make
sense to update the OpenMP parsing on this branch anyway, given all
the new OpenMP 4 support since the branch was created).

Apart from that, the _Atomic (type-name) syntax is implemented.  The
tests for applying _Atomic qualifiers to function or array types are
fixed.  Lots of typos and formatting issues are fixed (but I'm sure
there are still more).  stdatomic.h is added to USER_H so it gets
installed.  __extension__ is added to macros in stdatomic.h.  Atomic
bit-fields are disallowed (this is implementation-defined in C11, but
we don't have anything to implement them).  typeof is made to remove
_Atomic qualifiers (and const qualifiers from _Atomic objects; it's
not entirely clear if use of const with the relevant macros is valid,
but it might be), when applied to expressions (as opposed to typeof
(type-name)).  The code generating atomic loads, atomic stores and the
more complicated sequences for atomic compound assignments is made to
put the sequence of statements inside a compound statement which forms
part of the returned expression - you can't just call add_stmt in
random places like the old code was doing, that will insert a
statement outside the current expression in the containing function
that won't be properly sequenced with respect to other parts of the
expression containing the atomic operation.

I put a hack in the C++ front end to disable checks on atomic
qualifiers so that libstdc++ builds - I think that if you want other
people to help on a development branch, it should be kept in a state
where it builds and tests cleanly.  However, I'm aiming specifically
to sort out the C front-end (and later stdatomic.h) issues, with a
view to getting the actual C11 support in shape and with adequate
testsuite coverage, so if that's ready on time I may propose it for
mainline without the attribute or C++ changes - as I understand it,
those are only needed for when targets start defining atomic types as
larger or more-aligned than the corresponding non-atomic types, not to
support the C11 features on the most common architectures.

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

	* Makefile.in (USER_H): Add stdatomic.h.
	* ginclude/stdatomic.h: Fix formatting and typos.  Use correct
	types or predefined macros for atomic_* typedefs.  Use
	__extension__ in macro definitions.
	(enum memory_order): Specify values of enumeration constants using
	__ATOMIC_* predefined macros.
	* tree.c (build_common_tree_nodes): Fix typos.

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

	* c-decl.c (check_bitfield_type_and_width): Disallow atomic types.
	(grokdeclarator): Correct checks for atomic function or array
	types.
	* c-parser.c (c_parser_declspecs): Say "_Atomic" in comment.
	Handle _Atomic (type-name) syntax.  Adjust diagnostics for use of
	_Atomic outside C11 mode.  Call sorry for _Atomic with Objective-C
	or OpenMP.
	(c_parser_typeof_specifier): Remove const and _Atomic qualifiers
	from types of expressions with atomic type.
	(c_parser_direct_declarator_inner, c_parser_initializer)
	(c_parser_initelt, c_parser_statement_after_labels)
	(c_parser_switch_statement, c_parser_for_statement): Use
	convert_lvalue_to_rvalue.
	(c_parser_expr_no_commas): Don't handle atomic loads here.  Use
	convert_lvalue_to_rvalue.
	(c_parser_conditional_expression, c_parser_binary_expression)
	(c_parser_cast_expression, c_parser_unary_expression)
	(c_parser_postfix_expression)
	(c_parser_postfix_expression_after_primary, c_parser_expression):
	Use convert_lvalue_to_rvalue.
	(c_parser_expression_conv, c_parser_expr_list): Document
	conversion of lvalues to rvalues.  Use convert_lvalue_to_rvalue.
	(c_parser_objc_receiver, c_parser_array_notation): Use
	convert_lvalue_to_rvalue.
	* c-tree.h (ctsk_typeof): Adjust comment to mention use for
	_Atomic (type-name).
	(convert_lvalue_to_rvalue): Declare.
	* c-typeck.c (really_atomic_lvalue, convert_lvalue_to_rvalue): New
	functions.
	(build_modify_expr): Use really_atomic_lvalue.  Fix formatting.
	(build_asm_expr): Use convert_lvalue_to_rvalue.
	(build_atomic_assign): Fix formatting and typos.  Put sequence of
	statements inside a compound statement.
	(build_atomic_load): Remove function.  Merged into
	convert_lvalue_to_rvalue.

cp:
2013-10-17  Joseph Myers  <joseph@codesourcery.com>

	* typeck.c (at_least_as_qualified_p): Ignore differences in atomic
	qualifiers.

Comments

Andrew MacLeod Oct. 18, 2013, 4:40 p.m. UTC | #1
On 10/17/2013 05:50 PM, Joseph S. Myers wrote:
> I've applied this patch to the C11-atomic branch to fix various
> miscellaneous issues.

excellent!
>
> I put a hack in the C++ front end to disable checks on atomic
> qualifiers so that libstdc++ builds - I think that if you want other
> people to help on a development branch, it should be kept in a state
> where it builds and tests cleanly.  However, I'm aiming specifically
Yes, perhaps I should not have checked in the bit that uses the atomic 
attribute in the c++ templates... it was working fine until late in the 
game when I removed the incorrect "treat atomic as volatile" parts of 
the patches.. which then caused that failure. sorry.  I didn't know how 
to fix it "correctly"...  I figured it should be easy if you knew how 
:-P  but maybe not...

> to sort out the C front-end (and later stdatomic.h) issues, with a
> view to getting the actual C11 support in shape and with adequate
> testsuite coverage, so if that's ready on time I may propose it for
> mainline without the attribute or C++ changes - as I understand it,
> those are only needed for when targets start defining atomic types as
> larger or more-aligned than the corresponding non-atomic types, not to
> support the C11 features on the most common architectures.
>
right.  We may re-visit it when we finalize the ABI changes for c++...  
Use of the attribute in c++ will ensure that C and C++ both treat an 
atomic object the same...  My original discussions with lawrence and 
jeffrey over atomics concerned the desire to "upsize" an _Atomic object 
to the next highest size that supports lock-free operations. (ie, a 6 
byte object becomes an 8 byte atomic object). The __attribute__ is 
really to ensure we can share the code and get compatible behaviour 
between languages.  At the moment it is a nop. A better solution may 
show up, if we ever actually need it.

Thanks for picking this up... I for one really appreciate it.

Andrew
Joseph Myers Oct. 18, 2013, 5:27 p.m. UTC | #2
On Fri, 18 Oct 2013, Andrew MacLeod wrote:

> right.  We may re-visit it when we finalize the ABI changes for c++...  Use of
> the attribute in c++ will ensure that C and C++ both treat an atomic object
> the same...  My original discussions with lawrence and jeffrey over atomics
> concerned the desire to "upsize" an _Atomic object to the next highest size
> that supports lock-free operations. (ie, a 6 byte object becomes an 8 byte
> atomic object). The __attribute__ is really to ensure we can share the code

I'm thinking of upsizing as something that's best done only for special 
cases such as maybe hppa - that the normal case is that if you request a 
6-byte atomic object, it's not lock-free.  I think users generally expect 
to need to choose appropriate types for their atomic operations.  
(Indeed, we could even merge without the hook, potentially, on the basis 
that atomic_flag is the sole type that needs to be lock-free and so all 
that's required is a suitable target-specific definition of that type in 
stdatomic.h.  And there's a case for not putting the hook on mainline 
until it's needed.  So maybe the attributes and hook can be completely 
avoided on that basis.)
Andrew MacLeod Oct. 18, 2013, 5:52 p.m. UTC | #3
On 10/18/2013 01:27 PM, Joseph S. Myers wrote:
> On Fri, 18 Oct 2013, Andrew MacLeod wrote:
>
>> right.  We may re-visit it when we finalize the ABI changes for c++...  Use of
>> the attribute in c++ will ensure that C and C++ both treat an atomic object
>> the same...  My original discussions with lawrence and jeffrey over atomics
>> concerned the desire to "upsize" an _Atomic object to the next highest size
>> that supports lock-free operations. (ie, a 6 byte object becomes an 8 byte
>> atomic object). The __attribute__ is really to ensure we can share the code
> I'm thinking of upsizing as something that's best done only for special
> cases such as maybe hppa - that the normal case is that if you request a
> 6-byte atomic object, it's not lock-free.  I think users generally expect
> to need to choose appropriate types for their atomic operations.
> (Indeed, we could even merge without the hook, potentially, on the basis
> that atomic_flag is the sole type that needs to be lock-free and so all
> that's required is a suitable target-specific definition of that type in
> stdatomic.h.  And there's a case for not putting the hook on mainline
> until it's needed.  So maybe the attributes and hook can be completely
> avoided on that basis.)
>
I had thought about making the type and value of atomic_flag hooks , but 
never got to it.  There is currently one for the TRUE value which is 
exposed to the C++ templates as" __GCC_ATOMIC_TEST_AND_SET_TRUEVAL"

It is used to set the type to either bool or unsigned char right now, 
and used to set the true value in test_and_set.   I thought that should 
be fully flushed out so that the type and both the true/false values 
were provided by the compiler... and they could be overridden by the 
target if they were different than the default...

Seems to me there was a PR or problem vaguely related to this somewhere 
that this would resolve as well..

And maybe we could skip most of the rest indefinitely...

The alignment issue is an actual issue on the cris port I think. Their 2 
byte atomic operations must operate on 4 byte aligned values... IIRC.  I 
suspect that can wait for another release to address better.  Thats the 
only one I'm aware of.

Andrew

Andrew
Joseph Myers Oct. 18, 2013, 8:40 p.m. UTC | #4
On Fri, 18 Oct 2013, Andrew MacLeod wrote:

> I had thought about making the type and value of atomic_flag hooks , but never
> got to it.  There is currently one for the TRUE value which is exposed to the
> C++ templates as" __GCC_ATOMIC_TEST_AND_SET_TRUEVAL"

I'm tending to think of this, and alignment for cris, as things that don't 
need to be done before the work is mainline-ready - if the basic support 
is in, architecture maintainers can add whatever hooks they need for their 
architectures later, not just in development stage 1.
Andrew MacLeod Oct. 18, 2013, 9:19 p.m. UTC | #5
On 10/18/2013 04:40 PM, Joseph S. Myers wrote:
> On Fri, 18 Oct 2013, Andrew MacLeod wrote:
>
>> I had thought about making the type and value of atomic_flag hooks , but never
>> got to it.  There is currently one for the TRUE value which is exposed to the
>> C++ templates as" __GCC_ATOMIC_TEST_AND_SET_TRUEVAL"
> I'm tending to think of this, and alignment for cris, as things that don't
> need to be done before the work is mainline-ready - if the basic support
> is in, architecture maintainers can add whatever hooks they need for their
> architectures later, not just in development stage 1.
>
agreed.  those are already issues with atomics... not the C11 layer on top.

Andrew
diff mbox

Patch

Index: gcc/ginclude/stdatomic.h
===================================================================
--- gcc/ginclude/stdatomic.h	(revision 203707)
+++ gcc/ginclude/stdatomic.h	(working copy)
@@ -1,88 +1,86 @@ 
 /* Copyright (C) 2013 Free Software Foundation, Inc.
- *
- * This file is part of GCC.
- *
- * GCC is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GCC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Under Section 7 of GPL version 3, you are granted additional
- * permissions described in the GCC Runtime Library Exception, version
- * 3.1, as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License and
- * a copy of the GCC Runtime Library Exception along with this program;
- * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
- * <http://www.gnu.org/licenses/>.  */
 
-/*
- *  * ISO C11 Standard:  7.17  Atomics <stdatomic.h>
- *   */
+This file is part of GCC.
 
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* ISO C11 Standard:  7.17  Atomics <stdatomic.h>.  */
+
 #ifndef _STDATOMIC_H
 #define _STDATOMIC_H
 
 
 typedef enum memory_order
 {
-  memory_order_relaxed,
-  memory_order_consume,
-  memory_order_acquire,
-  memory_order_release,
-  memory_order_acq_rel,
-  memory_order_seq_cst
+  memory_order_relaxed = __ATOMIC_RELAXED,
+  memory_order_consume = __ATOMIC_CONSUME,
+  memory_order_acquire = __ATOMIC_ACQUIRE,
+  memory_order_release = __ATOMIC_RELEASE,
+  memory_order_acq_rel = __ATOMIC_ACQ_REL,
+  memory_order_seq_cst = __ATOMIC_SEQ_CST
 } memory_order;
 
 
 typedef _Atomic _Bool 	       atomic_bool;
-typedef _Atomic char	       atomic_char
-typedef _Atomic schar	       atomic_schar
-typedef _Atomic uchar	       atomic_uchar
-typedef _Atomic short	       atomic_short
-typedef _Atomic ushort	       atomic_ushort
-typedef _Atomic int            atomic_int
-typedef _Atomic uint           atomic_uint
-typedef _Atomic long           atomic_long
-typedef _Atomic ulong          atomic_ulong
-typedef _Atomic llong          atomic_llong
-typedef _Atomic ullong         atomic_ullong
-typedef _Atomic char16_t       atomic_char16_t
-typedef _Atomic char32_t       atomic_char32_t
-typedef _Atomic wchar_t        atomic_wchar_t
-typedef _Atomic int_least8_t   atomic_int_least8_t
-typedef _Atomic uint_least8_t  atomic_uint_least8_t
-typedef _Atomic int_least16_t  atomic_int_least16_t
-typedef _Atomic uint_least16_t atomic_uint_least16_t
-typedef _Atomic int_least32_t  atomic_int_least32_t
-typedef _Atomic uint_least32_t atomic_uint_least32_t
-typedef _Atomic int_least64_t  atomic_int_least64_t
-typedef _Atomic uint_least64_t atomic_uint_least64_t
-typedef _Atomic int_fast8_t    atomic_int_fast8_t
-typedef _Atomic uint_fast8_t   atomic_uint_fast8_t
-typedef _Atomic int_fast16_t   atomic_int_fast16_t
-typedef _Atomic uint_fast16_t  atomic_uint_fast16_t
-typedef _Atomic int_fast32_t   atomic_int_fast32_t
-typedef _Atomic uint_fast32_t  atomic_uint_fast32_t
-typedef _Atomic int_fast64_t   atomic_int_fast64_t
-typedef _Atomic uint_fast64_t  atomic_uint_fast64_t
-typedef _Atomic intptr_t       atomic_intptr_t
-typedef _Atomic uintptr_t      atomic_uintptr_t
-typedef _Atomic size_t         atomic_size_t
-typedef _Atomic ptrdiff_t      atomic_ptrdiff_t
-typedef _Atomic intmax_t       atomic_intmax_t
-typedef _Atomic uintmax_t      atomic_uintmax_t        
+typedef _Atomic char	       atomic_char;
+typedef _Atomic signed char    atomic_schar;
+typedef _Atomic unsigned char  atomic_uchar;
+typedef _Atomic short	       atomic_short;
+typedef _Atomic unsigned short atomic_ushort;
+typedef _Atomic int            atomic_int;
+typedef _Atomic unsigned int   atomic_uint;
+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        
 
 
 #define ATOMIC_VAR_INIT(VALUE)	(VALUE)
 #define atomic_init(PTR, VAL)	{ *(PTR) = (VAL); }
 
-/* TODO actually kill the dependancy.  */
+/* TODO actually kill the dependency.  */
 #define kill_dependency(Y)	(Y)
 
 #define atomic_thread_fence 	__atomic_thread_fence
@@ -111,14 +109,9 @@  typedef _Atomic _Bool 	       atomic_bool;
 			__atomic_is_lock_free (sizeof (_Atomic void *), NULL)
 
 
-/* TODO: Note this required the __typeof__ definition to drops the atomic
-   qualifier, which means __typeof__ (atomic type) return the underlying 
-   non-atomic type.
-   I think this makes sense, as most meaningful uses of __typeof__ of an atomic
-   object would want the non-atomic version to be useful, as it is above.
-
-   If we dont want to change that meaning, we'll need to implement a __typeof__
-   variant which does this. 
+/* Note that these macros require __typeof__ to remove _Atomic
+   qualifiers (and const qualifiers, if those are valid on macro
+   operands).
    
    Also note that the header file uses the generic form of __atomic builtins,
    which requires the address to be taken of the value parameter, and then
@@ -126,46 +119,48 @@  typedef _Atomic _Bool 	       atomic_bool;
    and the compiler is smart enough to convert these to lock-free _N 
    variants if possible, and throw away the temps.  */
 
-#define atomic_store_explicit(PTR, VAL, MO) ({		\
-  __typeof__ (*(PTR)) __tmp  = (VAL); 			\
+#define atomic_store_explicit(PTR, VAL, MO) __extension__ ({	\
+  __typeof__ (*(PTR)) __tmp  = (VAL);				\
   __atomic_store ((PTR), &__tmp, (MO)); })
 
 #define atomic_store(PTR, VAL)				\
   atomic_store_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
 
 
-#define atomic_load_explicit(PTR, MO) ({		\
+#define atomic_load_explicit(PTR, MO) __extension__ ({	\
   __typeof__ (*(PTR)) __tmp; 				\
-  __atomic)load ((PTR), &__tmp, __ATOMIC_SEQ_CST);	\
+  __atomic_load ((PTR), &__tmp, __ATOMIC_SEQ_CST);	\
   __tmp; })
 
 #define atomic_load(PTR)  atomic_load_explicit (PTR, __ATOMIC_SEQ_CST)
 
 
-#define atomic_exchange_explicit(PTR, VAL, MO) ({	\
-  __typeof__ (*(PTR)) __tmp  = (VAL); 			\
-  __atomic_exchange_n ((PTR), (VAL), (MO)); 		\
+#define atomic_exchange_explicit(PTR, VAL, MO) __extension__ ({	\
+  __typeof__ (*(PTR)) __tmp  = (VAL);				\
+  __atomic_exchange_n ((PTR), (VAL), (MO));			\
   __tmp; })
 
 #define atomic_exchange(PTR, VAL) 			\
-  atomic_exchange_explicit(PTR, VAL, __ATOMIC_SEQ_CST)
+  atomic_exchange_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
 
 
-#define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) ({ \
-  __typeof__ (*(PTR)) __tmp  = (DES); 			\
+#define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \
+  __extension__ ({							\
+  __typeof__ (*(PTR)) __tmp  = (DES);					\
   __atomic_compare_exchange_n ((PTR), (VAL), &__tmp, 0, (SUC), (FAIL)); })
 
 #define atomic_compare_exchange_strong(PTR, VAL, DES) 			   \
-  atomic_compare_exchange_strong_explicit(PTR, VAL, DES, __ATOMIC_SEQ_CST, \
-				          __ATOMIC_SEQ_CST)
+  atomic_compare_exchange_strong_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
+					   __ATOMIC_SEQ_CST)
 
-#define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) ({  \
-  __typeof__ (*(PTR)) __tmp  = (DES); 			\
+#define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \
+  __extension__ ({							\
+  __typeof__ (*(PTR)) __tmp  = (DES);					\
   __atomic_compare_exchange_n ((PTR), (VAL), &__tmp, 1, (SUC), (FAIL)); })
 
-#define atomic_compare_exchange_weak(PTR, VAL, DES) 			 \
-  atomic_compare_exchange_weak_explicit(PTR, VAL, DES, __ATOMIC_SEQ_CST, \
-					__ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_weak(PTR, VAL, DES)			\
+  atomic_compare_exchange_weak_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
+					 __ATOMIC_SEQ_CST)
 
 
 
@@ -196,9 +191,9 @@  typedef _Atomic _Bool 	       atomic_bool;
 
 
 #if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
-    typedef bool atomic_flag;
+    typedef _Atomic bool atomic_flag;
 #else
-    typedef unsigned char atomic_flag;
+    typedef _Atomic unsigned char atomic_flag;
 #endif
 
 #define ATOMIC_FLAG_INIT	0
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 203707)
+++ gcc/tree.c	(working copy)
@@ -9690,8 +9690,8 @@  build_common_tree_nodes (bool signed_char, bool sh
   unsigned_intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 1);
   unsigned_intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 1);
 
-  /* Dont call build_qualified type for atomics.  That routine does special
-     processing for atomics, and until they are initialized its better not
+  /* Don't call build_qualified type for atomics.  That routine does special
+     processing for atomics, and until they are initialized it's better not
      to make that call.  
      
      Check to see if there is a target override for atomic types.  */
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 203707)
+++ gcc/Makefile.in	(working copy)
@@ -371,6 +371,7 @@  USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdfix.h \
 	 $(srcdir)/ginclude/stdnoreturn.h \
 	 $(srcdir)/ginclude/stdalign.h \
+	 $(srcdir)/ginclude/stdatomic.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 203707)
+++ gcc/cp/typeck.c	(working copy)
@@ -1439,6 +1439,11 @@  at_least_as_qualified_p (const_tree type1, const_t
   int q1 = cp_type_quals (type1);
   int q2 = cp_type_quals (type2);
 
+  /* TODO: as a hack for building libstdc++, ignore atomic type
+     qualifiers.  (This is probably not the right place for this.)  */
+  q1 &= ~TYPE_QUAL_ATOMIC;
+  q2 &= ~TYPE_QUAL_ATOMIC;
+
   /* All qualifiers for TYPE2 must also appear in TYPE1.  */
   return (q1 & q2) == q2;
 }
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 203707)
+++ gcc/c/c-parser.c	(working copy)
@@ -1941,8 +1941,10 @@  c_parser_static_assert_declaration_no_semi (c_pars
      struct-or-union-specifier
      enum-specifier
      typedef-name
+     atomic-type-specifier
 
    (_Bool and _Complex are new in C99.)
+   (atomic-type-specifier is new in C11.)
 
    C90 6.5.3, C99 6.7.3:
 
@@ -1951,10 +1953,10 @@  c_parser_static_assert_declaration_no_semi (c_pars
      restrict
      volatile
      address-space-qualifier
-     atomic
+     _Atomic
 
    (restrict is new in C99.)
-   (atomic is new in C11.)
+   (_Atomic is new in C11.)
 
    GNU extensions:
 
@@ -1983,6 +1985,9 @@  c_parser_static_assert_declaration_no_semi (c_pars
   (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)
 
+   atomic-type-specifier
+    _Atomic ( type-name )
+
    Objective-C:
 
    type-specifier:
@@ -2177,16 +2182,60 @@  c_parser_declspecs (c_parser *parser, struct c_dec
 	  declspecs_add_type (loc, specs, t);
 	  break;
 	case RID_ATOMIC:
+	  /* 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.  */
+	  if (c_dialect_objc ())
+	    sorry ("%<_Atomic%> in Objective-C");
+	  /* C parser handling of OpenMP constructs needs checking for
+	     correct lvalue-to-rvalue conversions.  */
+	  if (flag_openmp)
+	    sorry ("%<_Atomic%> with OpenMP");
 	  if (!flag_isoc11)
 	    {
 	      if (flag_isoc99)
 		pedwarn (loc, OPT_Wpedantic,
-			 "ISO C99 does not support _Atomic qualifier");
+			 "ISO C99 does not support the %<_Atomic%> qualifier");
 	      else
 		pedwarn (loc, OPT_Wpedantic,
-			 "ISO C90 does not support _Atomic qualifier");
+			 "ISO C90 does not support the %<_Atomic%> qualifier");
 	    }
-	  /* Fallthru.  */
+	  attrs_ok = true;
+	  tree value;
+	  value = c_parser_peek_token (parser)->value;
+	  c_parser_consume_token (parser);
+	  if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	    {
+	      /* _Atomic ( type-name ).  */
+	      seen_type = true;
+	      c_parser_consume_token (parser);
+	      struct c_type_name *type = c_parser_type_name (parser);
+	      t.kind = ctsk_typeof;
+	      t.spec = error_mark_node;
+	      t.expr = NULL_TREE;
+	      t.expr_const_operands = true;
+	      if (type != NULL)
+		t.spec = groktypename (type, &t.expr,
+				       &t.expr_const_operands);
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+					 "expected %<)%>");
+	      if (t.spec != error_mark_node)
+		{
+		  if (TREE_CODE (t.spec) == ARRAY_TYPE)
+		    error_at (loc, "%<_Atomic%>-qualified array type");
+		  else if (TREE_CODE (t.spec) == FUNCTION_TYPE)
+		    error_at (loc, "%<_Atomic%>-qualified function type");
+		  else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED)
+		    error_at (loc, "%<_Atomic%> applied to a qualified type");
+		  else
+		    t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC);
+		}
+	      declspecs_add_type (loc, specs, t);
+	    }
+	  else
+	    declspecs_add_qual (loc, specs, value);
+	  break;
 	case RID_CONST:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
@@ -2781,6 +2830,17 @@  c_parser_typeof_specifier (c_parser *parser)
       if (was_vm)
 	ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
       pop_maybe_used (was_vm);
+      /* For use in macros such as those in <stdatomic.h>, remove
+	 _Atomic and const qualifiers from atomic types.  (Possibly
+	 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))
+	ret.spec = c_build_qualified_type (ret.spec,
+					   (TYPE_QUALS (ret.spec)
+					    & ~(TYPE_QUAL_ATOMIC
+						| TYPE_QUAL_CONST)));
     }
   c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
   return ret;
@@ -3062,7 +3122,10 @@  c_parser_direct_declarator_inner (c_parser *parser
       struct c_declspecs *quals_attrs = build_null_declspecs ();
       bool static_seen;
       bool star_seen;
-      tree dimen;
+      struct c_expr dimen;
+      dimen.value = NULL_TREE;
+      dimen.original_code = ERROR_MARK;
+      dimen.original_type = NULL_TREE;
       c_parser_consume_token (parser);
       c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
       static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
@@ -3078,19 +3141,19 @@  c_parser_direct_declarator_inner (c_parser *parser
       if (static_seen)
 	{
 	  star_seen = false;
-	  dimen = c_parser_expr_no_commas (parser, NULL).value;
+	  dimen = c_parser_expr_no_commas (parser, NULL);
 	}
       else
 	{
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
 	    {
-	      dimen = NULL_TREE;
+	      dimen.value = NULL_TREE;
 	      star_seen = false;
 	    }
 	  else if (flag_enable_cilkplus
 		   && c_parser_next_token_is (parser, CPP_COLON))
 	    {
-	      dimen = error_mark_node;
+	      dimen.value = error_mark_node;
 	      star_seen = false;
 	      error_at (c_parser_peek_token (parser)->location,
 			"array notations cannot be used in declaration");
@@ -3100,20 +3163,20 @@  c_parser_direct_declarator_inner (c_parser *parser
 	    {
 	      if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
 		{
-		  dimen = NULL_TREE;
+		  dimen.value = NULL_TREE;
 		  star_seen = true;
 		  c_parser_consume_token (parser);
 		}
 	      else
 		{
 		  star_seen = false;
-		  dimen = c_parser_expr_no_commas (parser, NULL).value;
+		  dimen = c_parser_expr_no_commas (parser, NULL);
 		}
 	    }
 	  else
 	    {
 	      star_seen = false;
-	      dimen = c_parser_expr_no_commas (parser, NULL).value;
+	      dimen = c_parser_expr_no_commas (parser, NULL);
 	    }
 	}
       if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
@@ -3132,9 +3195,9 @@  c_parser_direct_declarator_inner (c_parser *parser
 				     "expected %<]%>");
 	  return NULL;
 	}
-      if (dimen)
-	mark_exp_read (dimen);
-      declarator = build_array_declarator (brace_loc, dimen, quals_attrs,
+      if (dimen.value)
+	dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true);
+      declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs,
 					   static_seen, star_seen);
       if (declarator == NULL)
 	return NULL;
@@ -3759,7 +3822,7 @@  c_parser_initializer (c_parser *parser)
       ret = c_parser_expr_no_commas (parser, NULL);
       if (TREE_CODE (ret.value) != STRING_CST
 	  && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
-	ret = default_function_array_read_conversion (loc, ret);
+	ret = convert_lvalue_to_rvalue (loc, ret, true, true);
       return ret;
     }
 }
@@ -3938,8 +4001,8 @@  c_parser_initelt (c_parser *parser, struct obstack
 		      c_parser_consume_token (parser);
 		      exp_loc = c_parser_peek_token (parser)->location;
 		      next = c_parser_expr_no_commas (parser, NULL);
-		      next = default_function_array_read_conversion (exp_loc,
-								     next);
+		      next = convert_lvalue_to_rvalue (exp_loc, next,
+						       true, true);
 		      rec = build_compound_expr (comma_loc, rec, next.value);
 		    }
 		parse_message_args:
@@ -4035,7 +4098,7 @@  c_parser_initval (c_parser *parser, struct c_expr
       if (init.value != NULL_TREE
 	  && TREE_CODE (init.value) != STRING_CST
 	  && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
-	init = default_function_array_read_conversion (loc, init);
+	init = convert_lvalue_to_rvalue (loc, init, true, true);
     }
   process_init_element (init, false, braced_init_obstack);
 }
@@ -4524,12 +4587,12 @@  c_parser_statement_after_labels (c_parser *parser)
 	    }
 	  else if (c_parser_next_token_is (parser, CPP_MULT))
 	    {
-	      tree val;
+	      struct c_expr val;
 
 	      c_parser_consume_token (parser);
-	      val = c_parser_expression (parser).value;
-	      mark_exp_read (val);
-	      stmt = c_finish_goto_ptr (loc, val);
+	      val = c_parser_expression (parser);
+	      val = convert_lvalue_to_rvalue (loc, val, false, true);
+	      stmt = c_finish_goto_ptr (loc, val.value);
 	    }
 	  else
 	    c_parser_error (parser, "expected identifier or %<*%>");
@@ -4578,9 +4641,10 @@  c_parser_statement_after_labels (c_parser *parser)
 	    }
 	  else
 	    {
-	      tree expr = c_parser_expression (parser).value;
-	      expr = c_fully_fold (expr, false, NULL);
-	      stmt = objc_build_throw_stmt (loc, expr);
+	      struct c_expr expr = c_parser_expression (parser);
+	      expr = convert_lvalue_to_rvalue (loc, expr, false, false);
+	      expr.value = c_fully_fold (expr.value, false, NULL);
+	      stmt = objc_build_throw_stmt (loc, expr.value);
 	      goto expect_semicolon;
 	    }
 	  break;
@@ -4792,6 +4856,7 @@  c_parser_if_statement (c_parser *parser)
 static void
 c_parser_switch_statement (c_parser *parser)
 {
+  struct c_expr ce;
   tree block, expr, body, save_break;
   location_t switch_loc = c_parser_peek_token (parser)->location;
   location_t switch_cond_loc;
@@ -4801,7 +4866,9 @@  c_parser_switch_statement (c_parser *parser)
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       switch_cond_loc = c_parser_peek_token (parser)->location;
-      expr = c_parser_expression (parser).value;
+      ce = c_parser_expression (parser);
+      ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
+      expr = ce.value;
       if (flag_enable_cilkplus && contains_array_notation_expr (expr))
 	{
 	  error_at (switch_cond_loc,
@@ -5046,8 +5113,10 @@  c_parser_for_statement (c_parser *parser)
 	{
 	init_expr:
 	  {
+	    struct c_expr ce;
 	    tree init_expression;
-	    init_expression = c_parser_expression (parser).value;
+	    ce = c_parser_expression (parser);
+	    init_expression = ce.value;
 	    parser->objc_could_be_foreach_context = false;
 	    if (c_parser_next_token_is_keyword (parser, RID_IN))
 	      {
@@ -5059,6 +5128,8 @@  c_parser_for_statement (c_parser *parser)
 	      }
 	    else
 	      {
+		ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+		init_expression = ce.value;
 		c_finish_expr_stmt (loc, init_expression);
 		c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
 	      }
@@ -5106,7 +5177,11 @@  c_parser_for_statement (c_parser *parser)
 	    collection_expression = c_fully_fold (c_parser_expression (parser).value,
 						  false, NULL);
 	  else
-	    incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+	    {
+	      struct c_expr ce = c_parser_expression (parser);
+	      ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+	      incr = c_process_expr_stmt (loc, ce.value);
+	    }
 	}
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
@@ -5457,39 +5532,12 @@  c_parser_expr_no_commas (c_parser *parser, struct
       code = BIT_IOR_EXPR;
       break;
     default:
-      /* TODO
-	 This doesnt work. Expressions like ~a where a is atomic do not function
-	 properly. since the rhs is parsed/consumed as an entire expression.  
-	 and at the time, we don't know if this expression is a RHS or LHS, so
-	 we dont know if we need a load or not.
-
-	 I think we need to introduce an ATOMIC_EXPR node, and whenever the
-	 type of an expression becomes TYPE_ATOMIC(), we immiedately hang the
-	 expression off a new ATOMIC_EXPR node as operand 0, and change the
-	 type of the ATOMIC_EXPR node to TYPE_MAIN_VARIANT(atomic_type).  This
-	 will encapsulate all the expressions which need to be handled with an
-	 ATOMIC_EXPR node, and then at this point, scan the rhs and see if there
-	 are any ATOMIC_EXPR, and replace those nodes with atomic_loads's of 
-	 the ATOMIC_EXPR operand.
-
-	 THis will also change the LHS processing in build_modify_expr... 
-	 although *in theory* the top level expression *ought* to be the
-	 only thing that should have an ATOMIC_EXPR(), so it may be as
-	 simple as checking the LHS is an ATOMIC_EXPR node rather than 
-	 the current check of ATOMIC_TYPE (lhs).
-
-	 This also means the TYPE_ATOMIC flag in expressions should ONLY 
-	 occur on the operand of an ATOMIC_EXPR() nodes... anywhere else 
-	 would be an error.  */
-      if (TREE_CODE (lhs.value) != ERROR_MARK 
-	  && TYPE_ATOMIC (TREE_TYPE (lhs.value)))
-	lhs.value = build_atomic_load (op_location, lhs.value);
       return lhs;
     }
   c_parser_consume_token (parser);
   exp_location = c_parser_peek_token (parser)->location;
   rhs = c_parser_expr_no_commas (parser, NULL);
-  rhs = default_function_array_read_conversion (exp_location, rhs);
+  rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true);
   
   ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
 				 code, exp_location, rhs.value,
@@ -5532,7 +5580,7 @@  c_parser_conditional_expression (c_parser *parser,
   if (c_parser_next_token_is_not (parser, CPP_QUERY))
     return cond;
   cond_loc = c_parser_peek_token (parser)->location;
-  cond = default_function_array_read_conversion (cond_loc, cond);
+  cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true);
   c_parser_consume_token (parser);
   if (c_parser_next_token_is (parser, CPP_COLON))
     {
@@ -5580,7 +5628,7 @@  c_parser_conditional_expression (c_parser *parser,
   {
     location_t exp2_loc = c_parser_peek_token (parser)->location;
     exp2 = c_parser_conditional_expression (parser, NULL);
-    exp2 = default_function_array_read_conversion (exp2_loc, exp2);
+    exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true);
   }
   c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
   ret.value = build_conditional_expr (colon_loc, cond.value,
@@ -5719,11 +5767,11 @@  c_parser_binary_expression (c_parser *parser, stru
 	break;								      \
       }									      \
     stack[sp - 1].expr							      \
-      = default_function_array_read_conversion (stack[sp - 1].loc,	      \
-						stack[sp - 1].expr);	      \
+      = convert_lvalue_to_rvalue (stack[sp - 1].loc,			      \
+				  stack[sp - 1].expr, true, true);	      \
     stack[sp].expr							      \
-      = default_function_array_read_conversion (stack[sp].loc,		      \
-						stack[sp].expr);	      \
+      = convert_lvalue_to_rvalue (stack[sp].loc,			      \
+				  stack[sp].expr, true, true);		      \
     stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,		      \
 						 stack[sp].op,		      \
 						 stack[sp - 1].expr,	      \
@@ -5832,8 +5880,8 @@  c_parser_binary_expression (c_parser *parser, stru
 	{
 	case TRUTH_ANDIF_EXPR:
 	  stack[sp].expr
-	    = default_function_array_read_conversion (stack[sp].loc,
-						      stack[sp].expr);
+	    = convert_lvalue_to_rvalue (stack[sp].loc,
+					stack[sp].expr, true, true);
 	  stack[sp].expr.value = c_objc_common_truthvalue_conversion
 	    (stack[sp].loc, default_conversion (stack[sp].expr.value));
 	  c_inhibit_evaluation_warnings += (stack[sp].expr.value
@@ -5841,8 +5889,8 @@  c_parser_binary_expression (c_parser *parser, stru
 	  break;
 	case TRUTH_ORIF_EXPR:
 	  stack[sp].expr
-	    = default_function_array_read_conversion (stack[sp].loc,
-						      stack[sp].expr);
+	    = convert_lvalue_to_rvalue (stack[sp].loc,
+					stack[sp].expr, true, true);
 	  stack[sp].expr.value = c_objc_common_truthvalue_conversion
 	    (stack[sp].loc, default_conversion (stack[sp].expr.value));
 	  c_inhibit_evaluation_warnings += (stack[sp].expr.value
@@ -5913,7 +5961,7 @@  c_parser_cast_expression (c_parser *parser, struct
       {
 	location_t expr_loc = c_parser_peek_token (parser)->location;
 	expr = c_parser_cast_expression (parser, NULL);
-	expr = default_function_array_read_conversion (expr_loc, expr);
+	expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true);
       }
       ret.value = c_cast_expr (cast_loc, type_name, expr.value);
       ret.original_code = ERROR_MARK;
@@ -6004,7 +6052,7 @@  c_parser_unary_expression (c_parser *parser)
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR);
       return ret;
     case CPP_PLUS:
@@ -6015,25 +6063,25 @@  c_parser_unary_expression (c_parser *parser)
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
     case CPP_MINUS:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
     case CPP_COMPL:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
     case CPP_NOT:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
     case CPP_AND_AND:
       /* Refer to the address of a label as a pointer.  */
@@ -6826,10 +6874,13 @@  c_parser_postfix_expression (c_parser *parser)
 		      }
 		    else
 		      {
+			struct c_expr ce;
 			tree idx;
 			loc = c_parser_peek_token (parser)->location;
 			c_parser_consume_token (parser);
-			idx = c_parser_expression (parser).value;
+			ce = c_parser_expression (parser);
+			ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+			idx = ce.value;
 			idx = c_fully_fold (idx, false, NULL);
 			c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
 						   "expected %<]%>");
@@ -6952,11 +7003,11 @@  c_parser_postfix_expression (c_parser *parser)
 	    e1_p = &(*cexpr_list)[0];
 	    e2_p = &(*cexpr_list)[1];
 
-	    mark_exp_read (e1_p->value);
+	    *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true);
 	    if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR)
 	      e1_p->value = convert (TREE_TYPE (e1_p->value),
 				     TREE_OPERAND (e1_p->value, 0));
-	    mark_exp_read (e2_p->value);
+	    *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true);
 	    if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR)
 	      e2_p->value = convert (TREE_TYPE (e2_p->value),
 				     TREE_OPERAND (e2_p->value, 0));
@@ -7004,7 +7055,7 @@  c_parser_postfix_expression (c_parser *parser)
 	      }
 
 	    FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p)
-	      mark_exp_read (p->value);
+	      *p = convert_lvalue_to_rvalue (loc, *p, true, true);
 
 	    if (vec_safe_length (cexpr_list) == 2)
 	      expr.value =
@@ -7324,7 +7375,7 @@  c_parser_postfix_expression_after_primary (c_parse
 	case CPP_DEREF:
 	  /* Structure element reference.  */
 	  c_parser_consume_token (parser);
-	  expr = default_function_array_conversion (expr_loc, expr);
+	  expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false);
 	  if (c_parser_next_token_is (parser, CPP_NAME))
 	    ident = c_parser_peek_token (parser)->value;
 	  else
@@ -7402,8 +7453,11 @@  c_parser_postfix_expression_after_primary (c_parse
 static struct c_expr
 c_parser_expression (c_parser *parser)
 {
+  location_t tloc = c_parser_peek_token (parser)->location;
   struct c_expr expr;
   expr = c_parser_expr_no_commas (parser, NULL);
+  if (c_parser_next_token_is (parser, CPP_COMMA))
+    expr = convert_lvalue_to_rvalue (tloc, expr, true, false);
   while (c_parser_next_token_is (parser, CPP_COMMA))
     {
       struct c_expr next;
@@ -7418,7 +7472,7 @@  c_parser_expression (c_parser *parser)
       if (DECL_P (lhsval) || handled_component_p (lhsval))
 	mark_exp_read (lhsval);
       next = c_parser_expr_no_commas (parser, NULL);
-      next = default_function_array_conversion (expr_loc, next);
+      next = convert_lvalue_to_rvalue (expr_loc, next, true, false);
       expr.value = build_compound_expr (loc, expr.value, next.value);
       expr.original_code = COMPOUND_EXPR;
       expr.original_type = next.original_type;
@@ -7426,8 +7480,8 @@  c_parser_expression (c_parser *parser)
   return expr;
 }
 
-/* Parse an expression and convert functions or arrays to
-   pointers.  */
+/* Parse an expression and convert functions or arrays to pointers and
+   lvalues to rvalues.  */
 
 static struct c_expr
 c_parser_expression_conv (c_parser *parser)
@@ -7435,12 +7489,13 @@  c_parser_expression_conv (c_parser *parser)
   struct c_expr expr;
   location_t loc = c_parser_peek_token (parser)->location;
   expr = c_parser_expression (parser);
-  expr = default_function_array_conversion (loc, expr);
+  expr = convert_lvalue_to_rvalue (loc, expr, true, false);
   return expr;
 }
 
 /* Parse a non-empty list of expressions.  If CONVERT_P, convert
-   functions and arrays to pointers.  If FOLD_P, fold the expressions.
+   functions and arrays to pointers and lvalues to rvalues.  If
+   FOLD_P, fold the expressions.
 
    nonempty-expr-list:
      assignment-expression
@@ -7470,7 +7525,7 @@  c_parser_expr_list (c_parser *parser, bool convert
     cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
   expr = c_parser_expr_no_commas (parser, NULL);
   if (convert_p)
-    expr = default_function_array_read_conversion (loc, expr);
+    expr = convert_lvalue_to_rvalue (loc, expr, true, true);
   if (fold_p)
     expr.value = c_fully_fold (expr.value, false, NULL);
   ret->quick_push (expr.value);
@@ -7494,7 +7549,7 @@  c_parser_expr_list (c_parser *parser, bool convert
 	cur_sizeof_arg_loc = UNKNOWN_LOCATION;
       expr = c_parser_expr_no_commas (parser, NULL);
       if (convert_p)
-	expr = default_function_array_read_conversion (loc, expr);
+	expr = convert_lvalue_to_rvalue (loc, expr, true, true);
       if (fold_p)
 	expr.value = c_fully_fold (expr.value, false, NULL);
       vec_safe_push (ret, expr.value);
@@ -8400,7 +8455,9 @@  c_parser_objc_synchronized_statement (c_parser *pa
   objc_maybe_warn_exceptions (loc);
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
-      expr = c_parser_expression (parser).value;
+      struct c_expr ce = c_parser_expression (parser);
+      ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+      expr = ce.value;
       expr = c_fully_fold (expr, false, NULL);
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
@@ -8530,6 +8587,8 @@  c_parser_objc_selector_arg (c_parser *parser)
 static tree
 c_parser_objc_receiver (c_parser *parser)
 {
+  location_t loc = c_parser_peek_token (parser)->location;
+
   if (c_parser_peek_token (parser)->type == CPP_NAME
       && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
 	  || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
@@ -8538,7 +8597,9 @@  c_parser_objc_receiver (c_parser *parser)
       c_parser_consume_token (parser);
       return objc_get_class_reference (id);
     }
-  return c_fully_fold (c_parser_expression (parser).value, false, NULL);
+  struct c_expr ce = c_parser_expression (parser);
+  ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+  return c_fully_fold (ce.value, false, NULL);
 }
 
 /* Parse objc-message-args.
@@ -11364,7 +11425,9 @@  c_parser_array_notation (location_t loc, c_parser
 	      return error_mark_node;
 	    }
 	  c_parser_consume_token (parser); /* consume the ':' */
-	  end_index = c_parser_expression (parser).value;
+	  struct c_expr ce = c_parser_expression (parser);
+	  ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+	  end_index = ce.value;
 	  if (!end_index || end_index == error_mark_node)
 	    {
 	      c_parser_skip_to_end_of_block_or_statement (parser);
@@ -11373,7 +11436,9 @@  c_parser_array_notation (location_t loc, c_parser
 	  if (c_parser_peek_token (parser)->type == CPP_COLON)
 	    {
 	      c_parser_consume_token (parser);
-	      stride = c_parser_expression (parser).value;
+	      ce = c_parser_expression (parser);
+	      ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+	      stride = ce.value;
 	      if (!stride || stride == error_mark_node)
 		{
 		  c_parser_skip_to_end_of_block_or_statement (parser);
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 203707)
+++ gcc/c/c-typeck.c	(working copy)
@@ -1913,6 +1913,84 @@  default_function_array_read_conversion (location_t
   return default_function_array_conversion (loc, exp);
 }
 
+/* Return whether EXPR should be treated as an atomic lvalue for the
+   purposes of load and store handling.  */
+
+static bool
+really_atomic_lvalue (tree expr)
+{
+  if (expr == error_mark_node || TREE_TYPE (expr) == error_mark_node)
+    return false;
+  if (!TYPE_ATOMIC (TREE_TYPE (expr)))
+    return false;
+  if (!lvalue_p (expr))
+    return false;
+
+  /* Ignore _Atomic on register variables, since their addresses can't
+     be taken so (a) atomicity is irrelevant and (b) the normal atomic
+     sequences wouldn't work.  Ignore _Atomic on structures containing
+     bit-fields, since accessing elements of atomic structures or
+     unions is undefined behavior (C11 6.5.2.3#5), but it's unclear if
+     it's undefined at translation time or execution time, and the
+     normal atomic sequences again wouldn't work.  */
+  while (handled_component_p (expr))
+    {
+      if (TREE_CODE (expr) == COMPONENT_REF
+	  && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
+	return false;
+      expr = TREE_OPERAND (expr, 0);
+    }
+  if (DECL_P (expr) && C_DECL_REGISTER (expr))
+    return false;
+  return true;
+}
+
+/* Convert expression EXP (location LOC) from lvalue to rvalue,
+   including converting functions and arrays to pointers if CONVERT_P.
+   If READ_P, also mark the expression as having been read.  */
+
+struct c_expr
+convert_lvalue_to_rvalue (location_t loc, struct c_expr exp,
+			  bool convert_p, bool read_p)
+{
+  if (read_p)
+    mark_exp_read (exp.value);
+  if (convert_p)
+    exp = default_function_array_conversion (loc, exp);
+  if (really_atomic_lvalue (exp.value))
+    {
+      vec<tree, va_gc> *params;
+      tree nonatomic_type, tmp, tmp_addr, fndecl, func_call;
+      tree expr_type = TREE_TYPE (exp.value);
+      tree expr_addr = build_unary_op (loc, ADDR_EXPR, exp.value, 0);
+      tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
+
+      gcc_assert (TYPE_ATOMIC (expr_type));
+
+      /* Expansion of a generic atomic load may require an addition
+	 element, so allocate enough to prevent a resize.  */
+      vec_alloc (params, 4);
+
+      /* Remove the qualifiers for the rest of the expressions and
+	 create the VAL temp variable to hold the RHS.  */
+      nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED);
+      tmp = create_tmp_var (nonatomic_type, NULL);
+      tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, 0);
+      TREE_ADDRESSABLE (tmp) = 1;
+
+      /* Issue __atomic_load (&expr, &tmp, SEQ_CST);  */
+      fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+      params->quick_push (expr_addr);
+      params->quick_push (tmp_addr);
+      params->quick_push (seq_cst);
+      func_call = build_function_call_vec (loc, fndecl, params, NULL);
+
+      /* Return tmp which contains the value loaded.  */
+      exp.value = build2 (COMPOUND_EXPR, nonatomic_type, func_call, tmp);
+    }
+  return exp;
+}
+
 /* EXP is an expression of integer type.  Apply the integer promotions
    to it and return the promoted value.  */
 
@@ -4855,7 +4933,7 @@  build_modify_expr (location_t location, tree lhs,
   if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign))
     return error_mark_node;
 
-  is_atomic_op = TYPE_ATOMIC (TREE_TYPE (lhs));
+  is_atomic_op = really_atomic_lvalue (lhs);
 
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     {
@@ -4968,9 +5046,11 @@  build_modify_expr (location_t location, tree lhs,
   if (is_atomic_op)
     {
       lhstype = build_qualified_type (lhstype, 
-				      TYPE_QUALS(lhstype) & ~TYPE_QUAL_ATOMIC);
+				      (TYPE_QUALS (lhstype)
+				       & ~TYPE_QUAL_ATOMIC));
       olhstype = build_qualified_type (olhstype, 
-				       TYPE_QUALS(lhstype) & ~TYPE_QUAL_ATOMIC);
+				       (TYPE_QUALS (lhstype)
+					& ~TYPE_QUAL_ATOMIC));
     }
 
   /* Convert new value to destination type.  Fold it first, then
@@ -8625,7 +8705,7 @@  build_asm_expr (location_t loc, tree string, tree
 	      struct c_expr expr;
 	      memset (&expr, 0, sizeof (expr));
 	      expr.value = input;
-	      expr = default_function_array_conversion (loc, expr);
+	      expr = convert_lvalue_to_rvalue (loc, expr, true, false);
 	      input = c_fully_fold (expr.value, false, NULL);
 
 	      if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input)))
@@ -11050,15 +11130,18 @@  c_build_va_arg (location_t loc, tree expr, tree ty
        T2 E2
        E1 op= E2
 
- This sequence is used for integer, floating point and complex types. 
+  This sequence is used for integer, floating-point and complex types. 
 
- In addition the 'fe' prefixed routines may need to be invoked for 
- floating point and complex when annex F is in effect (regarding floating
- point or exceptional conditions)  See 6.5.16.2 footnote 113:
+  In addition, built-in versions of the 'fe' prefixed routines may
+  need to be invoked for floating point and complex when annex F is in
+  effect (regarding floating point or exceptional conditions) See
+  6.5.16.2 footnote 113.
 
- TODO these are not implemented as yes, but the comments are placed at the
- correct locations in the code for the appropriate calls to be made.  They
- should only be issued if the expression type is !INTEGRAL_TYPE_P().
+  TODO these are not implemented as yet, but the comments are placed
+  at the correct locations in the code for the appropriate calls to be
+  made.  They should only be issued if the expression type (of either
+  LHS or RHS) is !INTEGRAL_TYPE_P ().  The type of the temporary for
+  the RHS must allow for any excess precision.
 
   T1 newval;
   T1 old;
@@ -11081,16 +11164,18 @@  done:
   feupdateenv (&fenv);				<<-- float & complex only
 
 
- Also note that the compiler is simply issuing the generic form of the atomic
- operations. This requires temp(s) and has their address taken.  The atomic
- processing is smart enough to figure out when the size of an object can
- utilize a lock free versionm, and convert the built-in call to the appropriate
- lockfree routine.  The optimizers will then dispose of any temps that are no
- longer required, and lock free implementations are utilized for integer, float
- and complex as long as there is target supoprt for the required size. 
+  Also note that the compiler is simply issuing the generic form of
+  the atomic operations.  This requires temp(s) and has their address
+  taken.  The atomic processing is smart enough to figure out when the
+  size of an object can utilize a lock free versionm, and convert the
+  built-in call to the appropriate lock-free routine.  The optimizers
+  will then dispose of any temps that are no longer required, and
+  lock-free implementations are utilized for integer, float and
+  complex as long as there is target supoprt for the required size.
 
- If the operator is NOP_EXPR, then this is a simple assignment, and an
- __atomic_store is issued to perform the assignment rather than the above loop.
+  If the operator is NOP_EXPR, then this is a simple assignment, and
+  an __atomic_store is issued to perform the assignment rather than
+  the above loop.
 
 */
 
@@ -11105,6 +11190,7 @@  build_atomic_assign (location_t loc, tree lhs, enu
   vec<tree, va_gc> *params;
   tree val, nonatomic_type, newval, newval_addr;
   tree old, old_addr;
+  tree compound_stmt;
   tree stmt, goto_stmt;
   tree loop_label, loop_decl, done_label, done_decl;
 
@@ -11114,9 +11200,13 @@  build_atomic_assign (location_t loc, tree lhs, enu
 
   gcc_assert (TYPE_ATOMIC (lhs_type));
 
-  /* allocate enough vector items for a compare_exchange.  */
+  /* Allocate enough vector items for a compare_exchange.  */
   vec_alloc (params, 6);
 
+  /* Create a compound statement to hold the sequence of statements
+     with a loop.  */
+  compound_stmt = c_begin_compound_stmt (false);
+
   /* 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);
@@ -11126,8 +11216,8 @@  build_atomic_assign (location_t loc, tree lhs, enu
   SET_EXPR_LOCATION (rhs, loc);
   add_stmt (rhs);
 
-  /* NOP_EXPR indicates its a straight store of the RHS. Simply issue
-     and atomic_store.  */
+  /* NOP_EXPR indicates it's a straight store of the RHS. Simply issue
+     an atomic_store.  */
   if (modifycode == NOP_EXPR)
     {
       /* Build __atomic_store (&lhs, &val, SEQ_CST)  */
@@ -11139,9 +11229,12 @@  build_atomic_assign (location_t loc, tree lhs, enu
       func_call = build_function_call_vec (loc, fndecl, params, NULL);
       add_stmt (func_call);
 
-      /* Val is the value which was stored, return it for any further value
-	 propagation.  */
-      return val;
+      /* Finish the compound statement.  */
+      compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
+
+      /* 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);
     }
 
   /* Create the variables and labels required for the op= form.  */
@@ -11209,44 +11302,10 @@  build_atomic_assign (location_t loc, tree lhs, enu
 
   /* TODO If (!integral) issue feupdateenv (&fenv)  */
 
-  /* Newval is the value that was successfully stored, return that.  */
-  return newval;
-}
+  /* Finish the compound statement.  */
+  compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
 
-
-/* This simply performs an atomic load from EXPR and returns the temp it was
-   loaded into.  */
-
-tree
-build_atomic_load (location_t loc, tree expr)
-{
-  vec<tree, va_gc> *params;
-  tree nonatomic_type, tmp, tmp_addr, fndecl, func_call;
-  tree expr_type = TREE_TYPE (expr);
-  tree expr_addr = build_unary_op (loc, ADDR_EXPR, expr, 0);
-  tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
-
-  gcc_assert (TYPE_ATOMIC (expr_type));
-
-  /* Expansion of a generic atomoic load may require an addition element, so
-     allocate enough to prevent a resize.  */
-  vec_alloc (params, 4);
-
-  /* Remove the qualifiers for the rest of the expressions and create
-     the VAL temp variable to hold the RHS.  */
-  nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED);
-  tmp = create_tmp_var (nonatomic_type, NULL);
-  tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, 0);
-  TREE_ADDRESSABLE (tmp) = 1;
-
-  /* Issue __atomic_load (&expr, &tmp, SEQ_CST);  */
-  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
-  params->quick_push (expr_addr);
-  params->quick_push (tmp_addr);
-  params->quick_push (seq_cst);
-  func_call = build_function_call_vec (loc, fndecl, params, NULL);
-  add_stmt (func_call);
-
-  /* return tmp which contains the value loaded,  */
-  return tmp;
+  /* 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);
 }
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	(revision 203707)
+++ gcc/c/c-tree.h	(working copy)
@@ -163,7 +163,7 @@  enum c_typespec_kind {
   ctsk_typedef,
   /* An ObjC-specific kind of type specifier.  */
   ctsk_objc,
-  /* A typeof specifier.  */
+  /* A typeof specifier, or _Atomic ( type-name ).  */
   ctsk_typeof
 };
 
@@ -585,6 +585,8 @@  extern struct c_expr default_function_array_conver
 							struct c_expr);
 extern struct c_expr default_function_array_read_conversion (location_t,
 							     struct c_expr);
+extern struct c_expr convert_lvalue_to_rvalue (location_t, struct c_expr,
+					       bool, bool);
 extern void mark_exp_read (tree);
 extern tree composite_type (tree, tree);
 extern tree build_component_ref (location_t, tree, tree);
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 203707)
+++ gcc/c/c-decl.c	(working copy)
@@ -4772,6 +4772,15 @@  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
@@ -5661,18 +5670,24 @@  grokdeclarator (const struct c_declarator *declara
 	  }
 	case cdk_pointer:
 	  {
-	    if (atomicp)
+	    /* Merge any constancy or volatility into the target type
+	       for the pointer.  */
+	    if ((type_quals & TYPE_QUAL_ATOMIC)
+		&& TREE_CODE (type) == FUNCTION_TYPE)
 	      {
 		error_at (loc,
-			  "ISO C forbids _Atomic qualifier function types");
-		type = error_mark_node;
-		break;
+			  "%<_Atomic%>-qualified function type");
+		type_quals &= ~TYPE_QUAL_ATOMIC;
 	      }
-
-	    /* Merge any constancy or volatility into the target type
-	       for the pointer.  */
-	    if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-		&& type_quals)
+	    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,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
@@ -5849,8 +5864,22 @@  grokdeclarator (const struct c_declarator *declara
   if (storage_class == csc_typedef)
     {
       tree decl;
-      if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-	  && type_quals)
+      if ((type_quals & TYPE_QUAL_ATOMIC)
+	  && TREE_CODE (type) == FUNCTION_TYPE)
+	{
+	  error_at (loc,
+		    "%<_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,
 		 "ISO C forbids qualified function types");
       if (type_quals)
@@ -5895,8 +5924,22 @@  grokdeclarator (const struct c_declarator *declara
 	 and fields.  */
       gcc_assert (storage_class == csc_none && !threadp
 		  && !declspecs->inline_p && !declspecs->noreturn_p);
-      if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-	  && type_quals)
+      if ((type_quals & TYPE_QUAL_ATOMIC)
+	  && TREE_CODE (type) == FUNCTION_TYPE)
+	{
+	  error_at (loc,
+		    "%<_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,
 		 "ISO C forbids const or volatile function types");
       if (type_quals)
@@ -5944,6 +5987,12 @@  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)
@@ -5962,7 +6011,13 @@  grokdeclarator (const struct c_declarator *declara
 	  }
 	else if (TREE_CODE (type) == FUNCTION_TYPE)
 	  {
-	    if (type_quals)
+	    if (type_quals & TYPE_QUAL_ATOMIC)
+	      {
+		error_at (loc,
+			  "%<_Atomic%>-qualified function type");
+		type_quals &= ~TYPE_QUAL_ATOMIC;
+	      }
+	    else if (type_quals)
 	      pedwarn (loc, OPT_Wpedantic,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
@@ -6017,6 +6072,12 @@  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);
@@ -6057,7 +6118,13 @@  grokdeclarator (const struct c_declarator *declara
 			   FUNCTION_DECL, declarator->u.id, type);
 	decl = build_decl_attribute_variant (decl, decl_attr);
 
-	if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
+	if (type_quals & TYPE_QUAL_ATOMIC)
+	  {
+	    error_at (loc,
+		      "%<_Atomic%>-qualified function type");
+	    type_quals &= ~TYPE_QUAL_ATOMIC;
+	  }
+	else if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
 	  pedwarn (loc, OPT_Wpedantic,
 		   "ISO C forbids qualified function types");
 
@@ -6126,6 +6193,12 @@  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