literal. NON_CONST is true if the initializers contain something
that cannot occur in a constant expression. If ALIGNAS_ALIGN is nonzero,
it is the (valid) alignment for this compound literal, as specified
- with _Alignas. */
+ with _Alignas. SCSPECS are the storage class specifiers (C2x) from the
+ compound literal. */
tree
build_compound_literal (location_t loc, tree type, tree init, bool non_const,
- unsigned int alignas_align)
+ unsigned int alignas_align,
+ struct c_declspecs *scspecs)
{
/* We do not use start_decl here because we have a type, not a declarator;
and do not use finish_decl because the decl should be stored inside
tree decl;
tree complit;
tree stmt;
+ bool threadp = scspecs ? scspecs->thread_p : false;
+ enum c_storage_class storage_class = (scspecs
+ ? scspecs->storage_class
+ : csc_none);
if (type == error_mark_node
|| init == error_mark_node)
return error_mark_node;
+ if (current_scope == file_scope && storage_class == csc_register)
+ {
+ error_at (loc, "file-scope compound literal specifies %<register%>");
+ storage_class = csc_none;
+ }
+
+ if (current_scope != file_scope && threadp && storage_class == csc_none)
+ {
+ error_at (loc, "compound literal implicitly auto and declared %qs",
+ scspecs->thread_gnu_p ? "__thread" : "_Thread_local");
+ threadp = false;
+ }
+
decl = build_decl (loc, VAR_DECL, NULL_TREE, type);
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = 0;
- TREE_STATIC (decl) = (current_scope == file_scope);
+ TREE_STATIC (decl) = (current_scope == file_scope
+ || storage_class == csc_static);
DECL_CONTEXT (decl) = current_function_decl;
TREE_USED (decl) = 1;
DECL_READ_P (decl) = 1;
DECL_IGNORED_P (decl) = 1;
C_DECL_COMPOUND_LITERAL_P (decl) = 1;
TREE_TYPE (decl) = type;
+ if (threadp)
+ set_decl_tls_model (decl, decl_default_tls_model (decl));
+ if (storage_class == csc_register)
+ {
+ C_DECL_REGISTER (decl) = 1;
+ DECL_REGISTER (decl) = 1;
+ }
c_apply_type_quals_to_decl (TYPE_QUALS (strip_array_types (type)), decl);
if (alignas_align)
{
return false;
}
+/* Return true if TOKEN, after an open parenthesis, can start a
+ compound literal (either a storage class specifier allowed in that
+ context, or a type name), false otherwise. */
+static bool
+c_token_starts_compound_literal (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_REGISTER:
+ case RID_STATIC:
+ case RID_THREAD:
+ return true;
+ default:
+ break;
+ }
+ /* Fall through. */
+ default:
+ return c_token_starts_typename (token);
+ }
+}
+
/* Return true if TOKEN is a type qualifier, false otherwise. */
static bool
c_token_is_qualifier (c_token *token)
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
+ struct c_declspecs *,
struct c_type_name *,
location_t);
static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
#undef POP
}
+/* Parse any storage class specifiers after an open parenthesis in a
+ context where a compound literal is permitted. */
+
+static struct c_declspecs *
+c_parser_compound_literal_scspecs (c_parser *parser)
+{
+ bool seen_scspec = false;
+ struct c_declspecs *specs = build_null_declspecs ();
+ while (c_parser_next_token_is (parser, CPP_KEYWORD))
+ {
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_REGISTER:
+ case RID_STATIC:
+ case RID_THREAD:
+ seen_scspec = true;
+ declspecs_add_scspec (c_parser_peek_token (parser)->location,
+ specs, c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
+ default:
+ goto out;
+ }
+ }
+ out:
+ return seen_scspec ? specs : NULL;
+}
+
/* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4). If AFTER
is not NULL then it is an Objective-C message expression which is the
primary-expression starting the expression as an initializer.
an unary expression. Full detection of unknown typenames here
would require a 3-token lookahead. */
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
- && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
+ struct c_declspecs *scspecs;
struct c_type_name *type_name;
struct c_expr ret;
struct c_expr expr;
matching_parens parens;
parens.consume_open (parser);
+ scspecs = c_parser_compound_literal_scspecs (parser);
type_name = c_parser_type_name (parser, true);
parens.skip_until_found_close (parser);
if (type_name == NULL)
used_types_insert (type_name->specs->type);
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- return c_parser_postfix_expression_after_paren_type (parser, type_name,
+ return c_parser_postfix_expression_after_paren_type (parser, scspecs,
+ type_name,
cast_loc);
+ if (scspecs)
+ error_at (cast_loc, "storage class specifier in cast");
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
"alignment specified for type name in cast");
c_inhibit_evaluation_warnings++;
in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
- && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
/* Either sizeof ( type-name ) or sizeof unary-expression
starting with a compound literal. */
+ struct c_declspecs *scspecs;
struct c_type_name *type_name;
matching_parens parens;
parens.consume_open (parser);
expr_loc = c_parser_peek_token (parser)->location;
+ scspecs = c_parser_compound_literal_scspecs (parser);
type_name = c_parser_type_name (parser, true);
parens.skip_until_found_close (parser);
finish = parser->tokens_buf[0].location;
}
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
- expr = c_parser_postfix_expression_after_paren_type (parser,
+ expr = c_parser_postfix_expression_after_paren_type (parser, scspecs,
type_name,
expr_loc);
finish = expr.get_finish ();
goto sizeof_expr;
}
/* sizeof ( type-name ). */
+ if (scspecs)
+ error_at (expr_loc, "storage class specifier in %<sizeof%>");
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
"alignment specified for type name in %<sizeof%>");
c_inhibit_evaluation_warnings++;
in_alignof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
- && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
/* Either __alignof__ ( type-name ) or __alignof__
unary-expression starting with a compound literal. */
location_t loc;
+ struct c_declspecs *scspecs;
struct c_type_name *type_name;
struct c_expr ret;
matching_parens parens;
parens.consume_open (parser);
loc = c_parser_peek_token (parser)->location;
+ scspecs = c_parser_compound_literal_scspecs (parser);
type_name = c_parser_type_name (parser, true);
end_loc = c_parser_peek_token (parser)->location;
parens.skip_until_found_close (parser);
}
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
- expr = c_parser_postfix_expression_after_paren_type (parser,
+ expr = c_parser_postfix_expression_after_paren_type (parser, scspecs,
type_name,
loc);
goto alignof_expr;
}
/* alignof ( type-name ). */
+ if (scspecs)
+ error_at (loc, "storage class specifier in %qE", alignof_spelling);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
"alignment specified for type name in %qE",
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
- ( type-name ) { initializer-list }
- ( type-name ) { initializer-list , }
+ ( storage-class-specifiers[opt] type-name ) { initializer-list[opt] }
+ ( storage-class-specifiers[opt] type-name ) { initializer-list , }
argument-expression-list:
argument-expression
static struct c_expr
c_parser_postfix_expression_after_paren_type (c_parser *parser,
+ struct c_declspecs *scspecs,
struct c_type_name *type_name,
location_t type_loc)
{
type = error_mark_node;
}
- pedwarn_c90 (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals");
+ if (!pedwarn_c90 (start_loc, OPT_Wpedantic,
+ "ISO C90 forbids compound literals") && scspecs)
+ pedwarn_c11 (start_loc, OPT_Wpedantic,
+ "ISO C forbids storage class specifiers in compound literals "
+ "before C2X");
non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
? CONSTRUCTOR_NON_CONST (init.value)
: init.original_code == C_MAYBE_CONST_EXPR);
}
}
expr.value = build_compound_literal (start_loc, type, init.value, non_const,
- alignas_align);
+ alignas_align, scspecs);
set_c_expr_source_range (&expr, init.src_range);
expr.m_decimal = 0;
expr.original_code = ERROR_MARK;
extern void process_init_element (location_t, struct c_expr, bool,
struct obstack *);
extern tree build_compound_literal (location_t, tree, tree, bool,
- unsigned int);
+ unsigned int, struct c_declspecs *);
extern void check_compound_literal_type (location_t, struct c_type_name *);
extern tree c_start_switch (location_t, location_t, tree, bool);
extern void c_finish_switch (tree, tree);
break;
case COMPOUND_LITERAL_EXPR:
+ if (C_DECL_REGISTER (COMPOUND_LITERAL_EXPR_DECL (x)))
+ {
+ error ("address of register compound literal requested");
+ return false;
+ }
TREE_ADDRESSABLE (x) = 1;
TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1;
return true;
--- /dev/null
+/* Test C2x storage class specifiers in compound literals not permitted for
+ C11. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int *ps = &(static int) { 1 }; /* { dg-error "forbids storage class specifiers in compound literals" } */
+int ss = sizeof (static int) { 1 }; /* { dg-error "forbids storage class specifiers in compound literals" } */
--- /dev/null
+/* Test C2x storage class specifiers in compound literals not permitted for
+ C11. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic" } */
+
+int *ps = &(static int) { 1 }; /* { dg-warning "forbids storage class specifiers in compound literals" } */
+int ss = sizeof (static int) { 1 }; /* { dg-warning "forbids storage class specifiers in compound literals" } */
--- /dev/null
+/* Test C2x storage class specifiers in compound literals not permitted for
+ C11, but -Wno-c11-c2x-compat disables the -pedantic diagnostic for that. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors -Wno-c11-c2x-compat" } */
+
+int *ps = &(static int) { 1 };
+int ss = sizeof (static int) { 1 };
--- /dev/null
+/* Test C2x storage class specifiers in compound literals. */
+/* { dg-do run } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+#include <stddef.h>
+
+extern void abort (void);
+extern void exit (int);
+
+/* static is OK (although redundant) at file scope. */
+int *ps = &(static int) { 1 };
+size_t ss = sizeof (static int) { 1 };
+int *psa = (static int [3]) { 1, 2, 3 };
+
+int
+main ()
+{
+ if (ps[0] != 1)
+ abort ();
+ if (ss != sizeof (int))
+ abort ();
+ if (psa[0] != 1 || psa[1] != 2 || psa[2] != 3)
+ abort ();
+ if ((register int) { 3 } != 3)
+ abort ();
+ /* A static compound literal, like a static variable, is initialized once,
+ but an automatic compound literal is initialized every time it is reached
+ in the order of execution. */
+ int i = 0;
+ lab:
+ int *p = &(static int) { 0 };
+ if (*p != i)
+ abort ();
+ i++;
+ *p = i;
+ if (i < 5)
+ goto lab;
+ i = 0;
+ lab2:
+ int *p2 = &(int) { 0 };
+ if (*p2 != 0)
+ abort ();
+ i++;
+ *p2 = i;
+ if (i < 5)
+ goto lab2;
+ exit (0);
+}
--- /dev/null
+/* Test C2x storage class specifiers in compound literals. Thread-local
+ cases, compilation tests. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+/* { dg-require-effective-target tls } */
+
+#include <stddef.h>
+
+/* thread_local is OK at file scope, although of limited use since the
+ thread-local object and its address are not constant expressions. */
+size_t st = sizeof (thread_local int) { 1 };
+size_t sst = sizeof (static thread_local int) { 1 };
+
+int *
+f ()
+{
+ return &(static thread_local int) { 2 };
+}
+
+int *
+g ()
+{
+ return &(thread_local static int) { 3 };
+}
--- /dev/null
+/* Test C2x storage class specifiers in compound literals. Thread-local
+ cases, execution tests. */
+/* { dg-do run } */
+/* { dg-options "-pthread -std=gnu2x -pedantic-errors" } */
+/* { dg-require-effective-target pthread_h } */
+/* { dg-require-effective-target pthread } */
+/* { dg-require-effective-target tls_runtime } */
+/* { dg-add-options tls } */
+
+#include <pthread.h>
+
+extern void abort (void);
+extern void exit (int);
+
+int *
+thread_addr ()
+{
+ return (static thread_local int []) { 1, 2 };
+}
+
+int *volatile p, *volatile q, r;
+
+void *
+thread_fn (void *)
+{
+ q = thread_addr ();
+ if (q[0] != 1 || q[1] != 2)
+ return NULL;
+ q[0] = 5;
+ q[1] = 6;
+ return &r;
+}
+
+int
+main ()
+{
+ int i;
+ pthread_t tid;
+ void *ret;
+ p = thread_addr ();
+ if (p[0] != 1 || p[1] != 2)
+ abort ();
+ p[0] = 3;
+ p[1] = 4;
+ if (p != thread_addr ())
+ abort ();
+ i = pthread_create (&tid, NULL, thread_fn, NULL);
+ if (p != thread_addr ())
+ abort ();
+ i = pthread_join (tid, &ret);
+ if (i != 0)
+ abort ();
+ if (ret != &r)
+ abort ();
+ if (p != thread_addr ())
+ abort ();
+ if (p[0] != 3 || p[1] != 4)
+ abort ();
+ exit (0);
+}
--- /dev/null
+/* Test C2x storage class specifiers in compound literals: invalid code. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int *p = &(register int) { 0 }; /* { dg-error "file-scope compound literal specifies" } */
+
+int v;
+
+void
+f ()
+{
+ int *q = &(thread_local int) { 0 }; /* { dg-error "compound literal implicitly auto and declared" } */
+ int *pc = &(static int) { v }; /* { dg-error "not constant" } */
+ int *pt = &(static thread_local int) { v }; /* { dg-error "not constant" } */
+ &(register int) { 0 }; /* { dg-error "address of register compound literal requested" } */
+ struct s { int a, b; };
+ &((register struct s) { 1, 2 }.b); /* { dg-error "address of register compound literal requested" } */
+}
+
+int *s = &(static static int) { 0 }; /* { dg-error "duplicate" } */
+
+void
+g ()
+{
+ (void) (register register int) { 0 }; /* { dg-error "duplicate" } */
+ (void) (static static int) { 0 }; /* { dg-error "duplicate" } */
+ (void) (static thread_local thread_local int) { 0 }; /* { dg-error "duplicate" } */
+ (void) (static register int) { 0 }; /* { dg-error "multiple storage classes in declaration specifiers" } */
+ (void) (register static int) { 0 }; /* { dg-error "multiple storage classes in declaration specifiers" } */
+ (void) (register thread_local int) { 0 }; /* { dg-error "used with" } */
+ (void) (thread_local register int) { 0 }; /* { dg-error "used with" } */
+}
+
+void
+h ()
+{
+ /* The following cases are not part of the C2x syntax, but are detected
+ specially by the parser. */
+ (static int) 0; /* { dg-error "storage class specifier in cast" } */
+ sizeof (static int); /* { dg-error "storage class specifier in" } */
+ alignof (static int); /* { dg-error "storage class specifier in" } */
+}
+
+void
+bad_scspec ()
+{
+ /* Storage class specifiers not permitted in compound literals result in a
+ syntax error. */
+ (typedef int) { 0 }; /* { dg-error "expected" } */
+ (auto int) { 0 }; /* { dg-error "expected" } */
+ (extern int) { 0 }; /* { dg-error "expected" } */
+}
--- /dev/null
+/* Test C2x storage class specifiers in compound literals diagnosed with
+ -Wc11-c2x-compat. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+int *ps = &(static int) { 1 }; /* { dg-warning "forbids storage class specifiers in compound literals" } */
+int ss = sizeof (static int) { 1 }; /* { dg-warning "forbids storage class specifiers in compound literals" } */
--- /dev/null
+/* Test C2x storage class specifiers in compound literals diagnosed with
+ -Wc11-c2x-compat, but not errors with -pedantic-errors. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat -pedantic-errors" } */
+
+int *ps = &(static int) { 1 }; /* { dg-warning "forbids storage class specifiers in compound literals" } */
+int ss = sizeof (static int) { 1 }; /* { dg-warning "forbids storage class specifiers in compound literals" } */
--- /dev/null
+/* Test C2x storage class specifiers in compound literals not permitted for
+ C90, but without a duplicate diagnostic, just the diagnostic for compound
+ literals not being permitted in C90 at all. */
+/* { dg-do compile } */
+/* { dg-options "-std=c90 -pedantic-errors" } */
+
+int *ps = &(static int) { 1 }; /* { dg-error "ISO C90 forbids compound literals" } */
+int ss = sizeof (static int) { 1 }; /* { dg-error "ISO C90 forbids compound literals" } */
--- /dev/null
+/* Test C2x storage class specifiers in compound literals: GNU use of alignof
+ on objects (tested separately since alignof parsing handles the type name of
+ compound literals). */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x" } */
+
+int a = alignof (static int) { 0 };
--- /dev/null
+/* Test C2x storage class specifiers in compound literals. Thread-local
+ cases, compilation tests, GNU __thread used. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x" } */
+/* { dg-require-effective-target tls } */
+
+#include <stddef.h>
+
+/* __thread is OK at file scope, although of limited use since the
+ thread-local object and its address are not constant expressions. */
+size_t st = sizeof (__thread int) { 1 };
+size_t sst = sizeof (static __thread int) { 1 };
+
+int *
+f ()
+{
+ return &(static __thread int) { 2 };
+}