Commit 9a26d6ee by Joseph Myers Committed by Joseph Myers

c-tree.h (enum c_storage_class): New.

	* 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:
	* 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.

From-SVN: r87374
parent e6858057
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> 2004-09-11 Zack Weinberg <zack@codesourcery.com>
* tree.c (tree_code_size): New function, bulk of code from tree_size. * tree.c (tree_code_size): New function, bulk of code from tree_size.
......
...@@ -2741,6 +2741,36 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) ...@@ -2741,6 +2741,36 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
warned = 1; 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) if (!warned && !in_system_header && declspecs->specbits)
{ {
warning ("useless keyword or type name in empty declaration"); warning ("useless keyword or type name in empty declaration");
...@@ -3597,11 +3627,12 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -3597,11 +3627,12 @@ grokdeclarator (const struct c_declarator *declarator,
{ {
int specbits = declspecs->specbits; int specbits = declspecs->specbits;
tree type = declspecs->type; tree type = declspecs->type;
bool threadp = declspecs->thread_p;
enum c_storage_class storage_class = declspecs->storage_class;
int constp; int constp;
int restrictp; int restrictp;
int volatilep; int volatilep;
int type_quals = TYPE_UNQUALIFIED; int type_quals = TYPE_UNQUALIFIED;
int inlinep;
int defaulted_int = 0; int defaulted_int = 0;
const char *name, *orig_name; const char *name, *orig_name;
tree typedef_type = 0; tree typedef_type = 0;
...@@ -3682,7 +3713,7 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -3682,7 +3713,7 @@ grokdeclarator (const struct c_declarator *declarator,
| (1 << (int) RID_UNSIGNED) | (1 << (int) RID_UNSIGNED)
| (1 << (int) RID_COMPLEX)))) | (1 << (int) RID_COMPLEX))))
/* Don't warn about typedef foo = bar. */ /* Don't warn about typedef foo = bar. */
&& ! (specbits & (1 << (int) RID_TYPEDEF) && initialized) && ! (storage_class == csc_typedef && initialized)
&& ! in_system_header) && ! in_system_header)
{ {
/* Issue a warning if this is an ISO C 99 program or if -Wreturn-type /* 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, ...@@ -3866,7 +3897,6 @@ grokdeclarator (const struct c_declarator *declarator,
= !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (element_type); = !! (specbits & 1 << (int) RID_RESTRICT) + TYPE_RESTRICT (element_type);
volatilep volatilep
= !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (element_type); = !! (specbits & 1 << (int) RID_VOLATILE) + TYPE_VOLATILE (element_type);
inlinep = !! (specbits & (1 << (int) RID_INLINE));
if (pedantic && !flag_isoc99) if (pedantic && !flag_isoc99)
{ {
if (constp > 1) if (constp > 1)
...@@ -3882,97 +3912,80 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -3882,97 +3912,80 @@ grokdeclarator (const struct c_declarator *declarator,
| (restrictp ? TYPE_QUAL_RESTRICT : 0) | (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 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 /* Warn about storage classes that are invalid for certain
kinds of declarations (parameters, typenames, etc.). */ kinds of declarations (parameters, typenames, etc.). */
if (nclasses > 1) if (funcdef_flag
error ("multiple storage classes in declaration of `%s'", name); && (threadp
else if (funcdef_flag || storage_class == csc_auto
&& (specbits || storage_class == csc_register
& ((1 << (int) RID_REGISTER) || storage_class == csc_typedef))
| (1 << (int) RID_AUTO)
| (1 << (int) RID_TYPEDEF)
| (1 << (int) RID_THREAD))))
{ {
if (specbits & 1 << (int) RID_AUTO if (storage_class == csc_auto
&& (pedantic || current_scope == file_scope)) && (pedantic || current_scope == file_scope))
pedwarn ("function definition declared `auto'"); pedwarn ("function definition declared %<auto%>");
if (specbits & 1 << (int) RID_REGISTER) if (storage_class == csc_register)
error ("function definition declared `register'"); error ("function definition declared %<register%>");
if (specbits & 1 << (int) RID_TYPEDEF) if (storage_class == csc_typedef)
error ("function definition declared `typedef'"); error ("function definition declared %<typedef%>");
if (specbits & 1 << (int) RID_THREAD) if (threadp)
error ("function definition declared `__thread'"); error ("function definition declared %<__thread%>");
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) threadp = false;
| (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD)); if (storage_class == csc_auto
} || storage_class == csc_register
else if (decl_context != NORMAL && nclasses > 0) || storage_class == csc_typedef)
{ storage_class = csc_none;
if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER) }
else if (decl_context != NORMAL && (storage_class != csc_none || threadp))
{
if (decl_context == PARM && storage_class == csc_register)
; ;
else else
{ {
switch (decl_context) switch (decl_context)
{ {
case FIELD: case FIELD:
error ("storage class specified for structure field `%s'", error ("storage class specified for structure field %qs",
name); name);
break; break;
case PARM: case PARM:
error ("storage class specified for parameter `%s'", name); error ("storage class specified for parameter %qs", name);
break; break;
default: default:
error ("storage class specified for typename"); error ("storage class specified for typename");
break; break;
} }
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) storage_class = csc_none;
| (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) threadp = false;
| (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
} }
} }
else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag) else if (storage_class == csc_extern
&& initialized
&& !funcdef_flag)
{ {
/* `extern' with initialization is invalid if not at file scope. */ /* 'extern' with initialization is invalid if not at file scope. */
if (current_scope == file_scope) if (current_scope == file_scope)
warning ("`%s' initialized and declared `extern'", name); warning ("%qs initialized and declared %<extern%>", name);
else else
error ("`%s' has both `extern' and initializer", name); error ("%qs has both %<extern%> and initializer", name);
} }
else if (current_scope == file_scope) else if (current_scope == file_scope)
{ {
if (specbits & 1 << (int) RID_AUTO) if (storage_class == csc_auto)
error ("file-scope declaration of `%s' specifies `auto'", name); 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 else
{ {
if (specbits & 1 << (int) RID_EXTERN && funcdef_flag) if (storage_class == csc_extern && funcdef_flag)
error ("nested function `%s' declared `extern'", name); error ("nested function `%s' declared `extern'", name);
else if ((specbits & (1 << (int) RID_THREAD else if (threadp && storage_class == csc_none)
| 1 << (int) RID_EXTERN
| 1 << (int) RID_STATIC))
== (1 << (int) RID_THREAD))
{ {
error ("function-scope `%s' implicitly auto and declared `__thread'", error ("function-scope %qs implicitly auto and declared "
"%<__thread%>",
name); name);
specbits &= ~(1 << (int) RID_THREAD); threadp = false;
}
} }
} }
...@@ -4337,7 +4350,7 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4337,7 +4350,7 @@ grokdeclarator (const struct c_declarator *declarator,
/* If this is declaring a typedef name, return a TYPE_DECL. */ /* If this is declaring a typedef name, return a TYPE_DECL. */
if (specbits & (1 << (int) RID_TYPEDEF)) if (storage_class == csc_typedef)
{ {
tree decl; tree decl;
/* Note that the grammar rejects storage classes /* Note that the grammar rejects storage classes
...@@ -4394,10 +4407,10 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4394,10 +4407,10 @@ grokdeclarator (const struct c_declarator *declarator,
if (VOID_TYPE_P (type) && decl_context != PARM if (VOID_TYPE_P (type) && decl_context != PARM
&& ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) && ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE)
&& ((specbits & (1 << (int) RID_EXTERN)) && (storage_class == csc_extern
|| (current_scope == file_scope || (current_scope == file_scope
&& !(specbits && !(storage_class == csc_static
& ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))))))) || storage_class == csc_register)))))
{ {
error ("variable or field `%s' declared void", name); error ("variable or field `%s' declared void", name);
type = integer_type_node; type = integer_type_node;
...@@ -4508,8 +4521,7 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4508,8 +4521,7 @@ grokdeclarator (const struct c_declarator *declarator,
} }
else if (TREE_CODE (type) == FUNCTION_TYPE) else if (TREE_CODE (type) == FUNCTION_TYPE)
{ {
if (specbits & (1 << (int) RID_REGISTER) if (storage_class == csc_register || threadp)
|| specbits & (1 << (int) RID_THREAD))
error ("invalid storage class for function `%s'", name); error ("invalid storage class for function `%s'", name);
else if (current_scope != file_scope) else if (current_scope != file_scope)
{ {
...@@ -4518,12 +4530,12 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4518,12 +4530,12 @@ grokdeclarator (const struct c_declarator *declarator,
6.7.1p5, and `extern' makes no difference. However, 6.7.1p5, and `extern' makes no difference. However,
GCC allows 'auto', perhaps with 'inline', to support GCC allows 'auto', perhaps with 'inline', to support
nested functions. */ nested functions. */
if (specbits & (1 << (int) RID_AUTO)) if (storage_class == csc_auto)
{ {
if (pedantic) if (pedantic)
pedwarn ("invalid storage class for function `%s'", name); 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); error ("invalid storage class for function `%s'", name);
} }
...@@ -4546,14 +4558,14 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4546,14 +4558,14 @@ grokdeclarator (const struct c_declarator *declarator,
scope and are explicitly declared "auto". This is scope and are explicitly declared "auto". This is
forbidden by standard C (C99 6.7.1p5) and is interpreted by forbidden by standard C (C99 6.7.1p5) and is interpreted by
GCC to signify a forward declaration of a nested function. */ 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; DECL_EXTERNAL (decl) = 0;
else else
DECL_EXTERNAL (decl) = 1; DECL_EXTERNAL (decl) = 1;
/* Record absence of global scope for `static' or `auto'. */ /* Record absence of global scope for `static' or `auto'. */
TREE_PUBLIC (decl) 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 /* For a function definition, record the argument information
block where store_parm_decls will look for it. */ block where store_parm_decls will look for it. */
...@@ -4566,10 +4578,10 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4566,10 +4578,10 @@ grokdeclarator (const struct c_declarator *declarator,
/* Record presence of `inline', if it is reasonable. */ /* Record presence of `inline', if it is reasonable. */
if (MAIN_NAME_P (declarator->u.id)) if (MAIN_NAME_P (declarator->u.id))
{ {
if (inlinep) if (declspecs->inline_p)
warning ("cannot inline function `main'"); warning ("cannot inline function `main'");
} }
else if (inlinep) else if (declspecs->inline_p)
{ {
/* Record that the function is declared `inline'. */ /* Record that the function is declared `inline'. */
DECL_DECLARED_INLINE_P (decl) = 1; DECL_DECLARED_INLINE_P (decl) = 1;
...@@ -4581,7 +4593,7 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4581,7 +4593,7 @@ grokdeclarator (const struct c_declarator *declarator,
if (initialized) if (initialized)
{ {
DECL_INLINE (decl) = 1; DECL_INLINE (decl) = 1;
if (specbits & (1 << (int) RID_EXTERN)) if (storage_class == csc_extern)
current_extern_inline = 1; current_extern_inline = 1;
} }
} }
...@@ -4595,7 +4607,7 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4595,7 +4607,7 @@ grokdeclarator (const struct c_declarator *declarator,
{ {
/* It's a variable. */ /* It's a variable. */
/* An uninitialized decl with `extern' is a reference. */ /* 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. */ /* Move type qualifiers down to element of an array. */
if (TREE_CODE (type) == ARRAY_TYPE && type_quals) if (TREE_CODE (type) == ARRAY_TYPE && type_quals)
...@@ -4632,13 +4644,13 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4632,13 +4644,13 @@ grokdeclarator (const struct c_declarator *declarator,
if (size_varies) if (size_varies)
C_DECL_VARIABLE_SIZE (decl) = 1; C_DECL_VARIABLE_SIZE (decl) = 1;
if (inlinep) if (declspecs->inline_p)
pedwarn ("%Jvariable '%D' declared `inline'", decl, decl); pedwarn ("%Jvariable '%D' declared `inline'", decl, decl);
/* At file scope, an initialized extern declaration may follow /* At file scope, an initialized extern declaration may follow
a static declaration. In that case, DECL_EXTERNAL will be a static declaration. In that case, DECL_EXTERNAL will be
reset later in start_decl. */ 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 /* At file scope, the presence of a `static' or `register' storage
class specifier, or the absence of all storage class specifiers class specifier, or the absence of all storage class specifiers
...@@ -4646,18 +4658,18 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4646,18 +4658,18 @@ grokdeclarator (const struct c_declarator *declarator,
the absence of both `static' and `register' makes it public. */ the absence of both `static' and `register' makes it public. */
if (current_scope == file_scope) if (current_scope == file_scope)
{ {
TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC) TREE_PUBLIC (decl) = !(storage_class == csc_static
| (1 << (int) RID_REGISTER))); || storage_class == csc_register);
TREE_STATIC (decl) = !extern_ref; TREE_STATIC (decl) = !extern_ref;
} }
/* Not at file scope, only `static' makes a static definition. */ /* Not at file scope, only `static' makes a static definition. */
else else
{ {
TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; TREE_STATIC (decl) = (storage_class == csc_static);
TREE_PUBLIC (decl) = extern_ref; TREE_PUBLIC (decl) = extern_ref;
} }
if (specbits & 1 << (int) RID_THREAD) if (threadp)
{ {
if (targetm.have_tls) if (targetm.have_tls)
DECL_THREAD_LOCAL (decl) = 1; DECL_THREAD_LOCAL (decl) = 1;
...@@ -4671,7 +4683,7 @@ grokdeclarator (const struct c_declarator *declarator, ...@@ -4671,7 +4683,7 @@ grokdeclarator (const struct c_declarator *declarator,
/* Record `register' declaration for warnings on & /* Record `register' declaration for warnings on &
and in case doing stupid register allocation. */ and in case doing stupid register allocation. */
if (specbits & (1 << (int) RID_REGISTER)) if (storage_class == csc_register)
{ {
C_DECL_REGISTER (decl) = 1; C_DECL_REGISTER (decl) = 1;
DECL_REGISTER (decl) = 1; DECL_REGISTER (decl) = 1;
...@@ -6720,6 +6732,7 @@ build_null_declspecs (void) ...@@ -6720,6 +6732,7 @@ build_null_declspecs (void)
ret->decl_attr = 0; ret->decl_attr = 0;
ret->attrs = 0; ret->attrs = 0;
ret->specbits = 0; ret->specbits = 0;
ret->storage_class = csc_none;
ret->non_sc_seen_p = false; ret->non_sc_seen_p = false;
ret->typedef_p = false; ret->typedef_p = false;
ret->typedef_signed_p = false; ret->typedef_signed_p = false;
...@@ -6727,6 +6740,8 @@ build_null_declspecs (void) ...@@ -6727,6 +6740,8 @@ build_null_declspecs (void)
ret->explicit_int_p = false; ret->explicit_int_p = false;
ret->explicit_char_p = false; ret->explicit_char_p = false;
ret->long_long_p = false; ret->long_long_p = false;
ret->inline_p = false;
ret->thread_p = false;
return ret; return ret;
} }
...@@ -6826,23 +6841,79 @@ struct c_declspecs * ...@@ -6826,23 +6841,79 @@ struct c_declspecs *
declspecs_add_scspec (struct c_declspecs *specs, tree scspec) declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
{ {
enum rid i; enum rid i;
enum c_storage_class n = csc_none;
bool dupe = false;
gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
&& C_IS_RESERVED_WORD (scspec)); && C_IS_RESERVED_WORD (scspec));
i = C_RID_CODE (scspec); i = C_RID_CODE (scspec);
if (extra_warnings && specs->non_sc_seen_p) if (extra_warnings && specs->non_sc_seen_p)
warning ("%qs is not at beginning of declaration", warning ("%qs is not at beginning of declaration",
IDENTIFIER_POINTER (scspec)); IDENTIFIER_POINTER (scspec));
if (specs->specbits & (1 << (int) i)) switch (i)
error ("duplicate %qs", IDENTIFIER_POINTER (scspec)); {
/* Diagnose "__thread extern" and "__thread static". */ case RID_INLINE:
if (specs->specbits & (1 << (int) RID_THREAD)) /* GCC has hitherto given an error for duplicate inline, but
{ this should be revisited since C99 permits duplicate
if (i == RID_EXTERN) 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%>"); 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%>"); 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; return specs;
} }
......
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> 2004-09-11 Zack Weinberg <zack@codesourcery.com>
* gcc.dg/20040910-1.c: Correct dg-error regexp. * gcc.dg/20040910-1.c: Correct dg-error regexp.
......
/* { dg-do compile { target i?86-*-* } } */ /* { dg-do compile { target i?86-*-* } } */
/* { dg-options "-ansi -pedantic" } */
int foo () int foo ()
{ {
return 1; 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'" } */
/* 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'" } */
/* 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'" } */
...@@ -22,7 +22,7 @@ int; /* { dg-warning "warning: useless type name in empty declaration" } */ ...@@ -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" } */ long; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
/* { dg-warning "warning: empty declaration" "long" { target *-*-* } 22 } */ /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 22 } */
T; /* { dg-warning "warning: useless type name in empty declaration" } */ 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 } */ /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 25 } */
union { long b; }; /* { dg-warning "warning: unnamed struct/union that defines no instances" } */ union { long b; }; /* { dg-warning "warning: unnamed struct/union that defines no instances" } */
......
...@@ -22,7 +22,7 @@ int; /* { dg-warning "warning: useless type name in empty declaration" } */ ...@@ -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" } */ long; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
/* { dg-warning "warning: empty declaration" "long" { target *-*-* } 22 } */ /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 22 } */
T; /* { dg-warning "warning: useless type name in empty declaration" } */ 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 } */ /* { dg-warning "warning: empty declaration" "long" { target *-*-* } 25 } */
union { long b; }; /* { dg-warning "warning: unnamed struct/union that defines no instances" } */ union { long b; }; /* { dg-warning "warning: unnamed struct/union that defines no instances" } */
......
...@@ -22,7 +22,7 @@ int; /* { dg-error "error: useless type name in empty declaration" } */ ...@@ -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" } */ long; /* { dg-warning "warning: useless keyword or type name in empty declaration" } */
/* { dg-error "error: empty declaration" "long" { target *-*-* } 22 } */ /* { dg-error "error: empty declaration" "long" { target *-*-* } 22 } */
T; /* { dg-error "error: useless type name in empty declaration" } */ 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 } */ /* { dg-error "error: empty declaration" "long" { target *-*-* } 25 } */
union { long b; }; /* { dg-error "error: unnamed struct/union that defines no instances" } */ union { long b; }; /* { dg-error "error: unnamed struct/union that defines no instances" } */
......
/* 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;
/* 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" } */
}
/* 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'" } */
/* 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" } */
}
/* 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" } */
}
...@@ -3,19 +3,19 @@ ...@@ -3,19 +3,19 @@
__thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */ __thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */
__thread static int g2; /* { dg-error "'__thread' before 'static'" } */ __thread static int g2; /* { dg-error "'__thread' before 'static'" } */
__thread __thread int g3; /* { dg-error "duplicate '__thread'" } */ __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() void foo()
{ {
__thread int l1; /* { dg-error "implicitly auto and declared `__thread'" } */ __thread int l1; /* { dg-error "implicitly auto and declared '__thread'" } */
auto __thread int l2; /* { dg-error "multiple storage classes" } */ auto __thread int l2; /* { dg-error "'__thread' used with 'auto'" } */
__thread extern int l3; /* { dg-error "'__thread' before 'extern'" } */ __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" } */ __thread void f1 (); /* { dg-error "invalid storage class for function" } */
extern __thread void f2 (); /* { 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" } */ 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" } */ void bar(__thread int p1); /* { dg-error "storage class specified for parameter" } */
/* 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'" } */
}
/* __thread specifiers on empty declarations. */
__thread struct foo; /* { dg-warning "warning: useless '__thread' in empty declaration" } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment