This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Declspecs patch 3


This third declspecs patch (part of the C90 series) changes the
c_declspecs structure to store a storage class specifier rather than
some bits which might hold multiple such specifiers, moving the checks
for having multiple such specifiers to parse time from grokdeclarator
and so avoiding grokdeclarator potentially dealing with multiple
specifiers itself.

Thus (a) duplicate diagnostics are avoided in various cases such as
"static extern int x, y;"; (b) "static extern struct foo;" becomes a
hard error instead of a warning because of the move to do more when
parsing the specifiers rather than afterwards where the handling
splits into the separate paths of shadow_tag_warned (for empty
declarations) and grokdeclarator (for others); (c) "inline struct
foo;" also becomes a hard error, being a use of "inline" other than
declaring an identifier for a function; (d) "register struct foo;" and
"auto struct foo;" at file scope also become hard errors, "register"
and "auto" not being permitted in the specifiers for file scope
declarations, (e) "register" on file scope declarations in general
becomes a pedwarn if pedantic (I was surprised this one wasn't already
there, being a simple constraint in both C90 and C99; but sometimes
though not in the particular test here there is an error for invalid
register name, which conformance tests wouldn't distinguish from some
more specific diagnostic).

Two aspects of "inline" have been specifically deferred for separate
consideration or implementation of C99 inline, keeping existing
behavior with this patch rather than combining it with more changes of
behavior: "inline inline" is permitted by C99, while "inline" on a
declaration of "main" should be a pedwarn, not a warning, but in
hosted mode only.

The removed testcases pr14289-2.c and pr14289-3.c only differ from
pr14289-1.c in that they include multiple storage class specifiers on
a single declaration.  Formerly, grokdeclarator might have specbits
including multiple storage class specifiers and have to deal with them
some way.  Now, grokdeclarator receives a structure with a single
storage class specifier and any after the first in a declaration have
already been discarded, so these tests no longer serve a purpose (and
if the specifiers were swapped to make them pass again, they wouldn't
be testing anything different from pr14289-1.c).

Bootstrapped with no regressions on i686-pc-linux-gnu.  Applied to
mainline.

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
  http://www.srcf.ucam.org/~jsm28/gcc/#c90status - status of C90 for GCC 4.0
    jsm@polyomino.org.uk (personal mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)

2004-09-11  Joseph S. Myers  <jsm@polyomino.org.uk>

	* c-tree.h (enum c_storage_class): New.
	(struct c_declspecs): Add storage_class, inline_p and thread_p.
	* c-decl.c (shadow_tag_warned): Give errors for "inline" in empty
	declarations and "auto" or "register" in file scope empty
	declarations.  Give more specific warnings for other cases of
	storage class specifiers in empty declarations.
	(grokdeclarator): Update for new structures.  Don't check for
	multiple storage classes.  Diagnose file-scope "register" if
	pedantic.
	(build_null_declspecs): Update.
	(declspecs_add_scspec): Update.  Diagnose multiple storage class
	specifiers and invalid uses of "__thread".

testsuite:
2004-09-11  Joseph S. Myers  <jsm@polyomino.org.uk>

	* gcc.dg/declspec-4.c, gcc.dg/declspec-5.c, gcc.dg/declspec-6.c,
	gcc.dg/tls/diag-2.c: Update expected messages.
	* gcc.dg/991209-1.c: Specify compilation options.  Update expected
	messages.
	* gcc.dg/pr14289-2.c, gcc.dg/pr14289-3.c: Remove.
	* gcc.dg/declspec-7.c, gcc.dg/declspec-8.c, gcc.dg/declspec-9.c,
	gcc.dg/declspec-10.c, gcc.dg/declspec-11.c, gcc.dg/tls/diag-4.c,
	gcc.dg/tls/diag-5.c: New tests.

diff -rupN GCC.orig/gcc/c-decl.c GCC/gcc/c-decl.c
--- GCC.orig/gcc/c-decl.c	2004-09-10 23:06:00.000000000 +0000
+++ GCC/gcc/c-decl.c	2004-09-11 16:06:31.000000000 +0000
@@ -2741,6 +2741,36 @@ shadow_tag_warned (const struct c_declsp
       warned = 1;
     }
 
