From 38b7bc7fc6a883b7ed12f27c798496fceef28ba2 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 13 Nov 2013 00:38:49 +0000 Subject: extend.texi (Statement Exprs, Typeof): Discuss __auto_type. * doc/extend.texi (Statement Exprs, Typeof): Discuss __auto_type. * ginclude/stdatomic.h (kill_dependency, atomic_store_explicit) (atomic_load_explicit, atomic_exchange_explicit) (atomic_compare_exchange_strong_explicit) (atomic_compare_exchange_weak_explicit): Use __auto_type to declare variable initialized with PTR argument. c-family: * c-common.h (enum rid): Add RID_AUTO_TYPE. * c-common.c (c_common_reswords): Add __auto_type. (keyword_begins_type_specifier): Handle RID_AUTO_TYPE. c: * c-tree.h (c_typespec_keyword): Add cts_auto_type. * c-decl.c (declspecs_add_type, finish_declspecs): Handle __auto_type. * c-parser.c (c_token_starts_typename, c_token_starts_declspecs) (c_parser_attribute_any_word, c_parser_objc_selector): Handle RID_AUTO_TYPE. (c_parser_declspecs): Take argument AUTO_TYPE_OK. (c_parser_declaration_or_fndef, c_parser_struct_declaration) (c_parser_declarator, c_parser_direct_declarator_inner) (c_parser_parameter_declaration, c_parser_type_name): All callers changed. (c_parser_declaration_or_fndef): Handle declarations with type determined from the initializer. testsuite: * gcc.dg/atomic/stdatomic-vm.c, gcc.dg/auto-type-1.c, gcc.dg/auto-type-2.c: New tests. From-SVN: r204731 --- gcc/ChangeLog | 9 ++ gcc/c-family/ChangeLog | 6 ++ gcc/c-family/c-common.c | 2 + gcc/c-family/c-common.h | 2 +- gcc/c/ChangeLog | 16 ++++ gcc/c/c-decl.c | 66 ++++++++++++- gcc/c/c-parser.c | 147 ++++++++++++++++++++++++----- gcc/c/c-tree.h | 3 +- gcc/doc/extend.texi | 31 +++++- gcc/ginclude/stdatomic.h | 42 +++++---- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c | 68 +++++++++++++ gcc/testsuite/gcc.dg/auto-type-1.c | 37 ++++++++ gcc/testsuite/gcc.dg/auto-type-2.c | 23 +++++ 14 files changed, 410 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c create mode 100644 gcc/testsuite/gcc.dg/auto-type-1.c create mode 100644 gcc/testsuite/gcc.dg/auto-type-2.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2c0554b..95e51ed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2013-11-13 Joseph Myers + + * doc/extend.texi (Statement Exprs, Typeof): Discuss __auto_type. + * ginclude/stdatomic.h (kill_dependency, atomic_store_explicit) + (atomic_load_explicit, atomic_exchange_explicit) + (atomic_compare_exchange_strong_explicit) + (atomic_compare_exchange_weak_explicit): Use __auto_type to + declare variable initialized with PTR argument. + 2013-11-12 Jeff Law * tree-ssa-threadedge.c (thread_around_empty_blocks): New diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 57063bc..e4e6163 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2013-11-13 Joseph Myers + + * c-common.h (enum rid): Add RID_AUTO_TYPE. + * c-common.c (c_common_reswords): Add __auto_type. + (keyword_begins_type_specifier): Handle RID_AUTO_TYPE. + 2013-11-12 Andrew MacLeod * c-family/c-common.c: Include gimplify.h. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 835d22c..1f5e4ed 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -434,6 +434,7 @@ const struct c_common_resword c_common_reswords[] = { "__asm__", RID_ASM, 0 }, { "__attribute", RID_ATTRIBUTE, 0 }, { "__attribute__", RID_ATTRIBUTE, 0 }, + { "__auto_type", RID_AUTO_TYPE, D_CONLY }, { "__bases", RID_BASES, D_CXXONLY }, { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY }, @@ -11551,6 +11552,7 @@ keyword_begins_type_specifier (enum rid keyword) { switch (keyword) { + case RID_AUTO_TYPE: case RID_INT: case RID_CHAR: case RID_FLOAT: diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 74fd59f..d9d2c44 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -102,7 +102,7 @@ enum rid RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, - RID_FRACT, RID_ACCUM, + RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, /* C11 */ RID_ALIGNAS, RID_GENERIC, diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index e95c54d..b9b9dc9 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,19 @@ +2013-11-13 Joseph Myers + + * c-tree.h (c_typespec_keyword): Add cts_auto_type. + * c-decl.c (declspecs_add_type, finish_declspecs): Handle + __auto_type. + * c-parser.c (c_token_starts_typename, c_token_starts_declspecs) + (c_parser_attribute_any_word, c_parser_objc_selector): Handle + RID_AUTO_TYPE. + (c_parser_declspecs): Take argument AUTO_TYPE_OK. + (c_parser_declaration_or_fndef, c_parser_struct_declaration) + (c_parser_declarator, c_parser_direct_declarator_inner) + (c_parser_parameter_declaration, c_parser_type_name): All callers + changed. + (c_parser_declaration_or_fndef): Handle declarations with type + determined from the initializer. + 2013-11-12 Andrew MacLeod * c/c-typeck.c: Include gimplify.h. diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 6fe418e..92fc68f 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -9115,6 +9115,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both % and % in " "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_void) error_at (loc, ("both % and % in " @@ -9159,6 +9163,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both % and % in " "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_void) error_at (loc, ("both % and % in " @@ -9207,6 +9215,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both % and % in " "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_void) error_at (loc, ("both % and % in " @@ -9247,6 +9259,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both % and % in " "declaration specifiers")); + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_void) error_at (loc, ("both % and % in " @@ -9286,7 +9302,11 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, if (!flag_isoc99 && !in_system_header_at (loc)) pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support complex types"); - if (specs->typespec_word == cts_void) + if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->typespec_word == cts_void) error_at (loc, ("both % and % in " "declaration specifiers")); @@ -9334,6 +9354,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and %<__int128%> in " "declaration specifiers")); } + else if (specs->typespec_word == cts_auto_type) + error_at (loc, + ("both %<_Sat%> and %<__auto_type%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_void) error_at (loc, ("both %<_Sat%> and % in " @@ -9392,7 +9416,8 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, else { /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32", - "__int128", "_Decimal64", "_Decimal128", "_Fract" or "_Accum". */ + "__int128", "_Decimal64", "_Decimal128", "_Fract", "_Accum" or + "__auto_type". */ if (specs->typespec_word != cts_none) { error_at (loc, @@ -9401,6 +9426,37 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, } switch (i) { + case RID_AUTO_TYPE: + if (specs->long_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->signed_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->unsigned_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both % and %<__auto_type%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<__auto_type%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_auto_type; + specs->locations[cdw_typespec] = loc; + } + return specs; case RID_INT128: if (int128_integer_type_node == NULL_TREE) { @@ -9956,6 +10012,12 @@ finish_declspecs (struct c_declspecs *specs) /* Now compute the actual type. */ switch (specs->typespec_word) { + case cts_auto_type: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p + && !specs->complex_p); + /* Type to be filled in later. */ + break; case cts_void: gcc_assert (!specs->long_p && !specs->short_p && !specs->signed_p && !specs->unsigned_p diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5b4665a..ffbf3c4 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -501,6 +501,7 @@ c_token_starts_typename (c_token *token) case RID_FRACT: case RID_ACCUM: case RID_SAT: + case RID_AUTO_TYPE: return true; default: return false; @@ -659,6 +660,7 @@ c_token_starts_declspecs (c_token *token) case RID_SAT: case RID_ALIGNAS: case RID_ATOMIC: + case RID_AUTO_TYPE: return true; default: return false; @@ -1128,7 +1130,7 @@ static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, static void c_parser_static_assert_declaration_no_semi (c_parser *); static void c_parser_static_assert_declaration (c_parser *); static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, - bool, bool, enum c_lookahead_kind); + bool, bool, bool, enum c_lookahead_kind); static struct c_typespec c_parser_enum_specifier (c_parser *); static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); static tree c_parser_struct_declaration (c_parser *); @@ -1499,7 +1501,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } c_parser_declspecs (parser, specs, true, true, start_attr_ok, - true, cla_nonabstract_decl); + true, true, cla_nonabstract_decl); if (parser->error) { c_parser_skip_to_end_of_block_or_statement (parser); @@ -1512,9 +1514,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, return; } finish_declspecs (specs); + bool auto_type_p = specs->typespec_word == cts_auto_type; if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - if (empty_ok) + if (auto_type_p) + error_at (here, "%<__auto_type%> in empty declaration"); + else if (empty_ok) shadow_tag (specs); else { @@ -1537,7 +1542,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, shadow_tag_warned (specs, 1); return; } - else if (c_dialect_objc ()) + else if (c_dialect_objc () && !auto_type_p) { /* Prefix attributes are an error on method decls. */ switch (c_parser_peek_token (parser)->type) @@ -1640,6 +1645,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_skip_to_end_of_block_or_statement (parser); return; } + if (auto_type_p && declarator->kind != cdk_id) + { + error_at (here, + "%<__auto_type%> requires a plain identifier" + " as declarator"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } if (c_parser_next_token_is (parser, CPP_EQ) || c_parser_next_token_is (parser, CPP_COMMA) || c_parser_next_token_is (parser, CPP_SEMICOLON) @@ -1667,19 +1680,72 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, struct c_expr init; location_t init_loc; c_parser_consume_token (parser); - /* The declaration of the variable is in effect while - its initializer is parsed. */ - d = start_decl (declarator, specs, true, - chainon (postfix_attrs, all_prefix_attrs)); - if (!d) - d = error_mark_node; - if (omp_declare_simd_clauses.exists ()) - c_finish_omp_declare_simd (parser, d, NULL_TREE, - omp_declare_simd_clauses); - start_init (d, asm_name, global_bindings_p ()); - init_loc = c_parser_peek_token (parser)->location; - init = c_parser_initializer (parser); - finish_init (); + if (auto_type_p) + { + start_init (NULL_TREE, asm_name, global_bindings_p ()); + init_loc = c_parser_peek_token (parser)->location; + init = c_parser_expr_no_commas (parser, NULL); + if (TREE_CODE (init.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) + error_at (here, + "%<__auto_type%> used with a bit-field" + " initializer"); + init = convert_lvalue_to_rvalue (init_loc, init, true, true); + tree init_type = TREE_TYPE (init.value); + /* As with typeof, remove _Atomic and const + qualifiers from atomic types. */ + if (init_type != error_mark_node && TYPE_ATOMIC (init_type)) + init_type + = c_build_qualified_type (init_type, + (TYPE_QUALS (init_type) + & ~(TYPE_QUAL_ATOMIC + | TYPE_QUAL_CONST))); + bool vm_type = variably_modified_type_p (init_type, + NULL_TREE); + if (vm_type) + init.value = c_save_expr (init.value); + finish_init (); + specs->typespec_kind = ctsk_typeof; + specs->locations[cdw_typedef] = init_loc; + specs->typedef_p = true; + specs->type = init_type; + if (vm_type) + { + bool maybe_const = true; + tree type_expr = c_fully_fold (init.value, false, + &maybe_const); + specs->expr_const_operands &= maybe_const; + if (specs->expr) + specs->expr = build2 (COMPOUND_EXPR, + TREE_TYPE (type_expr), + specs->expr, type_expr); + else + specs->expr = type_expr; + } + d = start_decl (declarator, specs, true, + chainon (postfix_attrs, all_prefix_attrs)); + if (!d) + d = error_mark_node; + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (parser, d, NULL_TREE, + omp_declare_simd_clauses); + } + else + { + /* The declaration of the variable is in effect while + its initializer is parsed. */ + d = start_decl (declarator, specs, true, + chainon (postfix_attrs, all_prefix_attrs)); + if (!d) + d = error_mark_node; + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (parser, d, NULL_TREE, + omp_declare_simd_clauses); + start_init (d, asm_name, global_bindings_p ()); + init_loc = c_parser_peek_token (parser)->location; + init = c_parser_initializer (parser); + finish_init (); + } if (d != error_mark_node) { maybe_warn_string_init (TREE_TYPE (d), init); @@ -1689,6 +1755,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } else { + if (auto_type_p) + { + error_at (here, + "%<__auto_type%> requires an initialized " + "data declaration"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } tree d = start_decl (declarator, specs, false, chainon (postfix_attrs, all_prefix_attrs)); @@ -1728,6 +1802,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } if (c_parser_next_token_is (parser, CPP_COMMA)) { + if (auto_type_p) + { + error_at (here, + "%<__auto_type%> may only be used with" + " a single declarator"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } c_parser_consume_token (parser); if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) all_prefix_attrs = chainon (c_parser_attributes (parser), @@ -1757,6 +1839,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, return; } } + else if (auto_type_p) + { + error_at (here, + "%<__auto_type%> requires an initialized data declaration"); + c_parser_skip_to_end_of_block_or_statement (parser); + return; + } else if (!fndef_ok) { c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " @@ -1949,7 +2038,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) Storage class specifiers are accepted iff SCSPEC_OK; type specifiers are accepted iff TYPESPEC_OK; alignment specifiers are accepted iff ALIGNSPEC_OK; attributes are accepted at the start - iff START_ATTR_OK. + iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK. declaration-specifiers: storage-class-specifier declaration-specifiers[opt] @@ -2030,6 +2119,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) type-specifier: typeof-specifier + __auto_type __int128 _Decimal32 _Decimal64 @@ -2055,7 +2145,8 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) static void c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, bool scspec_ok, bool typespec_ok, bool start_attr_ok, - bool alignspec_ok, enum c_lookahead_kind la) + bool alignspec_ok, bool auto_type_ok, + enum c_lookahead_kind la) { bool attrs_ok = start_attr_ok; bool seen_type = specs->typespec_kind != ctsk_none; @@ -2177,6 +2268,10 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; + case RID_AUTO_TYPE: + if (!auto_type_ok) + goto out; + /* Fall through. */ case RID_UNSIGNED: case RID_LONG: case RID_INT128: @@ -2722,7 +2817,7 @@ c_parser_struct_declaration (c_parser *parser) of N1731. */ c_parser_declspecs (parser, specs, false, true, true, - true, cla_nonabstract_decl); + true, false, cla_nonabstract_decl); if (parser->error) return NULL_TREE; if (!specs->declspecs_seen_p) @@ -3045,7 +3140,7 @@ c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, struct c_declarator *inner; c_parser_consume_token (parser); c_parser_declspecs (parser, quals_attrs, false, false, true, - false, cla_prefer_id); + false, false, cla_prefer_id); inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); if (inner == NULL) return NULL; @@ -3201,13 +3296,13 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, dimen.original_type = NULL_TREE; c_parser_consume_token (parser); c_parser_declspecs (parser, quals_attrs, false, false, true, - false, cla_prefer_id); + false, false, cla_prefer_id); static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC); if (static_seen) c_parser_consume_token (parser); if (static_seen && !quals_attrs->declspecs_seen_p) c_parser_declspecs (parser, quals_attrs, false, false, true, - false, cla_prefer_id); + false, false, cla_prefer_id); if (!quals_attrs->declspecs_seen_p) quals_attrs = NULL; /* If "static" is present, there must be an array dimension. @@ -3510,7 +3605,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) declspecs_add_attrs (input_location, specs, attrs); attrs = NULL_TREE; } - c_parser_declspecs (parser, specs, true, true, true, true, + c_parser_declspecs (parser, specs, true, true, true, true, false, cla_nonabstract_decl); finish_declspecs (specs); pending_xref_error (); @@ -3643,6 +3738,7 @@ c_parser_attribute_any_word (c_parser *parser) case RID_TRANSACTION_ATOMIC: case RID_TRANSACTION_CANCEL: case RID_ATOMIC: + case RID_AUTO_TYPE: ok = true; break; default: @@ -3821,7 +3917,7 @@ c_parser_type_name (c_parser *parser) struct c_declarator *declarator; struct c_type_name *ret; bool dummy = false; - c_parser_declspecs (parser, specs, false, true, true, false, + c_parser_declspecs (parser, specs, false, true, true, false, false, cla_prefer_type); if (!specs->declspecs_seen_p) { @@ -8702,6 +8798,7 @@ c_parser_objc_selector (c_parser *parser) case RID_VOID: case RID_BOOL: case RID_ATOMIC: + case RID_AUTO_TYPE: c_parser_consume_token (parser); return value; default: diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 502fdca..c4dfc3b 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -214,7 +214,8 @@ enum c_typespec_keyword { cts_dfloat64, cts_dfloat128, cts_fract, - cts_accum + cts_accum, + cts_auto_type }; /* This enum lists all the possible declarator specifiers, storage diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 2132b1e..599dee3 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -153,7 +153,7 @@ the value of an enumeration constant, the width of a bit-field, or the initial value of a static variable. If you don't know the type of the operand, you can still do this, but you -must use @code{typeof} (@pxref{Typeof}). +must use @code{typeof} or @code{__auto_type} (@pxref{Typeof}). In G++, the result value of a statement expression undergoes array and function pointer decay, and is returned by value to the enclosing @@ -755,6 +755,35 @@ Thus, @code{array (pointer (char), 4)} is the type of arrays of 4 pointers to @code{char}. @end itemize +In GNU C, but not GNU C++, you may also declare the type of a variable +as @code{__auto_type}. In that case, the declaration must declare +only one variable, whose declarator must just be an identifier, the +declaration must be initialized, and the type of the variable is +determined by the initializer; the name of the variable is not in +scope until after the initializer. (In C++, you should use C++11 +@code{auto} for this purpose.) Using @code{__auto_type}, the +``maximum'' macro above could be written as: + +@smallexample +#define max(a,b) \ + (@{ __auto_type _a = (a); \ + __auto_type _b = (b); \ + _a > _b ? _a : _b; @}) +@end smallexample + +Using @code{__auto_type} instead of @code{typeof} has two advantages: + +@itemize @bullet +@item Each argument to the macro appears only once in the expansion of +the macro. This prevents the size of the macro expansion growing +exponentially when calls to such macros are nested inside arguments of +such macros. + +@item If the argument to the macro has variably modified type, it is +evaluated only once when using @code{__auto_type}, but twice if +@code{typeof} is used. +@end itemize + @emph{Compatibility Note:} In addition to @code{typeof}, GCC 2 supported a more limited extension that permitted one to write diff --git a/gcc/ginclude/stdatomic.h b/gcc/ginclude/stdatomic.h index 622577f..b558bf1 100644 --- a/gcc/ginclude/stdatomic.h +++ b/gcc/ginclude/stdatomic.h @@ -87,7 +87,7 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; #define kill_dependency(Y) \ __extension__ \ ({ \ - __typeof__ (Y) __kill_dependency_tmp = (Y); \ + __auto_type __kill_dependency_tmp = (Y); \ __kill_dependency_tmp; \ }) @@ -121,9 +121,9 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; __atomic_type_lock_free (void * _Atomic) -/* Note that these macros require __typeof__ to remove _Atomic - qualifiers (and const qualifiers, if those are valid on macro - operands). +/* Note that these macros require __typeof__ and __auto_type 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 @@ -132,11 +132,12 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; these to lock-free _N variants if possible, and throw away the temps. */ -#define atomic_store_explicit(PTR, VAL, MO) \ - __extension__ \ - ({ \ - __typeof__ (*(PTR)) __atomic_store_tmp = (VAL); \ - __atomic_store ((PTR), &__atomic_store_tmp, (MO)); \ +#define atomic_store_explicit(PTR, VAL, MO) \ + __extension__ \ + ({ \ + __auto_type __atomic_store_ptr = (PTR); \ + __typeof__ (*__atomic_store_ptr) __atomic_store_tmp = (VAL); \ + __atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \ }) #define atomic_store(PTR, VAL) \ @@ -146,8 +147,9 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; #define atomic_load_explicit(PTR, MO) \ __extension__ \ ({ \ - __typeof__ (*(PTR)) __atomic_load_tmp; \ - __atomic_load ((PTR), &__atomic_load_tmp, (MO)); \ + __auto_type __atomic_load_ptr = (PTR); \ + __typeof__ (*__atomic_load_ptr) __atomic_load_tmp; \ + __atomic_load (__atomic_load_ptr, &__atomic_load_tmp, (MO)); \ __atomic_load_tmp; \ }) @@ -157,8 +159,10 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; #define atomic_exchange_explicit(PTR, VAL, MO) \ __extension__ \ ({ \ - __typeof__ (*(PTR)) __atomic_exchange_val = (VAL), __atomic_exchange_tmp; \ - __atomic_exchange ((PTR), &__atomic_exchange_val, \ + __auto_type __atomic_exchange_ptr = (PTR); \ + __typeof__ (*__atomic_exchange_ptr) __atomic_exchange_val = (VAL); \ + __typeof__ (*__atomic_exchange_ptr) __atomic_exchange_tmp; \ + __atomic_exchange (__atomic_exchange_ptr, &__atomic_exchange_val, \ &__atomic_exchange_tmp, (MO)); \ __atomic_exchange_tmp; \ }) @@ -170,8 +174,10 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; #define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \ __extension__ \ ({ \ - __typeof__ (*(PTR)) __atomic_compare_exchange_tmp = (DES); \ - __atomic_compare_exchange ((PTR), (VAL), \ + __auto_type __atomic_compare_exchange_ptr = (PTR); \ + __typeof__ (*__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \ + = (DES); \ + __atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \ &__atomic_compare_exchange_tmp, 0, \ (SUC), (FAIL)); \ }) @@ -183,8 +189,10 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; #define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \ __extension__ \ ({ \ - __typeof__ (*(PTR)) __atomic_compare_exchange_tmp = (DES); \ - __atomic_compare_exchange ((PTR), (VAL), \ + __auto_type __atomic_compare_exchange_ptr = (PTR); \ + __typeof__ (*__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \ + = (DES); \ + __atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \ &__atomic_compare_exchange_tmp, 1, \ (SUC), (FAIL)); \ }) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 09c7f20..2d724f7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-11-13 Joseph Myers + + * gcc.dg/atomic/stdatomic-vm.c, gcc.dg/auto-type-1.c, + gcc.dg/auto-type-2.c: New tests. + 2013-11-12 Balaji V. Iyer * gcc.dg/cilk-plus/cilk-plus.exp: Added a check for LTO before running diff --git a/gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c b/gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c new file mode 100644 index 0000000..f43fa49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c @@ -0,0 +1,68 @@ +/* Test atomic operations on expressions of variably modified type + with side effects. */ +/* { dg-do run } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +#include + +extern void abort (void); + +int s = 5; + +int count = 0; + +int +func (void) +{ + count++; + return 0; +} + +int +main (void) +{ + int vla[s][s]; + int (*_Atomic p)[s] = &vla[0]; + int (*b)[s] = kill_dependency (++p); + if (b != &vla[1] || p != &vla[1]) + abort (); + int (*_Atomic *q)[s] = &p; + atomic_store_explicit (q + func (), &vla[0], memory_order_seq_cst); + if (count != 1) + abort (); + atomic_store (q + func (), &vla[0]); + if (count != 2) + abort (); + (void) atomic_load_explicit (q + func (), memory_order_seq_cst); + if (count != 3) + abort (); + (void) atomic_load (q + func ()); + if (count != 4) + abort (); + (void) atomic_exchange_explicit (q + func (), &vla[0], memory_order_seq_cst); + if (count != 5) + abort (); + (void) atomic_exchange (q + func (), &vla[0]); + if (count != 6) + abort (); + int vla2[s][s]; + int (*p2)[s] = &vla2[0]; + int (**qna)[s] = &p2; + (void) atomic_compare_exchange_strong_explicit (q + func (), qna, &vla[0], + memory_order_seq_cst, + memory_order_seq_cst); + if (count != 7) + abort (); + (void) atomic_compare_exchange_strong (q + func (), qna, &vla[0]); + if (count != 8) + abort (); + (void) atomic_compare_exchange_weak_explicit (q + func (), qna, &vla[0], + memory_order_seq_cst, + memory_order_seq_cst); + if (count != 9) + abort (); + (void) atomic_compare_exchange_weak (q + func (), qna, &vla[0]); + if (count != 10) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/auto-type-1.c b/gcc/testsuite/gcc.dg/auto-type-1.c new file mode 100644 index 0000000..f47693a --- /dev/null +++ b/gcc/testsuite/gcc.dg/auto-type-1.c @@ -0,0 +1,37 @@ +/* Test __auto_type. Test correct uses. */ +/* { dg-do run } */ +/* { dg-options "" } */ + +extern void abort (void); +extern void exit (int); + +__auto_type i = 1; +extern int i; +__auto_type c = (char) 1; +extern char c; +static __auto_type u = 10U; +extern unsigned int u; +const __auto_type ll = 1LL; +extern const long long ll; + +int +main (void) +{ + if (i != 1 || c != 1 || u != 10U) + abort (); + __auto_type ai = i; + int *aip = &ai; + if (ai != 1) + abort (); + __auto_type p = (int (*) [++i]) 0; + if (i != 2) + abort (); + if (sizeof (*p) != 2 * sizeof (int)) + abort (); + int vla[u][u]; + int (*vp)[u] = &vla[0]; + __auto_type vpp = ++vp; + if (vp != &vla[1]) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/auto-type-2.c b/gcc/testsuite/gcc.dg/auto-type-2.c new file mode 100644 index 0000000..761671b --- /dev/null +++ b/gcc/testsuite/gcc.dg/auto-type-2.c @@ -0,0 +1,23 @@ +/* Test __auto_type. Test invalid uses. */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +__auto_type; /* { dg-error "empty declaration" } */ +__auto_type *p = (int *) 0; /* { dg-error "plain identifier" } */ +struct s0 { int i : 1; } x; +void f (void) { __auto_type v = x.i; } /* { dg-error "bit-field initializer" } */ +__auto_type i; /* { dg-error "initialized data declaration" } */ +__auto_type g { } /* { dg-error "initialized data declaration" } */ +__auto_type a = 1, b = 2; /* { dg-error "single declarator" } */ +__auto_type long e0 = 0; /* { dg-error "__auto_type" } */ +__auto_type short e1 = 0; /* { dg-error "__auto_type" } */ +__auto_type signed e2 = 0; /* { dg-error "__auto_type" } */ +__auto_type unsigned e3 = 0; /* { dg-error "__auto_type" } */ +__auto_type _Complex e4 = 0; /* { dg-error "__auto_type" } */ +long __auto_type e5 = 0; /* { dg-error "__auto_type" } */ +short __auto_type e6 = 0; /* { dg-error "__auto_type" } */ +signed __auto_type e7 = 0; /* { dg-error "__auto_type" } */ +unsigned __auto_type e8 = 0; /* { dg-error "__auto_type" } */ +_Complex __auto_type e9 = 0; /* { dg-error "__auto_type" } */ +int __auto_type e10 = 0; /* { dg-error "two or more data types" } */ +__auto_type _Bool e11 = 0; /* { dg-error "two or more data types" } */ -- cgit v1.1