public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] c: C2x storage class specifiers in compound literals
@ 2022-10-14  2:19 Joseph Myers
  0 siblings, 0 replies; only message in thread
From: Joseph Myers @ 2022-10-14  2:19 UTC (permalink / raw)
  To: gcc-patches

Implement the C2x feature of storage class specifiers in compound
literals.  Such storage class specifiers (static, register or
thread_local; also constexpr, but we don't yet have C2x constexpr
support implemented) can be used before the type name (not mixed with
type specifiers, unlike in declarations) and have the same semantics
and constraints as for declarations of named objects.  Also allow GNU
__thread to be used, given that thread_local can be.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c/
	* c-decl.cc (build_compound_literal): Add parameter scspecs.
	Handle storage class specifiers.
	* c-parser.cc (c_token_starts_compound_literal)
	(c_parser_compound_literal_scspecs): New.
	(c_parser_postfix_expression_after_paren_type): Add parameter
	scspecs.  Call pedwarn_c11 for use of storage class specifiers.
	Update call to build_compound_literal.
	(c_parser_cast_expression, c_parser_sizeof_expression)
	(c_parser_alignof_expression): Handle storage class specifiers for
	compound literals.  Update calls to
	c_parser_postfix_expression_after_paren_type.
	(c_parser_postfix_expression): Update syntax comment.
	* c-tree.h (build_compound_literal): Update prototype.
	* c-typeck.cc (c_mark_addressable): Diagnose taking address of
	register compound literal.

gcc/testsuite/
	* gcc.dg/c11-complit-1.c, gcc.dg/c11-complit-2.c,
	gcc.dg/c11-complit-3.c, gcc.dg/c2x-complit-2.c,
	gcc.dg/c2x-complit-3.c, gcc.dg/c2x-complit-4.c,
	gcc.dg/c2x-complit-5.c, gcc.dg/c2x-complit-6.c,
	gcc.dg/c2x-complit-7.c, gcc.dg/c90-complit-2.c,
	gcc.dg/gnu2x-complit-1.c, gcc.dg/gnu2x-complit-2.c: New tests.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 193e268f04e..a7571cc7542 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6048,11 +6048,13 @@ mark_forward_parm_decls (void)
    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
@@ -6060,15 +6062,33 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const,
   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;
@@ -6076,6 +6096,13 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const,
   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)
     {
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 89e05870f47..602e0235f2d 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -666,6 +666,30 @@ c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la)
   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)
@@ -1563,6 +1587,7 @@ static struct c_expr c_parser_sizeof_expression (c_parser *);
 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 *,
@@ -8237,6 +8262,34 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
 #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.
@@ -8260,13 +8313,15 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
      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)
@@ -8281,8 +8336,11 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
       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");
@@ -8485,14 +8543,16 @@ c_parser_sizeof_expression (c_parser *parser)
   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;
@@ -8508,13 +8568,15 @@ c_parser_sizeof_expression (c_parser *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,
 							       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%>");
@@ -8572,16 +8634,18 @@ c_parser_alignof_expression (c_parser *parser)
   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);
@@ -8597,12 +8661,14 @@ c_parser_alignof_expression (c_parser *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",
@@ -9140,8 +9206,8 @@ c_parser_predefined_identifier (c_parser *parser)
      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
@@ -10483,6 +10549,7 @@ c_parser_postfix_expression (c_parser *parser)
 
 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)
 {
@@ -10515,7 +10582,11 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
       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);
@@ -10534,7 +10605,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
 	}
     }
   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;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 46a3e8e9709..e7cdd2f11dc 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -734,7 +734,7 @@ extern void set_init_label (location_t, tree, location_t, struct obstack *);
 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);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index f9190680a3c..017658070f4 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -5114,6 +5114,11 @@ c_mark_addressable (tree exp, bool array_ref_p)
 	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;
diff --git a/gcc/testsuite/gcc.dg/c11-complit-1.c b/gcc/testsuite/gcc.dg/c11-complit-1.c
new file mode 100644
index 00000000000..e191cebbb6a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-complit-1.c
@@ -0,0 +1,7 @@
+/* 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" } */
diff --git a/gcc/testsuite/gcc.dg/c11-complit-2.c b/gcc/testsuite/gcc.dg/c11-complit-2.c
new file mode 100644
index 00000000000..d4d1f16f62e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-complit-2.c
@@ -0,0 +1,7 @@
+/* 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" } */
diff --git a/gcc/testsuite/gcc.dg/c11-complit-3.c b/gcc/testsuite/gcc.dg/c11-complit-3.c
new file mode 100644
index 00000000000..a73a8ef8ae1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-complit-3.c
@@ -0,0 +1,7 @@
+/* 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 };
diff --git a/gcc/testsuite/gcc.dg/c2x-complit-2.c b/gcc/testsuite/gcc.dg/c2x-complit-2.c
new file mode 100644
index 00000000000..dcca5e8d348
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-complit-2.c
@@ -0,0 +1,48 @@
+/* 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);
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-complit-3.c b/gcc/testsuite/gcc.dg/c2x-complit-3.c
new file mode 100644
index 00000000000..c672525ba6f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-complit-3.c
@@ -0,0 +1,24 @@
+/* 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 };
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-complit-4.c b/gcc/testsuite/gcc.dg/c2x-complit-4.c
new file mode 100644
index 00000000000..31d741325d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-complit-4.c
@@ -0,0 +1,60 @@
+/* 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);
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-complit-5.c b/gcc/testsuite/gcc.dg/c2x-complit-5.c
new file mode 100644
index 00000000000..1eb0f8dd760
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-complit-5.c
@@ -0,0 +1,52 @@
+/* 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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-complit-6.c b/gcc/testsuite/gcc.dg/c2x-complit-6.c
new file mode 100644
index 00000000000..23a0bb6420b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-complit-6.c
@@ -0,0 +1,7 @@
+/* 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" } */
diff --git a/gcc/testsuite/gcc.dg/c2x-complit-7.c b/gcc/testsuite/gcc.dg/c2x-complit-7.c
new file mode 100644
index 00000000000..0cd0b86c541
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-complit-7.c
@@ -0,0 +1,7 @@
+/* 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" } */
diff --git a/gcc/testsuite/gcc.dg/c90-complit-2.c b/gcc/testsuite/gcc.dg/c90-complit-2.c
new file mode 100644
index 00000000000..6fcf2a59c43
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-complit-2.c
@@ -0,0 +1,8 @@
+/* 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" } */
diff --git a/gcc/testsuite/gcc.dg/gnu2x-complit-1.c b/gcc/testsuite/gcc.dg/gnu2x-complit-1.c
new file mode 100644
index 00000000000..e9da5ad7958
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu2x-complit-1.c
@@ -0,0 +1,7 @@
+/* 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 };
diff --git a/gcc/testsuite/gcc.dg/gnu2x-complit-2.c b/gcc/testsuite/gcc.dg/gnu2x-complit-2.c
new file mode 100644
index 00000000000..20cb38fd94e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu2x-complit-2.c
@@ -0,0 +1,18 @@
+/* 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 };
+}

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-14  2:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-14  2:19 [committed] c: C2x storage class specifiers in compound literals Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).