+  if (declspecs->inline_p)
+    {
+      error ("%<inline%> in empty declaration");
+      warned = 1;
+    }
+
+  if (current_scope == file_scope && declspecs->storage_class == csc_auto)
+    {
+      error ("%<auto%> in file-scope empty declaration");
+      warned = 1;
+    }
+
+  if (current_scope == file_scope && declspecs->storage_class == csc_register)
+    {
+      error ("%<register%> in file-scope empty declaration");
+      warned = 1;
+    }
+
+  if (!warned && !in_system_header && declspecs->storage_class != csc_none)
+    {
+      warning ("useless storage class specifier in empty declaration");
+      warned = 2;
+    }
+
+  if (!warned && !in_system_header && declspecs->thread_p)
+    {
+      warning ("useless %<__thread%> in empty declaration");
+      warned = 2;
+    }
+
   if (!warned && !in_system_header && declspecs->specbits)
     {
       warning ("useless keyword or type name in empty declaration");
@@ -3597,11 +3627,12 @@ grokdeclarator (const struct c_declarato
 {
   int specbits = declspecs->specbits;
   tree type = declspecs->type;
+  bool threadp = declspecs->thread_p;
+  enum c_storage_class storage_class = declspecs->storage_class;
   int constp;
   int restrictp;
   int volatilep;
   int type_quals = TYPE_UNQUALIFIED;
-  int inlinep;
   int defaulted_int = 0;
   const char *name, *orig_name;
   tree typedef_type = 0;
@@ -3682,7 +3713,7 @@ grokdeclarator (const struct c_declarato
 			  | (1 << (int) RID_UNSIGNED)
 			  | (1 << (int) RID_COMPLEX))))
 	  /* Don't warn about typedef foo = bar.  */
-	  && ! (specbits & (1 << (int) RID_TYPEDEF) && initialized)
+	  && ! (storage_class == csc_typedef && initialized)
 	  && ! in_system_header)
 	{
 	  /* Issue a warning if this is an ISO C 99 program or if -Wreturn-type
@@ -3866,7 +3897,6 @@ grokdeclarator (const struct c_declarato
     = !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (element_type);
   volatilep
     = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (element_type);
-  inlinep = !! (specbits & (1 << (int) RID_INLINE));
   if (pedantic && !flag_isoc99)
     {
       if (constp > 1)
@@ -3882,99 +3912,82 @@ grokdeclarator (const struct c_declarato
 		| (restrictp ? TYPE_QUAL_RESTRICT : 0)
 		| (volatilep ? TYPE_QUAL_VOLATILE : 0));
 
-  /* Warn if two storage classes are given. Default to `auto'.  */
-
-  {
-    int nclasses = 0;
+  /* Warn about storage classes that are invalid for certain
+     kinds of declarations (parameters, typenames, etc.).  */
 
-    if (specbits & 1 << (int) RID_AUTO) nclasses++;
-    if (specbits & 1 << (int) RID_STATIC) nclasses++;
-    if (specbits & 1 << (int) RID_EXTERN) nclasses++;
-    if (specbits & 1 << (int) RID_REGISTER) nclasses++;
-    if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
-
-    /* "static __thread" and "extern __thread" are allowed.  */
-    if ((specbits & (1 << (int) RID_THREAD
-		     | 1 << (int) RID_STATIC
-		     | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD))
-      nclasses++;
-
-    /* Warn about storage classes that are invalid for certain
-       kinds of declarations (parameters, typenames, etc.).  */
-
-    if (nclasses > 1)
-      error ("multiple storage classes in declaration of `%s'", name);
-    else if (funcdef_flag
-	     && (specbits
-		 & ((1 << (int) RID_REGISTER)
-		    | (1 << (int) RID_AUTO)
-		    | (1 << (int) RID_TYPEDEF)
-		    | (1 << (int) RID_THREAD))))
-      {
-	if (specbits & 1 << (int) RID_AUTO
-	    && (pedantic || current_scope == file_scope))
-	  pedwarn ("function definition declared `auto'");
-	if (specbits & 1 << (int) RID_REGISTER)
-	  error ("function definition declared `register'");
-	if (specbits & 1 << (int) RID_TYPEDEF)
-	  error ("function definition declared `typedef'");
-	if (specbits & 1 << (int) RID_THREAD)
-	  error ("function definition declared `__thread'");
-	specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
-		      | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD));
-      }
-    else if (decl_context != NORMAL && nclasses > 0)
-      {
-	if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER)
-	  ;
-	else
-	  {
-	    switch (decl_context)
-	      {
-	      case FIELD:
-		error ("storage class specified for structure field `%s'",
-		       name);
-		break;
-	      case PARM:
-		error ("storage class specified for parameter `%s'", name);
-		break;
-	      default:
-		error ("storage class specified for typename");
-		break;
-	      }
-	    specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
-			  | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
-			  | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
-	  }
-      }
-    else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
-      {
-	/* `extern' with initialization is invalid if not at file scope.  */
-	if (current_scope == file_scope)
-	  warning ("`%s' initialized and declared `extern'", name);
-	else
-	  error ("`%s' has both `extern' and initializer", name);
-      }
-    else if (current_scope == file_scope)
-      {
-	if (specbits & 1 << (int) RID_AUTO)
-	  error ("file-scope declaration of `%s' specifies `auto'", name);
-      }
-    else
-      {
-	if (specbits & 1 << (int) RID_EXTERN && funcdef_flag)
-	  error ("nested function `%s' declared `extern'", name);
-	else if ((specbits & (1 << (int) RID_THREAD
-			       | 1 << (int) RID_EXTERN
-			       | 1 << (int) RID_STATIC))
-		 == (1 << (int) RID_THREAD))
-	  {
-	    error ("function-scope `%s' implicitly auto and declared `__thread'",
-		   name);
-	    specbits &= ~(1 << (int) RID_THREAD);
-	  }
-      }
-  }
+  if (funcdef_flag
+      && (threadp
+	  || storage_class == csc_auto
+	  || storage_class == csc_register
+	  || storage_class == csc_typedef))
+    {
+      if (storage_class == csc_auto
+	  && (pedantic || current_scope == file_scope))
+	pedwarn ("function definition declared %<auto%>");
+      if (storage_class == csc_register)
+	error ("function definition declared %<register%>");
+      if (storage_class == csc_typedef)
+	error ("function definition declared %<typedef%>");
+      if (threadp)
+	error ("function definition declared %<__thread%>");
+      threadp = false;
+      if (storage_class == csc_auto
+	  || storage_class == csc_register
+	  || storage_class == csc_typedef)
+	storage_class = csc_none;
+    }
+  else if (decl_context != NORMAL && (storage_class != csc_none || threadp))
+    {
+      if (decl_context == PARM && storage_class == csc_register)
+	;
+      else
+	{
+	  switch (decl_context)
+	    {
+	    case FIELD:
+	      error ("storage class specified for structure field %qs",
+		     name);
+	      break;
+	    case PARM:
+	      error ("storage class specified for parameter %qs", name);
+	      break;
+	    default:
+	      error ("storage class specified for typename");
+	      break;
+	    }
+	  storage_class = csc_none;
+	  threadp = false;
+	}
+    }
+  else if (storage_class == csc_extern
+	   && initialized
+	   && !funcdef_flag)
+    {
+      /* 'extern' with initialization is invalid if not at file scope.  */
+      if (current_scope == file_scope)
+	warning ("%qs initialized and declared %<extern%>", name);
+      else
+	error ("%qs has both %<extern%> and initializer", name);
+    }
+  else if (current_scope == file_scope)
+    {
+      if (storage_class == csc_auto)
+	error ("file-scope declaration of `%s' specifies `auto'", name);
+      if (pedantic && storage_class == csc_register)
+	pedwarn ("file-scope declaration of %qs specifies %<register%>", name);
+    }
+  else
+    {
+      if (storage_class == csc_extern && funcdef_flag)
+	error ("nested function `%s' declared `extern'", name);
+      else if (threadp && storage_class == csc_none)
+	{
+	  error ("function-scope %qs implicitly auto and declared "
+		 "%<__thread%>",
+		 name);
+	  threadp = false;
+	}
+    }
 
   /* Now figure out the structure of the declarator proper.
      Descend through it, creating more complex types, until we reach
@@ -4337,7 +4350,7 @@ grokdeclarator (const struct c_declarato
 
   /* If this is declaring a typedef name, return a TYPE_DECL.  */
 
