aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorJoseph Myers <jsm28@gcc.gnu.org>2013-11-07 21:15:25 +0000
committerJoseph Myers <jsm28@gcc.gnu.org>2013-11-07 21:15:25 +0000
commit267bac1078ce623767a9effa063d5b63fbbeb6ca (patch)
treeb7c9a4da58703fc4f909e241272dfbc85c92459e /gcc/c
parent07cb5010c806d4d41d4ecf06acab9306a3d4cdc6 (diff)
downloadgcc-267bac1078ce623767a9effa063d5b63fbbeb6ca.zip
gcc-267bac1078ce623767a9effa063d5b63fbbeb6ca.tar.gz
gcc-267bac1078ce623767a9effa063d5b63fbbeb6ca.tar.bz2
tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC.
gcc: 2013-11-05 Andrew MacLeod <amacleod@redhat.com> Joseph Myers <joseph@codesourcery.com> * tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC. (enum tree_index): Add TI_ATOMICQI_TYPE, TI_ATOMICHI_TYPE, TI_ATOMICSI_TYPE, TI_ATOMICDI_TYPE and TI_ATOMICTI_TYPE. (struct tree_base): Add atomic_flag field. * tree.h (TYPE_ATOMIC): New accessor macro. (TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE): Add TYPE_QUAL_ATOMIC. (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC): New macro. (atomicQI_type_node, atomicHI_type_node, atomicSI_type_node) (atomicDI_type_node, atomicTI_type_node): New macros for type nodes. * tree.c (set_type_quals): Set TYPE_ATOMIC. (find_atomic_core_type): New function. (build_qualified_type): Adjust alignment for qualified types. (build_atomic_base): New function (build_common_tree_nodes): Build atomicQI_type_node, atomicHI_type_node, atomicSI_type_node, atomicDI_type_node and atomicTI_type_node. * print-tree.c (print_node): Print atomic qualifier. * tree-pretty-print.c (dump_generic_node): Print atomic type attribute. * target.def (atomic_assign_expand_fenv): New hook. * doc/tm.texi.in (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New @hook. * doc/tm.texi: Regenerate. * targhooks.c (default_atomic_assign_expand_fenv): New function. * targhooks.h (default_atomic_assign_expand_fenv): Declare. * sync-builtins.def (__atomic_feraiseexcept): New built-in function. * config/i386/i386-builtin-types.def (VOID_FTYPE_PUSHORT): New function type. * config/i386/i386.c (enum ix86_builtins): Add IX86_BUILTIN_FNSTENV, IX86_BUILTIN_FLDENV, IX86_BUILTIN_FNSTSW and IX86_BUILTIN_FNCLEX. (bdesc_special_args): Add __builtin_ia32_fnstenv, __builtin_ia32_fldenv, __builtin_ia32_fnstsw and __builtin_ia32_fnclex. (ix86_expand_builtin): Handle the new built-in functions. (ix86_atomic_assign_expand_fenv): New function. (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New macro. * config/i386/i386.md (UNSPECV_FNSTENV, UNSPECV_FLDENV) (UNSPECV_FNSTSW, UNSPECV_FNCLEX): New unspecs. (fnstenv, fldenv, fnstsw, fnclex): New insns. gcc/c-family: 2013-11-05 Andrew MacLeod <amacleod@redhat.com> Joseph Myers <joseph@codesourcery.com> * c-common.h (enum rid): Add RID_ATOMIC. * c-common.c (c_common_reswords): Add _Atomic. (sync_resolve_params): Use TYPE_MAIN_VARIANT on pointer argument. (keyword_is_type_qualifier): Accept RID_ATOMIC. * c-format.c (check_format_types): Check for extra _Atomic qualifiers in format argument. * c-pretty-print.c (pp_c_cv_qualifiers): Handle atomic qualifier. (pp_c_type_qualifier_list): Mention _Atomic in comment. gcc/c: 2013-11-05 Joseph Myers <joseph@codesourcery.com> Andrew MacLeod <amacleod@redhat.com> * c-aux-info.c (gen_type): Handle atomic qualifier. * c-decl.c (validate_proto_after_old_defn): Do not remove atomic qualifiers when compating types. (shadow_tag_warned): Handle atomic_p in declspecs. (quals_from_declspecs): Likewise. (start_decl): Use c_type_promotes_to when promoting argument types. (grokdeclarator): Handle _Atomic. (get_parm_info): Diagnose any qualifier on "void" as only parameter. (store_parm_decls_oldstyle): Do not remove atomic qualifiers when comparing types. Use c_type_promotes_to when promoting argument types. (finish_function): Use c_type_promotes_to when promoting argument types. (build_null_declspecs): Handle atomic_p in declspecs. (declspecs_add_qual): Handle RID_ATOMIC. * c-parser.c (c_token_starts_typename, c_token_is_qualifier) (c_token_starts_declspecs): Handle RID_ATOMIC. (c_parser_declspecs): Handle atomic type specifiers and qualifiers. (c_parser_typeof_specifier): Remove const and _Atomic qualifiers from types of expressions with atomic type. (c_parser_direct_declarator_inner): Use convert_lvalue_to_rvalue. (c_parser_attribute_any_word): Handle RID_ATOMIC. (c_parser_initializer, c_parser_initelt, c_parser_initval) (c_parser_statement_after_labels, c_parser_switch_statement) (c_parser_for_statement, c_parser_expr_no_commas) (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_synchronized_statement): Use convert_lvalue_to_rvalue. (c_parser_objc_selector): Handle RID_ATOMIC. (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). (struct c_declspecs): Add atomic_p field. (convert_lvalue_to_rvalue): Declare. * c-typeck.c (c_type_promotes_to): Promote atomic types to corresponding atomic types. (qualify_type): Don't add _Atomic qualifiers from second argument. (comp_target_types): Do not allow _Atomic mismatches. (type_lists_compatible_p): Do not remove atomic qualifiers when comparing types. (really_atomic_lvalue, convert_lvalue_to_rvalue) (build_atomic_assign): New functions. (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): Use build_atomic_assign for atomic LHS. (find_anonymous_field_with_type, convert_to_anonymous_field) (convert_for_assignment): Do not remove atomic qualifiers when comparing types. (digest_init): Do not accept initialization of arrays of atomic elements by string constants. (build_asm_expr): Use convert_lvalue_to_rvalue. (build_binary_op): Do not treat _Atomic void as a qualified version of void. gcc/objc: 2013-11-05 Andrew MacLeod <amacleod@redhat.com> * objc-act.c (objc_push_parm): Handle atomic qualifier. gcc/testsuite: 2013-11-05 Joseph Myers <joseph@codesourcery.com> * lib/target-supports.exp (check_effective_target_fenv_exceptions): New function. * lib/atomic-dg.exp, gcc.dg/atomic/atomic.exp: New files. * gcc.dg/atomic/c11-atomic-exec-1.c, gcc.dg/atomic/c11-atomic-exec-2.c, gcc.dg/atomic/c11-atomic-exec-3.c, gcc.dg/atomic/c11-atomic-exec-4.c, gcc.dg/atomic/c11-atomic-exec-5.c, gcc.dg/c11-atomic-1.c, gcc.dg/c11-atomic-2.c, gcc.dg/c11-atomic-3.c, gcc.dg/c90-atomic-1.c, gcc.dg/c99-atomic-1.c: New tests. libatomic: 2013-11-05 Joseph Myers <joseph@codesourcery.com> * fenv.c: New file. * libatomic.map (LIBATOMIC_1.1): New symbol version. Include __atomic_feraiseexcept. * configure.ac (libtool_VERSION): Change to 2:0:1. (fenv.h): Test for header. * Makefile.am (libatomic_la_SOURCES): Add fenv.c. * Makefile.in, auto-config.h.in, configure: Regenerate. From-SVN: r204544
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog69
-rw-r--r--gcc/c/c-aux-info.c4
-rw-r--r--gcc/c/c-decl.c118
-rw-r--r--gcc/c/c-parser.c227
-rw-r--r--gcc/c/c-tree.h6
-rw-r--r--gcc/c/c-typeck.c513
6 files changed, 797 insertions, 140 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index cc335e4..e38bcb8 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,72 @@
+2013-11-07 Joseph Myers <joseph@codesourcery.com>
+ Andrew MacLeod <amacleod@redhat.com>
+
+ * c-aux-info.c (gen_type): Handle atomic qualifier.
+ * c-decl.c (validate_proto_after_old_defn): Do not remove atomic
+ qualifiers when compating types.
+ (shadow_tag_warned): Handle atomic_p in declspecs.
+ (quals_from_declspecs): Likewise.
+ (start_decl): Use c_type_promotes_to when promoting argument
+ types.
+ (grokdeclarator): Handle _Atomic.
+ (get_parm_info): Diagnose any qualifier on "void" as only
+ parameter.
+ (store_parm_decls_oldstyle): Do not remove atomic qualifiers when
+ comparing types. Use c_type_promotes_to when promoting argument
+ types.
+ (finish_function): Use c_type_promotes_to when promoting argument
+ types.
+ (build_null_declspecs): Handle atomic_p in declspecs.
+ (declspecs_add_qual): Handle RID_ATOMIC.
+ * c-parser.c (c_token_starts_typename, c_token_is_qualifier)
+ (c_token_starts_declspecs): Handle RID_ATOMIC.
+ (c_parser_declspecs): Handle atomic type specifiers and
+ qualifiers.
+ (c_parser_typeof_specifier): Remove const and _Atomic qualifiers
+ from types of expressions with atomic type.
+ (c_parser_direct_declarator_inner): Use convert_lvalue_to_rvalue.
+ (c_parser_attribute_any_word): Handle RID_ATOMIC.
+ (c_parser_initializer, c_parser_initelt, c_parser_initval)
+ (c_parser_statement_after_labels, c_parser_switch_statement)
+ (c_parser_for_statement, c_parser_expr_no_commas)
+ (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_synchronized_statement): Use
+ convert_lvalue_to_rvalue.
+ (c_parser_objc_selector): Handle RID_ATOMIC.
+ (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).
+ (struct c_declspecs): Add atomic_p field.
+ (convert_lvalue_to_rvalue): Declare.
+ * c-typeck.c (c_type_promotes_to): Promote atomic types to
+ corresponding atomic types.
+ (qualify_type): Don't add _Atomic qualifiers from second argument.
+ (comp_target_types): Do not allow _Atomic mismatches.
+ (type_lists_compatible_p): Do not remove atomic qualifiers when
+ comparing types.
+ (really_atomic_lvalue, convert_lvalue_to_rvalue)
+ (build_atomic_assign): New functions.
+ (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): Use build_atomic_assign for atomic LHS.
+ (find_anonymous_field_with_type, convert_to_anonymous_field)
+ (convert_for_assignment): Do not remove atomic qualifiers when
+ comparing types.
+ (digest_init): Do not accept initialization of arrays of atomic
+ elements by string constants.
+ (build_asm_expr): Use convert_lvalue_to_rvalue.
+ (build_binary_op): Do not treat _Atomic void as a qualified
+ version of void.
+
2013-11-06 DJ Delorie <dj@redhat.com>
* c-decl.c (locate_old_decl): If a previous conflicting decl is
diff --git a/gcc/c/c-aux-info.c b/gcc/c/c-aux-info.c
index dd9c768..823a3c4 100644
--- a/gcc/c/c-aux-info.c
+++ b/gcc/c/c-aux-info.c
@@ -285,6 +285,8 @@ gen_type (const char *ret_val, tree t, formals_style style)
switch (TREE_CODE (t))
{
case POINTER_TYPE:
+ if (TYPE_ATOMIC (t))
+ ret_val = concat ("_Atomic ", ret_val, NULL);
if (TYPE_READONLY (t))
ret_val = concat ("const ", ret_val, NULL);
if (TYPE_VOLATILE (t))
@@ -425,6 +427,8 @@ gen_type (const char *ret_val, tree t, formals_style style)
gcc_unreachable ();
}
}
+ if (TYPE_ATOMIC (t))
+ ret_val = concat ("_Atomic ", ret_val, NULL);
if (TYPE_READONLY (t))
ret_val = concat ("const ", ret_val, NULL);
if (TYPE_VOLATILE (t))
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 23f0516..9520e4d 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1584,8 +1584,14 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
if (oldargtype == error_mark_node || newargtype == error_mark_node)
return false;
- oldargtype = TYPE_MAIN_VARIANT (oldargtype);
- newargtype = TYPE_MAIN_VARIANT (newargtype);
+ oldargtype = (TYPE_ATOMIC (oldargtype)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (oldargtype),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (oldargtype));
+ newargtype = (TYPE_ATOMIC (newargtype)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (newargtype),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (newargtype));
if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype))
break;
@@ -3715,6 +3721,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
&& declspecs->typespec_kind != ctsk_tagfirstref
&& (declspecs->const_p
|| declspecs->volatile_p
+ || declspecs->atomic_p
|| declspecs->restrict_p
|| declspecs->address_space))
{
@@ -3804,6 +3811,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
if (!warned && !in_system_header && (declspecs->const_p
|| declspecs->volatile_p
+ || declspecs->atomic_p
|| declspecs->restrict_p
|| declspecs->address_space))
{
@@ -3835,6 +3843,7 @@ quals_from_declspecs (const struct c_declspecs *specs)
int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0)
| (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
| (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)
+ | (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0)
| (ENCODE_QUAL_ADDR_SPACE (specs->address_space)));
gcc_assert (!specs->type
&& !specs->decl_attr
@@ -4170,7 +4179,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
tree type = TREE_TYPE (args);
if (type && INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
- DECL_ARG_TYPE (args) = integer_type_node;
+ DECL_ARG_TYPE (args) = c_type_promotes_to (type);
}
}
}
@@ -4943,6 +4952,7 @@ grokdeclarator (const struct c_declarator *declarator,
int constp;
int restrictp;
int volatilep;
+ int atomicp;
int type_quals = TYPE_UNQUALIFIED;
tree name = NULL_TREE;
bool funcdef_flag = false;
@@ -5097,6 +5107,7 @@ grokdeclarator (const struct c_declarator *declarator,
constp = declspecs->const_p + TYPE_READONLY (element_type);
restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type);
volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type);
+ atomicp = declspecs->atomic_p + TYPE_ATOMIC (element_type);
as1 = declspecs->address_space;
as2 = TYPE_ADDR_SPACE (element_type);
address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1;
@@ -5109,6 +5120,9 @@ grokdeclarator (const struct c_declarator *declarator,
pedwarn (loc, OPT_Wpedantic, "duplicate %<restrict%>");
if (volatilep > 1)
pedwarn (loc, OPT_Wpedantic, "duplicate %<volatile%>");
+ if (atomicp > 1)
+ pedwarn (loc, OPT_Wpedantic, "duplicate %<_Atomic%>");
+
}
if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2)
@@ -5122,8 +5136,16 @@ grokdeclarator (const struct c_declarator *declarator,
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 0)
+ | (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.). */
@@ -5699,9 +5721,15 @@ grokdeclarator (const struct c_declarator *declarator,
{
/* Merge any constancy or volatility into the target type
for the pointer. */
-
- 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 (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+ && type_quals)
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids qualified function types");
if (type_quals)
@@ -5815,7 +5843,20 @@ grokdeclarator (const struct c_declarator *declarator,
/* Check the type and width of a bit-field. */
if (bitfield)
- check_bitfield_type_and_width (&type, width, name);
+ {
+ check_bitfield_type_and_width (&type, width, name);
+ /* C11 makes it implementation-defined (6.7.2.1#5) whether
+ atomic types are permitted for bit-fields; we have no code to
+ make bit-field accesses atomic, so disallow them. */
+ if (type_quals & TYPE_QUAL_ATOMIC)
+ {
+ if (name)
+ error ("bit-field %qE has atomic type", name);
+ else
+ error ("bit-field has atomic type");
+ type_quals &= ~TYPE_QUAL_ATOMIC;
+ }
+ }
/* Reject invalid uses of _Alignas. */
if (declspecs->alignas_p)
@@ -5878,8 +5919,15 @@ grokdeclarator (const struct c_declarator *declarator,
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 (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+ && type_quals)
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids qualified function types");
if (type_quals)
@@ -5924,8 +5972,15 @@ grokdeclarator (const struct c_declarator *declarator,
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 (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+ && type_quals)
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids const or volatile function types");
if (type_quals)
@@ -5991,7 +6046,13 @@ grokdeclarator (const struct c_declarator *declarator,
}
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)
@@ -6086,7 +6147,13 @@ grokdeclarator (const struct c_declarator *declarator,
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");
@@ -6459,8 +6526,7 @@ get_parm_info (bool ellipsis, tree expr)
&& !DECL_NAME (b->decl) /* anonymous */
&& VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */
{
- if (TREE_THIS_VOLATILE (b->decl)
- || TREE_READONLY (b->decl)
+ if (TYPE_QUALS (TREE_TYPE (b->decl)) != TYPE_UNQUALIFIED
|| C_DECL_REGISTER (b->decl))
error ("%<void%> as only parameter may not be qualified");
@@ -8213,11 +8279,15 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
type for parameters declared with qualified type. */
if (TREE_TYPE (parm) != error_mark_node
&& TREE_TYPE (type) != error_mark_node
- && !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
- TYPE_MAIN_VARIANT (TREE_VALUE (type))))
+ && ((TYPE_ATOMIC (DECL_ARG_TYPE (parm))
+ != TYPE_ATOMIC (TREE_VALUE (type)))
+ || !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
+ TYPE_MAIN_VARIANT (TREE_VALUE (type)))))
{
- if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
- == TYPE_MAIN_VARIANT (TREE_VALUE (type)))
+ if ((TYPE_ATOMIC (DECL_ARG_TYPE (parm))
+ == TYPE_ATOMIC (TREE_VALUE (type)))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
+ == TYPE_MAIN_VARIANT (TREE_VALUE (type))))
{
/* Adjust argument to match prototype. E.g. a previous
`int foo(float);' prototype causes
@@ -8230,7 +8300,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
&& INTEGRAL_TYPE_P (TREE_TYPE (parm))
&& TYPE_PRECISION (TREE_TYPE (parm))
< TYPE_PRECISION (integer_type_node))
- DECL_ARG_TYPE (parm) = integer_type_node;
+ DECL_ARG_TYPE (parm)
+ = c_type_promotes_to (TREE_TYPE (parm));
/* ??? Is it possible to get here with a
built-in prototype or will it always have
@@ -8432,7 +8503,7 @@ finish_function (void)
tree type = TREE_TYPE (args);
if (INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
- DECL_ARG_TYPE (args) = integer_type_node;
+ DECL_ARG_TYPE (args) = c_type_promotes_to (type);
}
}
@@ -8911,6 +8982,7 @@ build_null_declspecs (void)
ret->thread_p = false;
ret->const_p = false;
ret->volatile_p = false;
+ ret->atomic_p = false;
ret->restrict_p = false;
ret->saturating_p = false;
ret->alignas_p = false;
@@ -8972,6 +9044,10 @@ declspecs_add_qual (source_location loc,
specs->restrict_p = true;
specs->locations[cdw_restrict] = loc;
break;
+ case RID_ATOMIC:
+ dupe = specs->atomic_p;
+ specs->atomic_p = true;
+ break;
default:
gcc_unreachable ();
}
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 4ae30c3..09cce1c 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -494,6 +494,7 @@ c_token_starts_typename (c_token *token)
case RID_UNION:
case RID_TYPEOF:
case RID_CONST:
+ case RID_ATOMIC:
case RID_VOLATILE:
case RID_RESTRICT:
case RID_ATTRIBUTE:
@@ -576,6 +577,7 @@ c_token_is_qualifier (c_token *token)
case RID_VOLATILE:
case RID_RESTRICT:
case RID_ATTRIBUTE:
+ case RID_ATOMIC:
return true;
default:
return false;
@@ -656,6 +658,7 @@ c_token_starts_declspecs (c_token *token)
case RID_ACCUM:
case RID_SAT:
case RID_ALIGNAS:
+ case RID_ATOMIC:
return true;
default:
return false;
@@ -1991,8 +1994,10 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
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:
@@ -2001,8 +2006,10 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
restrict
volatile
address-space-qualifier
+ _Atomic
(restrict is new in C99.)
+ (_Atomic is new in C11.)
GNU extensions:
@@ -2031,6 +2038,9 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
(_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:
@@ -2224,6 +2234,64 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
t = c_parser_typeof_specifier (parser);
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, and that in build_unary_op handling
+ Objective-C cases for increment / decrement, also needs
+ updating; uses of TYPE_MAIN_VARIANT in objc_compare_types
+ and objc_types_are_equivalent may also need updates. */
+ 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 the %<_Atomic%> qualifier");
+ else
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C90 does not support the %<_Atomic%> qualifier");
+ }
+ 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:
@@ -2826,6 +2894,16 @@ 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_ATOMIC (ret.spec))
+ 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;
@@ -3114,7 +3192,10 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
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,
false, cla_prefer_id);
@@ -3132,19 +3213,19 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
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");
@@ -3154,20 +3235,20 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
{
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))
@@ -3186,9 +3267,9 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
"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;
@@ -3558,6 +3639,7 @@ c_parser_attribute_any_word (c_parser *parser)
case RID_SAT:
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_CANCEL:
+ case RID_ATOMIC:
ok = true;
break;
default:
@@ -3814,7 +3896,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;
}
}
@@ -3993,8 +4075,8 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_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:
@@ -4090,7 +4172,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
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);
}
@@ -4605,12 +4687,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 %<*%>");
@@ -4659,9 +4741,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;
@@ -4873,6 +4956,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;
@@ -4882,7 +4966,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,
@@ -5135,8 +5221,10 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
{
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))
{
@@ -5148,6 +5236,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
}
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 %<;%>");
}
@@ -5208,7 +5298,11 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
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 %<)%>");
}
@@ -5565,7 +5659,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
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,
@@ -5609,7 +5703,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
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))
{
@@ -5657,7 +5751,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
{
location_t exp2_loc = c_parser_peek_token (parser)->location;
exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE);
- 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,
@@ -5801,11 +5895,11 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
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); \
if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \
&& c_parser_peek_token (parser)->type == CPP_SEMICOLON \
&& ((1 << stack[sp].prec) \
@@ -5924,8 +6018,8 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
{
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
@@ -5933,8 +6027,8 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
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
@@ -6005,7 +6099,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
{
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;
@@ -6096,7 +6190,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:
@@ -6107,25 +6201,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. */
@@ -6918,10 +7012,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 %<]%>");
@@ -7044,11 +7141,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));
@@ -7096,7 +7193,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 =
@@ -7440,7 +7537,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
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
@@ -7518,8 +7615,11 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
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;
@@ -7534,7 +7634,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;
@@ -7542,8 +7642,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)
@@ -7551,12 +7651,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
@@ -7586,7 +7687,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
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);
@@ -7610,7 +7711,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
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);
@@ -8516,7 +8617,9 @@ c_parser_objc_synchronized_statement (c_parser *parser)
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 %<)%>");
}
@@ -8536,6 +8639,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
break continue return goto asm sizeof typeof __alignof
unsigned long const short volatile signed restrict _Complex
in out inout bycopy byref oneway int char float double void _Bool
+ _Atomic
??? Why this selection of keywords but not, for example, storage
class specifiers? */
@@ -8594,6 +8698,7 @@ c_parser_objc_selector (c_parser *parser)
case RID_DOUBLE:
case RID_VOID:
case RID_BOOL:
+ case RID_ATOMIC:
c_parser_consume_token (parser);
return value;
default:
@@ -8646,6 +8751,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))
@@ -8654,7 +8761,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.
@@ -13441,7 +13550,9 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
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);
@@ -13450,7 +13561,9 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
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);
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 2565ccb..8dffa9c 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -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
};
@@ -328,6 +328,8 @@ struct c_declspecs {
BOOL_BITFIELD volatile_p : 1;
/* Whether "restrict" was specified. */
BOOL_BITFIELD restrict_p : 1;
+ /* Whether "_Atomic" was specified. */
+ BOOL_BITFIELD atomic_p : 1;
/* Whether "_Sat" was specified. */
BOOL_BITFIELD saturating_p : 1;
/* Whether any alignment specifier (even with zero alignment) was
@@ -585,6 +587,8 @@ extern struct c_expr default_function_array_conversion (location_t,
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);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 8f1d3a4..5ef1f93 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -265,18 +265,25 @@ c_incomplete_type_error (const_tree value, const_tree type)
tree
c_type_promotes_to (tree type)
{
- if (TYPE_MAIN_VARIANT (type) == float_type_node)
- return double_type_node;
+ tree ret = NULL_TREE;
- if (c_promoting_integer_type_p (type))
+ if (TYPE_MAIN_VARIANT (type) == float_type_node)
+ ret = double_type_node;
+ else if (c_promoting_integer_type_p (type))
{
/* Preserve unsignedness if not really getting any wider. */
if (TYPE_UNSIGNED (type)
&& (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
- return unsigned_type_node;
- return integer_type_node;
+ ret = unsigned_type_node;
+ else
+ ret = integer_type_node;
}
+ if (ret != NULL_TREE)
+ return (TYPE_ATOMIC (type)
+ ? c_build_qualified_type (ret, TYPE_QUAL_ATOMIC)
+ : ret);
+
return type;
}
@@ -327,7 +334,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 +1221,13 @@ comp_target_types (location_t location, tree ttl, tree ttr)
/* 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);
@@ -1633,9 +1644,15 @@ type_lists_compatible_p (const_tree args1, const_tree args2,
mv1 = a1 = TREE_VALUE (args1);
mv2 = a2 = TREE_VALUE (args2);
if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
- mv1 = TYPE_MAIN_VARIANT (mv1);
+ mv1 = (TYPE_ATOMIC (mv1)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv1),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mv1));
if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
- mv2 = TYPE_MAIN_VARIANT (mv2);
+ mv2 = (TYPE_ATOMIC (mv2)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv2),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mv2));
/* A null pointer instead of a type
means there is supposed to be an argument
but nothing is specified about what type it has.
@@ -1678,7 +1695,10 @@ type_lists_compatible_p (const_tree args1, const_tree args2,
tree mv3 = TREE_TYPE (memb);
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
- mv3 = TYPE_MAIN_VARIANT (mv3);
+ mv3 = (TYPE_ATOMIC (mv3)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mv3));
if (comptypes_internal (mv3, mv2, enum_and_int_p,
different_types_p))
break;
@@ -1700,7 +1720,10 @@ type_lists_compatible_p (const_tree args1, const_tree args2,
tree mv3 = TREE_TYPE (memb);
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
- mv3 = TYPE_MAIN_VARIANT (mv3);
+ mv3 = (TYPE_ATOMIC (mv3)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mv3));
if (comptypes_internal (mv3, mv1, enum_and_int_p,
different_types_p))
break;
@@ -1913,6 +1936,84 @@ default_function_array_read_conversion (location_t loc, struct c_expr exp)
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. */
@@ -3435,6 +3536,215 @@ pointer_diff (location_t loc, tree op0, tree op1)
return convert (restype, result);
}
+/* Expand atomic compound assignments into an approriate sequence as
+ specified by the C11 standard section 6.5.16.2.
+ given
+ _Atomic T1 E1
+ T2 E2
+ E1 op= E2
+
+ This sequence is used for all types for which these operations are
+ supported.
+
+ In addition, built-in versions of the 'fe' prefixed routines may
+ need to be invoked for floating point (real, complex or vector) when
+ floating-point exceptions are supported. See 6.5.16.2 footnote 113.
+
+ T1 newval;
+ T1 old;
+ T1 *addr
+ T2 val
+ fenv_t fenv
+
+ addr = &E1;
+ val = (E2);
+ __atomic_load (addr, &old, SEQ_CST);
+ feholdexcept (&fenv);
+loop:
+ newval = old op val;
+ if (__atomic_compare_exchange_strong (addr, &old, &newval, SEQ_CST,
+ SEQ_CST))
+ goto done;
+ feclearexcept (FE_ALL_EXCEPT);
+ goto loop:
+done:
+ feupdateenv (&fenv);
+
+ 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 version, 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 as long as there is target
+ support 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.
+
+*/
+
+/* 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, bool return_old_p)
+{
+ tree fndecl, func_call;
+ vec<tree, va_gc> *params;
+ tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr;
+ tree old, old_addr;
+ tree compound_stmt;
+ tree stmt, goto_stmt;
+ tree loop_label, loop_decl, done_label, done_decl;
+
+ 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);
+
+ /* Create a compound statement to hold the sequence of statements
+ with a loop. */
+ compound_stmt = c_begin_compound_stmt (false);
+
+ /* Fold the RHS if it hasn't already been folded. */
+ if (modifycode != NOP_EXPR)
+ rhs = c_fully_fold (rhs, false, NULL);
+
+ /* Remove the qualifiers for the rest of the expressions and create
+ the VAL temp variable to hold the RHS. */
+ 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_rhs_type, val, rhs);
+ SET_EXPR_LOCATION (rhs, loc);
+ add_stmt (rhs);
+
+ /* 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) */
+ rhs = build_unary_op (loc, ADDR_EXPR, val, 0);
+ fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE);
+ params->quick_push (lhs_addr);
+ params->quick_push (rhs);
+ params->quick_push (seq_cst);
+ func_call = build_function_call_vec (loc, fndecl, params, NULL);
+ add_stmt (func_call);
+
+ /* 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_lhs_type, compound_stmt, val);
+ }
+
+ /* Create the variables and labels required for the op= form. */
+ 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_lhs_type, NULL);
+ newval_addr = build_unary_op (loc, ADDR_EXPR, newval, 0);
+ TREE_ADDRESSABLE (newval) = 1;
+
+ loop_decl = create_artificial_label (loc);
+ loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl);
+
+ done_decl = create_artificial_label (loc);
+ done_label = build1 (LABEL_EXPR, void_type_node, done_decl);
+
+ /* __atomic_load (addr, &old, SEQ_CST). */
+ fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+ params->quick_push (lhs_addr);
+ params->quick_push (old_addr);
+ params->quick_push (seq_cst);
+ func_call = build_function_call_vec (loc, fndecl, params, NULL);
+ add_stmt (func_call);
+ params->truncate (0);
+
+ /* Create the expressions for floating-point environment
+ manipulation, if required. */
+ bool need_fenv = (flag_trapping_math
+ && (FLOAT_TYPE_P (lhs_type) || FLOAT_TYPE_P (rhs_type)));
+ tree hold_call = NULL_TREE, clear_call = NULL_TREE, update_call = NULL_TREE;
+ if (need_fenv)
+ targetm.atomic_assign_expand_fenv (&hold_call, &clear_call, &update_call);
+
+ if (hold_call)
+ add_stmt (hold_call);
+
+ /* loop: */
+ add_stmt (loop_label);
+
+ /* newval = old + val; */
+ rhs = build_binary_op (loc, modifycode, old, val, 1);
+ 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; */
+ fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE);
+ params->quick_push (lhs_addr);
+ params->quick_push (old_addr);
+ params->quick_push (newval_addr);
+ params->quick_push (integer_zero_node);
+ params->quick_push (seq_cst);
+ params->quick_push (seq_cst);
+ func_call = build_function_call_vec (loc, fndecl, params, NULL);
+
+ goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl);
+ SET_EXPR_LOCATION (goto_stmt, loc);
+
+ stmt = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+
+ if (clear_call)
+ add_stmt (clear_call);
+
+ /* goto loop; */
+ goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl);
+ SET_EXPR_LOCATION (goto_stmt, loc);
+ add_stmt (goto_stmt);
+
+ /* done: */
+ add_stmt (done_label);
+
+ if (update_call)
+ add_stmt (update_call);
+
+ /* 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 the appropriate value. */
+ return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt,
+ return_old_p ? old : newval);
+}
+
/* Construct and perhaps optimize a tree representation
for a unary operation. CODE, a tree_code, specifies the operation
and XARG is the operand.
@@ -3635,6 +3945,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)
@@ -3644,21 +3957,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");
@@ -3749,6 +4066,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
@@ -4259,7 +4594,8 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
"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,
@@ -4268,7 +4604,8 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
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,
@@ -4850,6 +5187,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
bool npc;
+ bool is_atomic_op;
/* Types that aren't fully specified cannot be used in assignments. */
lhs = require_complete_type (lhs);
@@ -4862,6 +5200,8 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign))
return error_mark_node;
+ is_atomic_op = really_atomic_lvalue (lhs);
+
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
{
rhs_semantic_type = TREE_TYPE (rhs);
@@ -4892,12 +5232,17 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
{
lhs = c_fully_fold (lhs, false, NULL);
lhs = stabilize_reference (lhs);
- newrhs = build_binary_op (location,
- modifycode, lhs, rhs, 1);
- /* The original type of the right hand side is no longer
- meaningful. */
- rhs_origtype = NULL_TREE;
+ /* Construct the RHS for any non-atomic compound assignemnt. */
+ if (!is_atomic_op)
+ {
+ newrhs = build_binary_op (location,
+ modifycode, lhs, rhs, 1);
+
+ /* The original type of the right hand side is no longer
+ meaningful. */
+ rhs_origtype = NULL_TREE;
+ }
}
if (c_dialect_objc ())
@@ -4959,23 +5304,39 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
? 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++");
}
+ /* If the lhs is atomic, remove that qualifier. */
+ if (is_atomic_op)
+ {
+ lhstype = build_qualified_type (lhstype,
+ (TYPE_QUALS (lhstype)
+ & ~TYPE_QUAL_ATOMIC));
+ olhstype = build_qualified_type (olhstype,
+ (TYPE_QUALS (lhstype)
+ & ~TYPE_QUAL_ATOMIC));
+ }
+
/* Convert new value to destination type. Fold it first, then
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)
@@ -4990,9 +5351,14 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
/* Scan operands. */
- result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
- TREE_SIDE_EFFECTS (result) = 1;
- protected_set_expr_location (result, location);
+ if (is_atomic_op)
+ result = build_atomic_assign (location, lhs, modifycode, newrhs, false);
+ else
+ {
+ result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
+ TREE_SIDE_EFFECTS (result) = 1;
+ protected_set_expr_location (result, location);
+ }
/* If we got the LHS in a different type for storing in,
convert the result back to the nominal type of LHS
@@ -5024,8 +5390,12 @@ find_anonymous_field_with_type (tree struct_type, tree type)
field != NULL_TREE;
field = TREE_CHAIN (field))
{
+ tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field))
+ ? c_build_qualified_type (TREE_TYPE (field),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (TREE_TYPE (field)));
if (DECL_NAME (field) == NULL
- && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+ && comptypes (type, fieldtype))
{
if (found)
return false;
@@ -5063,7 +5433,10 @@ convert_to_anonymous_field (location_t location, tree type, tree rhs)
|| TREE_CODE (rhs_struct_type) == UNION_TYPE);
gcc_assert (POINTER_TYPE_P (type));
- lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ lhs_main_type = (TYPE_ATOMIC (TREE_TYPE (type))
+ ? c_build_qualified_type (TREE_TYPE (type),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (TREE_TYPE (type)));
found_field = NULL_TREE;
found_sub_field = false;
@@ -5075,7 +5448,11 @@ convert_to_anonymous_field (location_t location, tree type, tree rhs)
|| (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE
&& TREE_CODE (TREE_TYPE (field)) != UNION_TYPE))
continue;
- if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+ tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field))
+ ? c_build_qualified_type (TREE_TYPE (field),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (TREE_TYPE (field)));
+ if (comptypes (lhs_main_type, fieldtype))
{
if (found_field != NULL_TREE)
return NULL_TREE;
@@ -5365,17 +5742,18 @@ convert_for_assignment (location_t location, tree type, tree rhs,
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of
the rhs. */
- if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+ if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
+ || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
|| comp_target_types (location, memb_type, rhstype))
{
+ int lquals = TYPE_QUALS (ttl) & ~TYPE_QUAL_ATOMIC;
+ int rquals = TYPE_QUALS (ttr) & ~TYPE_QUAL_ATOMIC;
/* If this type won't generate any warnings, use it. */
- if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
+ if (lquals == rquals
|| ((TREE_CODE (ttr) == FUNCTION_TYPE
&& TREE_CODE (ttl) == FUNCTION_TYPE)
- ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
- == TYPE_QUALS (ttr))
- : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
- == TYPE_QUALS (ttl))))
+ ? ((lquals | rquals) == rquals)
+ : ((lquals | rquals) == lquals)))
break;
/* Keep looking for a better type, but remember this one. */
@@ -5466,9 +5844,15 @@ convert_for_assignment (location_t location, tree type, tree rhs,
addr_space_t asr;
if (TREE_CODE (mvl) != ARRAY_TYPE)
- mvl = TYPE_MAIN_VARIANT (mvl);
+ mvl = (TYPE_ATOMIC (mvl)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mvl));
if (TREE_CODE (mvr) != ARRAY_TYPE)
- mvr = TYPE_MAIN_VARIANT (mvr);
+ mvr = (TYPE_ATOMIC (mvr)
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (mvr));
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
@@ -5569,13 +5953,15 @@ convert_for_assignment (location_t location, tree type, tree rhs,
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
- if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+ if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
+ || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
|| (target_cmp = comp_target_types (location, type, rhstype))
|| is_opaque_pointer
|| ((c_common_unsigned_type (mvl)
== c_common_unsigned_type (mvr))
- && c_common_signed_type (mvl)
- == c_common_signed_type (mvr)))
+ && (c_common_signed_type (mvl)
+ == c_common_signed_type (mvr))
+ && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr)))
{
if (pedantic
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -5598,8 +5984,9 @@ convert_for_assignment (location_t location, tree type, tree rhs,
else if (TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
- if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
- & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
+ /* Assignments between atomic and non-atomic objects are OK. */
+ if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
{
WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE discards "
@@ -6072,7 +6459,11 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
if (code == ARRAY_TYPE && inside_init
&& TREE_CODE (inside_init) == STRING_CST)
{
- tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ tree typ1
+ = (TYPE_ATOMIC (TREE_TYPE (type))
+ ? c_build_qualified_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
+ TYPE_QUAL_ATOMIC)
+ : TYPE_MAIN_VARIANT (TREE_TYPE (type)));
/* Note that an array could be both an array of character type
and an array of wchar_t if wchar_t is signed char or unsigned
char. */
@@ -8610,7 +9001,7 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
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)))
@@ -10096,13 +10487,13 @@ build_binary_op (location_t location, enum tree_code code,
"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 "