aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/c-decl.c321
-rw-r--r--gcc/testsuite/ChangeLog11
-rw-r--r--gcc/testsuite/gcc.dg/991209-1.c3
-rw-r--r--gcc/testsuite/gcc.dg/declspec-10.c45
-rw-r--r--gcc/testsuite/gcc.dg/declspec-11.c45
-rw-r--r--gcc/testsuite/gcc.dg/declspec-4.c2
-rw-r--r--gcc/testsuite/gcc.dg/declspec-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/declspec-6.c2
-rw-r--r--gcc/testsuite/gcc.dg/declspec-7.c39
-rw-r--r--gcc/testsuite/gcc.dg/declspec-8.c32
-rw-r--r--gcc/testsuite/gcc.dg/declspec-9.c43
-rw-r--r--gcc/testsuite/gcc.dg/pr14289-2.c12
-rw-r--r--gcc/testsuite/gcc.dg/pr14289-3.c12
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-2.c10
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-4.c10
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-5.c3
17 files changed, 449 insertions, 158 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 190c7e6f..db61ded 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+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".
+
2004-09-11 Zack Weinberg <zack@codesourcery.com>
* tree.c (tree_code_size): New function, bulk of code from tree_size.
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index acec389..60b613f 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -2741,6 +2741,36 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
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_declarator *declarator,
{
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_declarator *declarator,
| (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_declarator *declarator,
= !! (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_declarator *declarator,
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 0));
- /* Warn if two storage classes are given. Default to `auto'. */
-
- {
- int nclasses = 0;
-
- 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);
- }
- }
- }
+ /* Warn about storage classes that are invalid for certain
+ kinds of declarations (parameters, typenames, etc.). */
+
+ 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_declarator *declarator,
/* 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_declarator *declarator,
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_declarator *declarator,
}
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_declarator *declarator,
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_declarator *declarator,
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_declarator *declarator,
/* 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_declarator *declarator,
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_declarator *declarator,
{
/* 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_declarator *declarator,
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_declarator *declarator,
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_declarator *declarator,
/* 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;
@@ -6720,6 +6732,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;
@@ -6727,6 +6740,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;
}
@@ -6826,23 +6841,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))
- {
- if (i == RID_EXTERN)
+ switch (i)
+ {
+ 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 --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f7d6b82..e48d301 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+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.
+
2004-09-11 Zack Weinberg <zack@codesourcery.com>
* gcc.dg/20040910-1.c: Correct dg-error regexp.
diff --git a/gcc/testsuite/gcc.dg/991209-1.c b/gcc/testsuite/gcc.dg/991209-1.c
index b3a4728..2381922 100644
--- a/gcc/testsuite/gcc.dg/991209-1.c
+++ b/gcc/testsuite/gcc.dg/991209-1.c
@@ -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 --git a/gcc/testsuite/gcc.dg/declspec-10.c b/gcc/testsuite/gcc.dg/declspec-10.c
new file mode 100644
index 0000000..454cb1d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/declspec-10.c
@@ -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 --git a/gcc/testsuite/gcc.dg/declspec-11.c b/gcc/testsuite/gcc.dg/declspec-11.c
new file mode 100644
index 0000000..c418de1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/declspec-11.c
@@ -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 --git a/gcc/testsuite/gcc.dg/declspec-4.c b/gcc/testsuite/gcc.dg/declspec-4.c
index 0610e05..fbc6c36 100644
--- a/gcc/testsuite/gcc.dg/declspec-4.c
+++ b/gcc/testsuite/gcc.dg/declspec-4.c
@@ -22,7 +22,7 @@ int; /* { dg-warning "warning: useless type name in empty declaration" } */
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 --git a/gcc/testsuite/gcc.dg/declspec-5.c b/gcc/testsuite/gcc.dg/declspec-5.c
index aba2739..febbfb3 100644
--- a/gcc/testsuite/gcc.dg/declspec-5.c
+++ b/gcc/testsuite/gcc.dg/declspec-5.c
@@ -22,7 +22,7 @@ int; /* { dg-warning "warning: useless type name in empty declaration" } */
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 --git a/gcc/testsuite/gcc.dg/declspec-6.c b/gcc/testsuite/gcc.dg/declspec-6.c
index 91a5d82..305eed7 100644
--- a/gcc/testsuite/gcc.dg/declspec-6.c
+++ b/gcc/testsuite/gcc.dg/declspec-6.c
@@ -22,7 +22,7 @@ int; /* { dg-error "error: useless type name in empty declaration" } */
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 --git a/gcc/testsuite/gcc.dg/declspec-7.c b/gcc/testsuite/gcc.dg/declspec-7.c
new file mode 100644
index 0000000..bb63d95
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/declspec-7.c
@@ -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 --git a/gcc/testsuite/gcc.dg/declspec-8.c b/gcc/testsuite/gcc.dg/declspec-8.c
new file mode 100644
index 0000000..ea60126
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/declspec-8.c
@@ -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 --git a/gcc/testsuite/gcc.dg/declspec-9.c b/gcc/testsuite/gcc.dg/declspec-9.c
new file mode 100644
index 0000000..855393c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/declspec-9.c
@@ -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 --git a/gcc/testsuite/gcc.dg/pr14289-2.c b/gcc/testsuite/gcc.dg/pr14289-2.c
deleted file mode 100644
index 7530b46..0000000
--- a/gcc/testsuite/gcc.dg/pr14289-2.c
+++ /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr14289-3.c b/gcc/testsuite/gcc.dg/pr14289-3.c
deleted file mode 100644
index 7cfbf78..0000000
--- a/gcc/testsuite/gcc.dg/pr14289-3.c
+++ /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/tls/diag-2.c b/gcc/testsuite/gcc.dg/tls/diag-2.c
index 3c5d9bd..5e7e17b 100644
--- a/gcc/testsuite/gcc.dg/tls/diag-2.c
+++ b/gcc/testsuite/gcc.dg/tls/diag-2.c
@@ -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 --git a/gcc/testsuite/gcc.dg/tls/diag-4.c b/gcc/testsuite/gcc.dg/tls/diag-4.c
new file mode 100644
index 0000000..df3705d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/diag-4.c
@@ -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 --git a/gcc/testsuite/gcc.dg/tls/diag-5.c b/gcc/testsuite/gcc.dg/tls/diag-5.c
new file mode 100644
index 0000000..623832c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/diag-5.c
@@ -0,0 +1,3 @@
+/* __thread specifiers on empty declarations. */
+
+__thread struct foo; /* { dg-warning "warning: useless '__thread' in empty declaration" } */