-  if (specbits & (1 << (int) RID_TYPEDEF))
+  if (storage_class == csc_typedef)
     {
       tree decl;
       /* Note that the grammar rejects storage classes
@@ -4394,10 +4407,10 @@ grokdeclarator (const struct c_declarato
 
   if (VOID_TYPE_P (type) && decl_context != PARM
       && ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE)
-	    && ((specbits & (1 << (int) RID_EXTERN))
+	    && (storage_class == csc_extern
 		|| (current_scope == file_scope
-		    && !(specbits
-			 & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)))))))
+		    && !(storage_class == csc_static
+			 || storage_class == csc_register)))))
     {
       error ("variable or field `%s' declared void", name);
       type = integer_type_node;
@@ -4508,8 +4521,7 @@ grokdeclarator (const struct c_declarato
       }
     else if (TREE_CODE (type) == FUNCTION_TYPE)
       {
-	if (specbits & (1 << (int) RID_REGISTER)
-	    || specbits & (1 << (int) RID_THREAD))
+	if (storage_class == csc_register || threadp)
 	  error ("invalid storage class for function `%s'", name);
 	else if (current_scope != file_scope)
 	  {
@@ -4518,12 +4530,12 @@ grokdeclarator (const struct c_declarato
 	       6.7.1p5, and `extern' makes no difference.  However,
 	       GCC allows 'auto', perhaps with 'inline', to support
 	       nested functions.  */
-	    if (specbits & (1 << (int) RID_AUTO))
+	    if (storage_class == csc_auto)
 	      {
 		if (pedantic)
 		  pedwarn ("invalid storage class for function `%s'", name);
 	      }
-	    if (specbits & (1 << (int) RID_STATIC))
+	    if (storage_class == csc_static)
 	      error ("invalid storage class for function `%s'", name);
 	  }
 
