aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-common.c2
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/c/ChangeLog16
-rw-r--r--gcc/c/c-decl.c66
-rw-r--r--gcc/c/c-parser.c147
-rw-r--r--gcc/c/c-tree.h3
-rw-r--r--gcc/doc/extend.texi31
-rw-r--r--gcc/ginclude/stdatomic.h42
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c68
-rw-r--r--gcc/testsuite/gcc.dg/auto-type-1.c37
-rw-r--r--gcc/testsuite/gcc.dg/auto-type-2.c23
14 files changed, 410 insertions, 47 deletions
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 <joseph@codesourcery.com>
+
+ * 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 <law@redhat.com>
* 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 <joseph@codesourcery.com>
+
+ * 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 <amacleod@redhat.com>
* 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 <joseph@codesourcery.com>
+
+ * 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 <amacleod@redhat.com>
* 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 %<long%> and %<short%> in "
"declaration specifiers"));
+ else if (specs->typespec_word == cts_auto_type)
+ error_at (loc,
+ ("both %<long%> and %<__auto_type%> in "
+ "declaration specifiers"));
else if (specs->typespec_word == cts_void)
error_at (loc,
("both %<long%> and %<void%> in "
@@ -9159,6 +9163,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
error_at (loc,
("both %<long%> and %<short%> in "
"declaration specifiers"));
+ else if (specs->typespec_word == cts_auto_type)
+ error_at (loc,
+ ("both %<short%> and %<__auto_type%> in "
+ "declaration specifiers"));
else if (specs->typespec_word == cts_void)
error_at (loc,
("both %<short%> and %<void%> in "
@@ -9207,6 +9215,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
error_at (loc,
("both %<signed%> and %<unsigned%> in "
"declaration specifiers"));
+ else if (specs->typespec_word == cts_auto_type)
+ error_at (loc,
+ ("both %<signed%> and %<__auto_type%> in "
+ "declaration specifiers"));
else if (specs->typespec_word == cts_void)
error_at (loc,
("both %<signed%> and %<void%> in "
@@ -9247,6 +9259,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
error_at (loc,
("both %<signed%> and %<unsigned%> in "
"declaration specifiers"));
+ else if (specs->typespec_word == cts_auto_type)
+ error_at (loc,
+ ("both %<unsigned%> and %<__auto_type%> in "
+ "declaration specifiers"));
else if (specs->typespec_word == cts_void)
error_at (loc,
("both %<unsigned%> and %<void%> 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 %<complex%> and %<__auto_type%> in "
+ "declaration specifiers"));
+ else if (specs->typespec_word == cts_void)
error_at (loc,
("both %<complex%> and %<void%> 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 %<void%> 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 %<long%> and %<__auto_type%> in "
+ "declaration specifiers"));
+ else if (specs->short_p)
+ error_at (loc,
+ ("both %<short%> and %<__auto_type%> in "
+ "declaration specifiers"));
+ else if (specs->signed_p)
+ error_at (loc,
+ ("both %<signed%> and %<__auto_type%> in "
+ "declaration specifiers"));
+ else if (specs->unsigned_p)
+ error_at (loc,
+ ("both %<unsigned%> and %<__auto_type%> in "
+ "declaration specifiers"));
+ else if (specs->complex_p)
+ error_at (loc,
+ ("both %<complex%> 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.
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf> */
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 <joseph@codesourcery.com>
+
+ * 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 <balaji.v.iyer@intel.com>
* 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 <stdatomic.h>
+
+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" } */