@@ -4546,14 +4558,14 @@ grokdeclarator (const struct c_declarato
 	   scope and are explicitly declared "auto".  This is
 	   forbidden by standard C (C99 6.7.1p5) and is interpreted by
 	   GCC to signify a forward declaration of a nested function.  */
-	if ((specbits & (1 << RID_AUTO)) && current_scope != file_scope)
+	if (storage_class == csc_auto && current_scope != file_scope)
 	  DECL_EXTERNAL (decl) = 0;
 	else
 	  DECL_EXTERNAL (decl) = 1;
 
 	/* Record absence of global scope for `static' or `auto'.  */
 	TREE_PUBLIC (decl)
-	  = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
+	  = !(storage_class == csc_static || storage_class == csc_auto);
 
 	/* For a function definition, record the argument information
 	   block where store_parm_decls will look for it.  */
@@ -4566,10 +4578,10 @@ grokdeclarator (const struct c_declarato
 	/* Record presence of `inline', if it is reasonable.  */
 	if (MAIN_NAME_P (declarator->u.id))
 	  {
-	    if (inlinep)
+	    if (declspecs->inline_p)
 	      warning ("cannot inline function `main'");
 	  }
-	else if (inlinep)
+	else if (declspecs->inline_p)
 	  {
 	    /* Record that the function is declared `inline'.  */
 	    DECL_DECLARED_INLINE_P (decl) = 1;
@@ -4581,7 +4593,7 @@ grokdeclarator (const struct c_declarato
 	    if (initialized)
 	      {
 		DECL_INLINE (decl) = 1;
-		if (specbits & (1 << (int) RID_EXTERN))
+		if (storage_class == csc_extern)
 		  current_extern_inline = 1;
 	      }
 	  }
@@ -4595,7 +4607,7 @@ grokdeclarator (const struct c_declarato
       {
 	/* It's a variable.  */
 	/* An uninitialized decl with `extern' is a reference.  */
-	int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN));
+	int extern_ref = !initialized && storage_class == csc_extern;
 
 	/* Move type qualifiers down to element of an array.  */
 	if (TREE_CODE (type) == ARRAY_TYPE && type_quals)
@@ -4632,13 +4644,13 @@ grokdeclarator (const struct c_declarato
 	if (size_varies)
 	  C_DECL_VARIABLE_SIZE (decl) = 1;
 
-	if (inlinep)
+	if (declspecs->inline_p)
 	  pedwarn ("%Jvariable '%D' declared `inline'", decl, decl);
 
 	/* At file scope, an initialized extern declaration may follow
 	   a static declaration.  In that case, DECL_EXTERNAL will be
 	   reset later in start_decl.  */
-	DECL_EXTERNAL (decl) = !!(specbits & (1 << (int) RID_EXTERN));
+	DECL_EXTERNAL (decl) = (storage_class == csc_extern);
 
 	/* At file scope, the presence of a `static' or `register' storage
 	   class specifier, or the absence of all storage class specifiers
@@ -4646,18 +4658,18 @@ grokdeclarator (const struct c_declarato
 	   the absence of both `static' and `register' makes it public.  */
 	if (current_scope == file_scope)
 	  {
-	    TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
-					       | (1 << (int) RID_REGISTER)));
+	    TREE_PUBLIC (decl) = !(storage_class == csc_static
+				   || storage_class == csc_register);
 	    TREE_STATIC (decl) = !extern_ref;
 	  }
 	/* Not at file scope, only `static' makes a static definition.  */
 	else
 	  {
-	    TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
+	    TREE_STATIC (decl) = (storage_class == csc_static);
 	    TREE_PUBLIC (decl) = extern_ref;
 	  }
 
-	if (specbits & 1 << (int) RID_THREAD)
+	if (threadp)
 	  {
 	    if (targetm.have_tls)
 	      DECL_THREAD_LOCAL (decl) = 1;
@@ -4671,7 +4683,7 @@ grokdeclarator (const struct c_declarato
     /* Record `register' declaration for warnings on &
        and in case doing stupid register allocation.  */
 
-    if (specbits & (1 << (int) RID_REGISTER))
+    if (storage_class == csc_register)
       {
 	C_DECL_REGISTER (decl) = 1;
 	DECL_REGISTER (decl) = 1;
@@ -6727,6 +6739,7 @@ build_null_declspecs (void)
   ret->decl_attr = 0;
   ret->attrs = 0;
   ret->specbits = 0;
+  ret->storage_class = csc_none;
   ret->non_sc_seen_p = false;
   ret->typedef_p = false;
   ret->typedef_signed_p = false;
@@ -6734,6 +6747,8 @@ build_null_declspecs (void)
   ret->explicit_int_p = false;
   ret->explicit_char_p = false;
   ret->long_long_p = false;
+  ret->inline_p = false;
+  ret->thread_p = false;
   return ret;
 }
 
@@ -6833,23 +6848,79 @@ struct c_declspecs *
 declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
 {
   enum rid i;
+  enum c_storage_class n = csc_none;
+  bool dupe = false;
   gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
 	      && C_IS_RESERVED_WORD (scspec));
   i = C_RID_CODE (scspec);
   if (extra_warnings && specs->non_sc_seen_p)
     warning ("%qs is not at beginning of declaration",
 	     IDENTIFIER_POINTER (scspec));
-  if (specs->specbits & (1 << (int) i))
-    error ("duplicate %qs", IDENTIFIER_POINTER (scspec));
-  /* Diagnose "__thread extern" and "__thread static".  */
-  if (specs->specbits & (1 << (int) RID_THREAD))
+  switch (i)
     {
-      if (i == RID_EXTERN)
+    case RID_INLINE:
+      /* GCC has hitherto given an error for duplicate inline, but
+	 this should be revisited since C99 permits duplicate
+	 inline.  */
+      dupe = specs->inline_p;
+      specs->inline_p = true;
+      break;
+    case RID_THREAD:
+      dupe = specs->thread_p;
+      if (specs->storage_class == csc_auto)
+	error ("%<__thread%> used with %<auto%>");
+      else if (specs->storage_class == csc_register)
+	error ("%<__thread%> used with %<register%>");
+      else if (specs->storage_class == csc_typedef)
+	error ("%<__thread%> used with %<typedef%>");
+      else
+	specs->thread_p = true;
+      break;
+    case RID_AUTO:
+      n = csc_auto;
+      break;
+    case RID_EXTERN:
+      n = csc_extern;
+      /* Diagnose "__thread extern".  */
+      if (specs->thread_p)
 	error ("%<__thread%> before %<extern%>");
-      else if (i == RID_STATIC)	
+      break;
+    case RID_REGISTER:
+      n = csc_register;
+      break;
+    case RID_STATIC:
+      n = csc_static;
+      /* Diagnose "__thread static".  */
+      if (specs->thread_p)
 	error ("%<__thread%> before %<static%>");
+      break;
+    case RID_TYPEDEF:
+      n = csc_typedef;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (n != csc_none && n == specs->storage_class)
+    dupe = true;
+  if (dupe)
+    error ("duplicate %qs", IDENTIFIER_POINTER (scspec));
+  if (n != csc_none)
+    {
+      if (specs->storage_class != csc_none && n != specs->storage_class)
+	{
+	  error ("multiple storage classes in declaration specifiers");
+	}
+      else
+	{
+	  specs->storage_class = n;
+	  if (n != csc_extern && n != csc_static && specs->thread_p)
+	    {
+	      error ("%<__thread%> used with %qs",
+		     IDENTIFIER_POINTER (scspec));
+	      specs->thread_p = false;
+	    }
+	}
     }
-  specs->specbits |= 1 << (int) i;
   return specs;
 }
 
diff -rupN GCC.orig/gcc/c-tree.h GCC/gcc/c-tree.h
--- GCC.orig/gcc/c-tree.h	2004-09-10 23:06:00.000000000 +0000
+++ GCC/gcc/c-tree.h	2004-09-11 00:33:51.000000000 +0000
@@ -131,6 +131,16 @@ struct c_expr
   enum tree_code original_code;
 };
 
+/* A storage class specifier.  */
+enum c_storage_class {
+  csc_none,
+  csc_auto,
+  csc_extern,
+  csc_register,
+  csc_static,
+  csc_typedef
+};
+
 /* A sequence of declaration specifiers in C.  */
 struct c_declspecs {
   /* The type specified, not reflecting modifiers such as "short" and
@@ -144,6 +154,8 @@ struct c_declspecs {
   tree attrs;
   /* The modifier bits present.  */
   int specbits;
+  /* The storage class specifier, or csc_none if none.  */
+  enum c_storage_class storage_class;
   /* Whether something other than a storage class specifier or
      attribute has been seen.  This is used to warn for the
      obsolescent usage of storage class specifiers other than at the
@@ -164,6 +176,10 @@ struct c_declspecs {
   BOOL_BITFIELD explicit_char_p : 1;
   /* Whether "long" was specified more than once.  */
   BOOL_BITFIELD long_long_p : 1;
+  /* Whether "inline" was specified.  */
+  BOOL_BITFIELD inline_p : 1;
+  /* Whether "__thread" was specified.  */
+  BOOL_BITFIELD thread_p : 1;
 };
 
 /* The various kinds of declarators in C.  */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/991209-1.c GCC/gcc/testsuite/gcc.dg/991209-1.c
--- GCC.orig/gcc/testsuite/gcc.dg/991209-1.c	2001-02-08 01:38:22.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/991209-1.c	2004-09-11 19:11:27.000000000 +0000
@@ -1,8 +1,9 @@
 /* { dg-do compile { target i?86-*-* } } */
+/* { dg-options "-ansi -pedantic" } */
 
 int foo ()
 {
   return 1;
 }
 
-register char *stack_ptr __asm ("%esp");
+register char *stack_ptr __asm ("%esp"); /* { dg-warning "warning: file-scope declaration of 'stack_ptr' specifies 'register'" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-10.c GCC/gcc/testsuite/gcc.dg/declspec-10.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-10.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-10.c	2004-09-11 21:09:58.000000000 +0000
@@ -0,0 +1,45 @@
+/* Test declaration specifiers.  Test various checks on storage class
+   and function specifiers that depend on information about the
+   declaration, not just the specifiers.  Test with -pedantic.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+/* { dg-do compile } */
+/* { dg-options "-pedantic" } */
+
+auto void f0 (void) {} /* { dg-warning "warning: function definition declared 'auto'" } */
+register void f1 (void) {} /* { dg-error "error: function definition declared 'register'" } */
+typedef void f2 (void) {} /* { dg-error "error: function definition declared 'typedef'" } */
+
+void f3 (auto int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f4 (extern int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f5 (register int);
+void f6 (static int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f7 (typedef int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+
+auto int x; /* { dg-error "error: file-scope declaration of `x' specifies `auto'" } */
+register int y; /* { dg-warning "warning: file-scope declaration of 'y' specifies 'register'" } */
+
+void h (void) { extern void x (void) {} } /* { dg-error "error: nested function `x' declared `extern'" } */
+/* { dg-warning "warning: ISO C forbids nested functions" "nested" { target *-*-* } 21 } */
+
+void
+g (void)
+{
+  void a; /* { dg-error "error: variable or field `a' declared void" } */
+  const void b; /* { dg-error "error: variable or field `b' declared void" } */
+  static void c; /* { dg-error "error: variable or field `c' declared void" } */
+}
+
+void p;
+const void p1;
+extern void q;
+extern const void q1;
+static void r; /* { dg-error "error: variable or field `r' declared void" } */
+static const void r1; /* { dg-error "error: variable or field `r1' declared void" } */
+
+register void f8 (void); /* { dg-error "error: invalid storage class for function `f8'" } */
+/* { dg-warning "warning: file-scope declaration of 'f8' specifies 'register'" "register function" { target *-*-* } 39 } */
+
+void i (void) { auto void y (void) {} } /* { dg-warning "warning: ISO C forbids nested functions" } */
+/* { dg-warning "warning: function definition declared 'auto'" "nested" { target *-*-* } 42 } */
+
+inline int main (void) { return 0; } /* { dg-warning "warning: cannot inline function `main'" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-11.c GCC/gcc/testsuite/gcc.dg/declspec-11.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-11.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-11.c	2004-09-11 21:10:04.000000000 +0000
@@ -0,0 +1,45 @@
+/* Test declaration specifiers.  Test various checks on storage class
+   and function specifiers that depend on information about the
+   declaration, not just the specifiers.  Test with -pedantic-errors.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors" } */
+
+auto void f0 (void) {} /* { dg-error "error: function definition declared 'auto'" } */
+register void f1 (void) {} /* { dg-error "error: function definition declared 'register'" } */
+typedef void f2 (void) {} /* { dg-error "error: function definition declared 'typedef'" } */
+
+void f3 (auto int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f4 (extern int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f5 (register int);
+void f6 (static int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f7 (typedef int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+
+auto int x; /* { dg-error "error: file-scope declaration of `x' specifies `auto'" } */
+register int y; /* { dg-error "error: file-scope declaration of 'y' specifies 'register'" } */
+
+void h (void) { extern void x (void) {} } /* { dg-error "error: nested function `x' declared `extern'" } */
+/* { dg-error "error: ISO C forbids nested functions" "nested" { target *-*-* } 21 } */
+
+void
+g (void)
+{
+  void a; /* { dg-error "error: variable or field `a' declared void" } */
+  const void b; /* { dg-error "error: variable or field `b' declared void" } */
+  static void c; /* { dg-error "error: variable or field `c' declared void" } */
+}
+
+void p;
+const void p1;
+extern void q;
+extern const void q1;
+static void r; /* { dg-error "error: variable or field `r' declared void" } */
+static const void r1; /* { dg-error "error: variable or field `r1' declared void" } */
+
+register void f8 (void); /* { dg-error "error: invalid storage class for function `f8'" } */
+/* { dg-error "error: file-scope declaration of 'f8' specifies 'register'" "register function" { target *-*-* } 39 } */
+
+void i (void) { auto void y (void) {} } /* { dg-error "error: ISO C forbids nested functions" } */
+/* { dg-error "error: function definition declared 'auto'" "nested" { target *-*-* } 42 } */
+
+inline int main (void) { return 0; } /* { dg-warning "warning: cannot inline function `main'" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-4.c GCC/gcc/testsuite/gcc.dg/declspec-4.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-4.c	2004-09-09 01:20:03.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-4.c	2004-09-11 13:49:52.000000000 +0000
@@ -22,7 +22,7 @@ int; /* { dg-warning "warning: useless t
 long; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
 /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 22 } */
 T; /* { dg-warning "warning: useless type name in empty declaration" } */
-static const; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
+static const; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
 /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 25 } */
 union { long b; }; /* { dg-warning "warning: unnamed struct/union that defines no instances" } */
 
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-5.c GCC/gcc/testsuite/gcc.dg/declspec-5.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-5.c	2004-09-09 01:20:03.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-5.c	2004-09-11 13:50:05.000000000 +0000
@@ -22,7 +22,7 @@ int; /* { dg-warning "warning: useless t
 long; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
 /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 22 } */
 T; /* { dg-warning "warning: useless type name in empty declaration" } */
-static const; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
+static const; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
 /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 25 } */
 union { long b; }; /* { dg-warning "warning: unnamed struct/union that defines no instances" } */
 
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-6.c GCC/gcc/testsuite/gcc.dg/declspec-6.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-6.c	2004-09-09 01:20:03.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-6.c	2004-09-11 13:50:21.000000000 +0000
@@ -22,7 +22,7 @@ int; /* { dg-error "error: useless type 
 long; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
 /* { dg-error "error: empty declaration" "long" { target *-*-* } 22 } */
 T; /* { dg-error "error: useless type name in empty declaration" } */
-static const; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
+static const; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
 /* { dg-error "error: empty declaration" "long" { target *-*-* } 25 } */
 union { long b; }; /* { dg-error "error: unnamed struct/union that defines no instances" } */
 
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-7.c GCC/gcc/testsuite/gcc.dg/declspec-7.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-7.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-7.c	2004-09-11 14:34:02.000000000 +0000
@@ -0,0 +1,39 @@
+/* Test declaration specifiers.  Test checks on storage class
+   specifiers that can be made at parse time rather than for each
+   declarator.  Note that __thread is tested in
+   gcc.dg/tls/diag-*.c.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Duplicate specifiers.  */
+
+inline inline void f0 (void), /* { dg-error "error: duplicate 'inline'" } */
+  f1 (void);
+
+static static int a, /* { dg-error "error: duplicate 'static'" } */
+  b;
+
+extern extern int c, /* { dg-error "error: duplicate 'extern'" } */
+  d;
+
+typedef typedef int e, /* { dg-error "error: duplicate 'typedef'" } */
+  f;
+
+void
+h (void)
+{
+  auto auto int p, /* { dg-error "error: duplicate 'auto'" } */
+    q;
+
+  register register int r, /* { dg-error "error: duplicate 'register'" } */
+    s;
+}
+
+/* Multiple specifiers.  */
+
+static extern int x, /* { dg-error "error: multiple storage classes in declaration specifiers" } */
+  y;
+
+extern typedef long z, /* { dg-error "error: multiple storage classes in declaration specifiers" } */
+  w;
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-8.c GCC/gcc/testsuite/gcc.dg/declspec-8.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-8.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-8.c	2004-09-11 19:19:35.000000000 +0000
@@ -0,0 +1,32 @@
+/* Test declaration specifiers.  Test checks on storage class
+   specifiers and function specifiers in empty declarations.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* The constraints on storage class specifiers and function specifiers
+   must be met for empty declarations where they are useless.  Thus
+   there may be only one storage class specifier (C90 6.5.1, C99
+   6.7.1#2) and "inline" must not be used because the declaration is
+   not that of an identifier for a function (C99 6.7.4#1), and
+   "register" and "auto" must not be used at file scope (C90 6.7, C99
+   6.9#2).  */
+
+static static struct s; /* { dg-error "error: duplicate 'static'" } */
+/* { dg-warning "warning: useless storage class specifier in empty declaration" "static static" { target *-*-* } 15 } */
+
+static extern struct t; /* { dg-error "error: multiple storage classes in declaration specifiers" } */
+/* { dg-warning "warning: useless storage class specifier in empty declaration" "static extern" { target *-*-* } 18 } */
+
+inline union u; /* { dg-error "error: 'inline' in empty declaration" } */
+
+auto struct v; /* { dg-error "error: 'auto' in file-scope empty declaration" } */
+
+register struct w; /* { dg-error "error: 'register' in file-scope empty declaration" } */
+
+void
+f (void)
+{
+  auto union p; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
+  register struct q; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
+}
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/declspec-9.c GCC/gcc/testsuite/gcc.dg/declspec-9.c
--- GCC.orig/gcc/testsuite/gcc.dg/declspec-9.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/declspec-9.c	2004-09-11 15:48:28.000000000 +0000
@@ -0,0 +1,43 @@
+/* Test declaration specifiers.  Test various checks on storage class
+   and function specifiers that depend on information about the
+   declaration, not just the specifiers.  Test with no special
+   options.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+auto void f0 (void) {} /* { dg-warning "warning: function definition declared 'auto'" } */
+register void f1 (void) {} /* { dg-error "error: function definition declared 'register'" } */
+typedef void f2 (void) {} /* { dg-error "error: function definition declared 'typedef'" } */
+
+void f3 (auto int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f4 (extern int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f5 (register int);
+void f6 (static int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+void f7 (typedef int); /* { dg-error "error: storage class specified for parameter 'type name'" } */
+
+auto int x; /* { dg-error "error: file-scope declaration of `x' specifies `auto'" } */
+register int y;
+
+void h (void) { extern void x (void) {} } /* { dg-error "error: nested function `x' declared `extern'" } */
+
+void
+g (void)
+{
+  void a; /* { dg-error "error: variable or field `a' declared void" } */
+  const void b; /* { dg-error "error: variable or field `b' declared void" } */
+  static void c; /* { dg-error "error: variable or field `c' declared void" } */
+}
+
+void p;
+const void p1;
+extern void q;
+extern const void q1;
+static void r; /* { dg-error "error: variable or field `r' declared void" } */
+static const void r1; /* { dg-error "error: variable or field `r1' declared void" } */
+
+register void f8 (void); /* { dg-error "error: invalid storage class for function `f8'" } */
+
+void i (void) { auto void y (void) {} }
+
+inline int main (void) { return 0; } /* { dg-warning "warning: cannot inline function `main'" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr14289-2.c GCC/gcc/testsuite/gcc.dg/pr14289-2.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr14289-2.c	2004-03-08 21:56:36.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr14289-2.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,12 +0,0 @@
-/* PR middle-end/14289 */
-/* { dg-do compile { target i?86-*-* } } */
-/* { dg-options "-O0" } */
-
-static register int a[2] asm("ebx");  /* { dg-error "multiple storage" } */
-
-void Nase(void)
-{
-  int i=6;
-  a[i]=5;  /* { dg-error "address of global" } */
-}
-
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr14289-3.c GCC/gcc/testsuite/gcc.dg/pr14289-3.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr14289-3.c	2004-03-08 21:56:36.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr14289-3.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,12 +0,0 @@
-/* PR middle-end/14289 */
-/* { dg-do compile { target i?86-*-* } } */
-/* { dg-options "-O0" } */
-
-extern register int a[2] asm("ebx");  /* { dg-error "multiple storage" } */
-
-void Nase(void)
-{
-  int i=6;
-  a[i]=5;  /* { dg-error "address of global" } */
-}
-
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/tls/diag-2.c GCC/gcc/testsuite/gcc.dg/tls/diag-2.c
--- GCC.orig/gcc/testsuite/gcc.dg/tls/diag-2.c	2004-09-09 01:20:03.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/tls/diag-2.c	2004-09-11 19:18:10.000000000 +0000
@@ -3,19 +3,19 @@
 __thread extern int g1;		/* { dg-error "'__thread' before 'extern'" } */
 __thread static int g2;		/* { dg-error "'__thread' before 'static'" } */
 __thread __thread int g3;	/* { dg-error "duplicate '__thread'" } */
-typedef __thread int g4;	/* { dg-error "multiple storage classes" } */
+typedef __thread int g4;	/* { dg-error "'__thread' used with 'typedef'" } */
 
 void foo()
 {
-  __thread int l1;		/* { dg-error "implicitly auto and declared `__thread'" } */
-  auto __thread int l2;		/* { dg-error "multiple storage classes" } */
+  __thread int l1;		/* { dg-error "implicitly auto and declared '__thread'" } */
+  auto __thread int l2;		/* { dg-error "'__thread' used with 'auto'" } */
   __thread extern int l3;	/* { dg-error "'__thread' before 'extern'" } */
-  register __thread int l4;	/* { dg-error "multiple storage classes" } */
+  register __thread int l4;	/* { dg-error "'__thread' used with 'register'" } */
 }
 
 __thread void f1 ();		/* { dg-error "invalid storage class for function" } */
 extern __thread void f2 ();	/* { dg-error "invalid storage class for function" } */
 static __thread void f3 ();	/* { dg-error "invalid storage class for function" } */
-__thread void f4 () { }		/* { dg-error "function definition declared `__thread'" } */
+__thread void f4 () { }		/* { dg-error "function definition declared '__thread'" } */
 
 void bar(__thread int p1);	/* { dg-error "storage class specified for parameter" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/tls/diag-4.c GCC/gcc/testsuite/gcc.dg/tls/diag-4.c
--- GCC.orig/gcc/testsuite/gcc.dg/tls/diag-4.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/tls/diag-4.c	2004-09-11 14:31:41.000000000 +0000
@@ -0,0 +1,10 @@
+/* Invalid __thread specifiers.  As diag-4.c but some cases in
+   different orders.  */
+
+__thread typedef int g4;	/* { dg-error "'__thread' used with 'typedef'" } */
+
+void foo()
+{
+  __thread auto int l2;		/* { dg-error "'__thread' used with 'auto'" } */
+  __thread register int l4;	/* { dg-error "'__thread' used with 'register'" } */
+}
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/tls/diag-5.c GCC/gcc/testsuite/gcc.dg/tls/diag-5.c
--- GCC.orig/gcc/testsuite/gcc.dg/tls/diag-5.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/tls/diag-5.c	2004-09-11 15:28:19.000000000 +0000
@@ -0,0 +1,3 @@
+/* __thread specifiers on empty declarations.  */
+
+__thread struct foo; /* { dg-warning "warning: useless '__thread' in empty declaration" } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]