#include "langhooks-def.h"
#include "pointer-set.h"
+/* Set this to 1 if you want the standard ISO C99 semantics of 'inline'
+ when you specify -std=c99 or -std=gnu99, and to 0 if you want
+ behaviour compatible with the nonstandard semantics implemented by
+ GCC 2.95 through 4.2. */
+#define WANT_C99_INLINE_SEMANTICS 1
+
/* In grokdeclarator, distinguish syntactic contexts of declarators. */
enum decl_context
{ NORMAL, /* Ordinary declaration */
static int warn_about_return_type;
-/* Nonzero when starting a function declared `extern inline'. */
-
-static int current_extern_inline;
-
/* Nonzero when the current toplevel function contains a declaration
of a nested function which is never defined. */
declarations. */
BOOL_BITFIELD parm_flag : 1;
+ /* True if we saw [*] in this scope. Used to give an error messages
+ if these appears in a function definition. */
+ BOOL_BITFIELD had_vla_unspec : 1;
+
/* True if we already complained about forward parameter decls
in this scope. This prevents double warnings on
foo (int a; int b; ...) */
TREE_CHAIN (p) = BLOCK_VARS (block);
BLOCK_VARS (block) = p;
gcc_assert (I_LABEL_BINDING (b->id) == b);
- I_LABEL_BINDING (b->id) = b->shadowed;
- break;
+ I_LABEL_BINDING (b->id) = b->shadowed;
+ break;
case ENUMERAL_TYPE:
case UNION_TYPE:
gcc_assert (I_TAG_BINDING (b->id) == b);
I_TAG_BINDING (b->id) = b->shadowed;
}
- break;
+ break;
case FUNCTION_DECL:
/* Propagate TREE_ADDRESSABLE from nested functions to their
&& DECL_ABSTRACT_ORIGIN (p) != p)
TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1;
if (!DECL_EXTERNAL (p)
- && DECL_INITIAL (p) == 0)
+ && !DECL_INITIAL (p)
+ && scope != file_scope
+ && scope != external_scope)
{
error ("nested function %q+D declared but never defined", p);
undef_nested_function = true;
}
+ /* C99 6.7.4p6: "a function with external linkage... declared
+ with an inline function specifier ... shall also be defined in the
+ same translation unit." */
+ else if (DECL_DECLARED_INLINE_P (p)
+ && TREE_PUBLIC (p)
+ && !DECL_INITIAL (p)
+ && flag_isoc99)
+ pedwarn ("inline function %q+D declared but never defined", p);
+
goto common_symbol;
case VAR_DECL:
/* Warnings for unused variables. */
if (!TREE_USED (p)
+ && !TREE_NO_WARNING (p)
&& !DECL_IN_SYSTEM_HEADER (p)
&& DECL_NAME (p)
&& !DECL_ARTIFICIAL (p)
&& scope != file_scope
- && scope != external_scope)
+ && scope != external_scope)
warning (OPT_Wunused_variable, "unused variable %q+D", p);
if (b->inner_comp)
for (;;)
{
- tree oldargtype = TYPE_MAIN_VARIANT (TREE_VALUE (oldargs));
- tree newargtype = TYPE_MAIN_VARIANT (TREE_VALUE (newargs));
+ tree oldargtype = TREE_VALUE (oldargs);
+ tree newargtype = TREE_VALUE (newargs);
+
+ if (oldargtype == error_mark_node || newargtype == error_mark_node)
+ return false;
+
+ oldargtype = TYPE_MAIN_VARIANT (oldargtype);
+ newargtype = TYPE_MAIN_VARIANT (newargtype);
if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype))
break;
/* Function declarations can either be 'static' or 'extern' (no
qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore
- can never conflict with each other on account of linkage (6.2.2p4).
- Multiple definitions are not allowed (6.9p3,5) but GCC permits
- two definitions if one is 'extern inline' and one is not. The non-
- extern-inline definition supersedes the extern-inline definition. */
+ can never conflict with each other on account of linkage
+ (6.2.2p4). Multiple definitions are not allowed (6.9p3,5) but
+ gnu89 mode permits two definitions if one is 'extern inline' and
+ one is not. The non- extern-inline definition supersedes the
+ extern-inline definition. */
else if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
{
/* If both decls are in the same TU and the new declaration
isn't overriding an extern inline reject the new decl.
- When we handle c99 style inline rules we'll want to reject
- the following:
-
- DECL_EXTERN_INLINE (olddecl)
- && !DECL_EXTERN_INLINE (newdecl)
-
- if they're in the same translation unit. Until we implement
- the full semantics we accept the construct. */
- if (!(DECL_EXTERN_INLINE (olddecl)
- && !DECL_EXTERN_INLINE (newdecl))
+ In c99, no overriding is allowed in the same translation
+ unit. */
+ if ((!DECL_EXTERN_INLINE (olddecl)
+ || DECL_EXTERN_INLINE (newdecl)
+#if WANT_C99_INLINE_SEMANTICS
+ || (flag_isoc99
+ && (!DECL_DECLARED_INLINE_P (olddecl)
+ || !lookup_attribute ("gnu_inline",
+ DECL_ATTRIBUTES (olddecl)))
+ && (!DECL_DECLARED_INLINE_P (newdecl)
+ || !lookup_attribute ("gnu_inline",
+ DECL_ATTRIBUTES (newdecl))))
+#endif /* WANT_C99_INLINE_SEMANTICS */
+ )
&& same_translation_unit_p (newdecl, olddecl))
{
error ("redefinition of %q+D", newdecl);
warned = true;
}
}
+
+ /* Make sure gnu_inline attribute is either not present, or
+ present on all inline decls. */
+ if (DECL_DECLARED_INLINE_P (olddecl)
+ && DECL_DECLARED_INLINE_P (newdecl))
+ {
+ bool newa = lookup_attribute ("gnu_inline",
+ DECL_ATTRIBUTES (newdecl)) != NULL;
+ bool olda = lookup_attribute ("gnu_inline",
+ DECL_ATTRIBUTES (olddecl)) != NULL;
+ if (newa != olda)
+ {
+ error ("%<gnu_inline%> attribute present on %q+D",
+ newa ? newdecl : olddecl);
+ error ("%Jbut not here", newa ? olddecl : newdecl);
+ }
+ }
}
else if (TREE_CODE (newdecl) == VAR_DECL)
{
/* Only variables can be thread-local, and all declarations must
agree on this property. */
- if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl))
+ if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (newdecl))
+ {
+ /* Nothing to check. Since OLDDECL is marked threadprivate
+ and NEWDECL does not have a thread-local attribute, we
+ will merge the threadprivate attribute into NEWDECL. */
+ ;
+ }
+ else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl))
{
if (DECL_THREAD_LOCAL_P (newdecl))
error ("thread-local declaration of %q+D follows "
/* warnings */
/* All decls must agree on a visibility. */
- if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS)
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS)
&& DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl)
&& DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
{
??? Should we still warn about this now we have unit-at-a-time
mode and can get it right?
Definitely don't complain if the decls are in different translation
- units. */
+ units.
+ C99 permits this, so don't warn in that case. (The function
+ may not be inlined everywhere in function-at-a-time mode, but
+ we still shouldn't warn.) */
if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)
- && same_translation_unit_p (olddecl, newdecl))
+ && same_translation_unit_p (olddecl, newdecl)
+ && ! flag_isoc99)
{
if (TREE_USED (olddecl))
{
static void
merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
{
- int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
- && DECL_INITIAL (newdecl) != 0);
- int new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL
- && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0);
- int old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
- && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
+ bool new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_INITIAL (newdecl) != 0);
+ bool new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL
+ && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0);
+ bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
+ && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
+ bool extern_changed = false;
/* For real parm decl following a forward decl, rechain the old decl
in its new location and clear TREE_ASM_WRITTEN (it's not a
if (DECL_INITIAL (newdecl) == 0)
DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
- if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
- {
- /* Merge the unused-warning information. */
- if (DECL_IN_SYSTEM_HEADER (olddecl))
- DECL_IN_SYSTEM_HEADER (newdecl) = 1;
- else if (DECL_IN_SYSTEM_HEADER (newdecl))
- DECL_IN_SYSTEM_HEADER (olddecl) = 1;
-
- /* Merge the section attribute.
- We want to issue an error if the sections conflict but that must be
- done later in decl_attributes since we are called before attributes
- are assigned. */
- if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
- DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
-
- /* Copy the assembler name.
- Currently, it can only be defined in the prototype. */
- COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
-
- /* Use visibility of whichever declaration had it specified */
- if (DECL_VISIBILITY_SPECIFIED (olddecl))
- {
- DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
- DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
- }
-
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
- {
- DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
- DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
- DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
- DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
- |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
- TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
- TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
- DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
- DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
- DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
- }
-
- /* Merge the storage class information. */
- merge_weak (newdecl, olddecl);
+ /* Merge the threadprivate attribute. */
+ if (TREE_CODE (olddecl) == VAR_DECL && C_DECL_THREADPRIVATE_P (olddecl))
+ {
+ DECL_TLS_MODEL (newdecl) = DECL_TLS_MODEL (olddecl);
+ C_DECL_THREADPRIVATE_P (newdecl) = 1;
+ }
- /* For functions, static overrides non-static. */
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
- {
- TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
- /* This is since we don't automatically
- copy the attributes of NEWDECL into OLDDECL. */
- TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
- /* If this clears `static', clear it in the identifier too. */
- if (!TREE_PUBLIC (olddecl))
- TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
- }
- }
-
- if (DECL_EXTERNAL (newdecl))
- {
- TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
- DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
-
- /* An extern decl does not override previous storage class. */
- TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
- if (!DECL_EXTERNAL (newdecl))
- {
- DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
- DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
- }
- }
- else
- {
- TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
- TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
- }
-
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
- {
- /* If we're redefining a function previously defined as extern
- inline, make sure we emit debug info for the inline before we
- throw it away, in case it was inlined into a function that hasn't
- been written out yet. */
- if (new_is_definition && DECL_INITIAL (olddecl))
- {
- if (TREE_USED (olddecl)
- /* In unit-at-a-time mode we never inline re-defined extern
- inline functions. */
- && !flag_unit_at_a_time
- && cgraph_function_possibly_inlined_p (olddecl))
- (*debug_hooks->outlining_inline_function) (olddecl);
-
- /* The new defn must not be inline. */
- DECL_INLINE (newdecl) = 0;
- DECL_UNINLINABLE (newdecl) = 1;
- }
- else
- {
- /* If either decl says `inline', this fn is inline,
- unless its definition was passed already. */
- if (DECL_DECLARED_INLINE_P (newdecl)
- || DECL_DECLARED_INLINE_P (olddecl))
- DECL_DECLARED_INLINE_P (newdecl) = 1;
-
- DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
- = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
- }
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
+ {
+ /* Merge the unused-warning information. */
+ if (DECL_IN_SYSTEM_HEADER (olddecl))
+ DECL_IN_SYSTEM_HEADER (newdecl) = 1;
+ else if (DECL_IN_SYSTEM_HEADER (newdecl))
+ DECL_IN_SYSTEM_HEADER (olddecl) = 1;
- if (DECL_BUILT_IN (olddecl))
- {
- /* If redeclaring a builtin function, it stays built in.
- But it gets tagged as having been declared. */
- DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
- DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
- C_DECL_DECLARED_BUILTIN (newdecl) = 1;
- if (new_is_prototype)
- C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
- else
- C_DECL_BUILTIN_PROTOTYPE (newdecl)
- = C_DECL_BUILTIN_PROTOTYPE (olddecl);
- }
+ /* Merge the section attribute.
+ We want to issue an error if the sections conflict but that
+ must be done later in decl_attributes since we are called
+ before attributes are assigned. */
+ if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
+ DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
- /* Also preserve various other info from the definition. */
- if (!new_is_definition)
- {
- DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
- DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
- DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl);
- DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
- DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
-
- /* Set DECL_INLINE on the declaration if we've got a body
- from which to instantiate. */
- if (DECL_INLINE (olddecl) && !DECL_UNINLINABLE (newdecl))
- {
- DECL_INLINE (newdecl) = 1;
- DECL_ABSTRACT_ORIGIN (newdecl)
- = DECL_ABSTRACT_ORIGIN (olddecl);
- }
- }
- else
- {
- /* If a previous declaration said inline, mark the
- definition as inlinable. */
- if (DECL_DECLARED_INLINE_P (newdecl)
- && !DECL_UNINLINABLE (newdecl))
- DECL_INLINE (newdecl) = 1;
- }
- }
-
- /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
+ /* Copy the assembler name.
+ Currently, it can only be defined in the prototype. */
+ COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
+
+ /* Use visibility of whichever declaration had it specified */
+ if (DECL_VISIBILITY_SPECIFIED (olddecl))
+ {
+ DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+ DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
+ }
+
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ {
+ DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
+ DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
+ DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
+ |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+ TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+ TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+ DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+ DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
+ DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
+ }
+
+ /* Merge the storage class information. */
+ merge_weak (newdecl, olddecl);
+
+ /* For functions, static overrides non-static. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ {
+ TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
+ /* This is since we don't automatically
+ copy the attributes of NEWDECL into OLDDECL. */
+ TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+ /* If this clears `static', clear it in the identifier too. */
+ if (!TREE_PUBLIC (olddecl))
+ TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
+ }
+ }
+
+#if WANT_C99_INLINE_SEMANTICS
+ /* In c99, 'extern' declaration before (or after) 'inline' means this
+ function is not DECL_EXTERNAL, unless 'gnu_inline' attribute
+ is present. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && flag_isoc99
+ && (DECL_DECLARED_INLINE_P (newdecl)
+ || DECL_DECLARED_INLINE_P (olddecl))
+ && (!DECL_DECLARED_INLINE_P (newdecl)
+ || !DECL_DECLARED_INLINE_P (olddecl)
+ || !DECL_EXTERNAL (olddecl))
+ && DECL_EXTERNAL (newdecl)
+ && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl)))
+ DECL_EXTERNAL (newdecl) = 0;
+#endif /* WANT_C99_INLINE_SEMANTICS */
+
+ if (DECL_EXTERNAL (newdecl))
+ {
+ TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
+ DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
+
+ /* An extern decl does not override previous storage class. */
+ TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
+ if (!DECL_EXTERNAL (newdecl))
+ {
+ DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
+ DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
+ }
+ }
+ else
+ {
+ TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
+ TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+ }
+
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ {
+ /* If we're redefining a function previously defined as extern
+ inline, make sure we emit debug info for the inline before we
+ throw it away, in case it was inlined into a function that
+ hasn't been written out yet. */
+ if (new_is_definition && DECL_INITIAL (olddecl))
+ {
+ if (TREE_USED (olddecl)
+ /* In unit-at-a-time mode we never inline re-defined extern
+ inline functions. */
+ && !flag_unit_at_a_time
+ && cgraph_function_possibly_inlined_p (olddecl))
+ (*debug_hooks->outlining_inline_function) (olddecl);
+
+ /* The new defn must not be inline. */
+ DECL_INLINE (newdecl) = 0;
+ DECL_UNINLINABLE (newdecl) = 1;
+ }
+ else
+ {
+ /* If either decl says `inline', this fn is inline, unless
+ its definition was passed already. */
+ if (DECL_DECLARED_INLINE_P (newdecl)
+ || DECL_DECLARED_INLINE_P (olddecl))
+ DECL_DECLARED_INLINE_P (newdecl) = 1;
+
+ DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
+ = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
+ }
+
+ if (DECL_BUILT_IN (olddecl))
+ {
+ /* If redeclaring a builtin function, it stays built in.
+ But it gets tagged as having been declared. */
+ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+ DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ C_DECL_DECLARED_BUILTIN (newdecl) = 1;
+ if (new_is_prototype)
+ C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
+ else
+ C_DECL_BUILTIN_PROTOTYPE (newdecl)
+ = C_DECL_BUILTIN_PROTOTYPE (olddecl);
+ }
+
+ /* Also preserve various other info from the definition. */
+ if (!new_is_definition)
+ {
+ DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+ DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl);
+ DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
+ DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+
+ /* Set DECL_INLINE on the declaration if we've got a body
+ from which to instantiate. */
+ if (DECL_INLINE (olddecl) && !DECL_UNINLINABLE (newdecl))
+ {
+ DECL_INLINE (newdecl) = 1;
+ DECL_ABSTRACT_ORIGIN (newdecl)
+ = DECL_ABSTRACT_ORIGIN (olddecl);
+ }
+ }
+ else
+ {
+ /* If a previous declaration said inline, mark the
+ definition as inlinable. */
+ if (DECL_DECLARED_INLINE_P (newdecl)
+ && !DECL_UNINLINABLE (newdecl))
+ DECL_INLINE (newdecl) = 1;
+ }
+ }
+
+ extern_changed = DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl);
+
+ /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
But preserve OLDDECL's DECL_UID and DECL_CONTEXT. */
{
unsigned olddecl_uid = DECL_UID (olddecl);
tree olddecl_context = DECL_CONTEXT (olddecl);
-
+
memcpy ((char *) olddecl + sizeof (struct tree_common),
(char *) newdecl + sizeof (struct tree_common),
sizeof (struct tree_decl_common) - sizeof (struct tree_common));
break;
default:
-
+
memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
(char *) newdecl + sizeof (struct tree_decl_common),
sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common));
|| (TREE_CODE (olddecl) == VAR_DECL
&& TREE_STATIC (olddecl))))
make_decl_rtl (olddecl);
+
+ /* If we changed a function from DECL_EXTERNAL to !DECL_EXTERNAL,
+ and the definition is coming from the old version, cgraph needs
+ to be called again. */
+ if (extern_changed && !new_is_definition
+ && TREE_CODE (olddecl) == FUNCTION_DECL && DECL_INITIAL (olddecl))
+ cgraph_finalize_function (olddecl, false);
}
/* Handle when a new declaration NEWDECL has the same name as an old
tree newtype = NULL, oldtype = NULL;
if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype))
- return false;
+ {
+ /* Avoid `unused variable' and other warnings warnings for OLDDECL. */
+ TREE_NO_WARNING (olddecl) = 1;
+ return false;
+ }
merge_decls (newdecl, olddecl, newtype, oldtype);
return true;
translation and get back the corresponding typedef name. For
example, given:
- typedef struct S MY_TYPE;
+ typedef struct S MY_TYPE;
MY_TYPE object;
Later parts of the compiler might only know that `object' was of
}
/* If we are parsing old-style parameter decls, current_function_decl
- will be nonnull but current_function_scope will be null. */
+ will be nonnull but current_function_scope will be null. */
scope = current_function_scope ? current_function_scope : current_scope;
}
bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false);
if (!in_system_header && lookup_name (name))
warning (OPT_Wtraditional, "%Htraditional C lacks a separate namespace "
- "for labels, identifier %qE conflicts", &location, name);
+ "for labels, identifier %qE conflicts", &location, name);
nlist_se = XOBNEW (&parser_obstack, struct c_label_list);
nlist_se->next = label_context_stack_se->labels_def;
{
if (pending_invalid_xref != 0)
error ("%H%qE defined as wrong kind of tag",
- &pending_invalid_xref_location, pending_invalid_xref);
+ &pending_invalid_xref_location, pending_invalid_xref);
pending_invalid_xref = 0;
}
TREE_USED (decl) = 1;
- if (current_function_decl)
+ if (current_function_decl
+ /* For invalid programs like this:
+
+ void foo()
+ const char* p = __FUNCTION__;
+
+ the __FUNCTION__ is believed to appear in K&R style function
+ parameter declarator. In that case we still don't have
+ function_scope. */
+ && (!errorcount || current_function_scope))
{
DECL_CONTEXT (decl) = current_function_decl;
bind (id, decl, current_function_scope,
return decl;
}
-/* Return a definition for a builtin function named NAME and whose data type
- is TYPE. TYPE should be a function type with argument types.
- FUNCTION_CODE tells later passes how to compile calls to this function.
- See tree.h for its possible values.
-
- If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
- the name to be called if we can't opencode the function. If
- ATTRS is nonzero, use that for the function's attribute list. */
-
tree
-builtin_function (const char *name, tree type, int function_code,
- enum built_in_class cl, const char *library_name,
- tree attrs)
+c_builtin_function (tree decl)
{
- tree id = get_identifier (name);
- tree decl = build_decl (FUNCTION_DECL, id, type);
- TREE_PUBLIC (decl) = 1;
- DECL_EXTERNAL (decl) = 1;
+ tree type = TREE_TYPE (decl);
+ tree id = DECL_NAME (decl);
+
+ const char *name = IDENTIFIER_POINTER (id);
DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
- DECL_BUILT_IN_CLASS (decl) = cl;
- DECL_FUNCTION_CODE (decl) = function_code;
C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
- if (library_name)
- SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
/* Should never be called on a symbol with a preexisting meaning. */
gcc_assert (!I_SYMBOL_BINDING (id));
visible_builtins = decl;
}
- /* Possibly apply some default attributes to this built-in function. */
- if (attrs)
- decl_attributes (&decl, attrs, ATTR_FLAG_BUILT_IN);
- else
- decl_attributes (&decl, NULL_TREE, 0);
-
return decl;
}
\f
return quals;
}
-/* Construct an array declarator. EXPR is the expression inside [], or
- NULL_TREE. QUALS are the type qualifiers inside the [] (to be applied
- to the pointer to which a parameter array is converted). STATIC_P is
- true if "static" is inside the [], false otherwise. VLA_UNSPEC_P
- is true if the array is [*], a VLA of unspecified length which is
- nevertheless a complete type (not currently implemented by GCC),
- false otherwise. The field for the contained declarator is left to be
- filled in by set_array_declarator_inner. */
+/* Construct an array declarator. EXPR is the expression inside [],
+ or NULL_TREE. QUALS are the type qualifiers inside the [] (to be
+ applied to the pointer to which a parameter array is converted).
+ STATIC_P is true if "static" is inside the [], false otherwise.
+ VLA_UNSPEC_P is true if the array is [*], a VLA of unspecified
+ length which is nevertheless a complete type, false otherwise. The
+ field for the contained declarator is left to be filled in by
+ set_array_declarator_inner. */
struct c_declarator *
build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p,
pedwarn ("ISO C90 does not support %<[*]%> array declarators");
}
if (vla_unspec_p)
- warning (0, "GCC does not yet properly implement %<[*]%> array declarators");
+ {
+ if (!current_scope->parm_flag)
+ {
+ /* C99 6.7.5.2p4 */
+ error ("%<[*]%> not allowed in other than function prototype scope");
+ declarator->u.array.vla_unspec_p = false;
+ return NULL;
+ }
+ current_scope->had_vla_unspec = true;
+ }
return declarator;
}
error ("static or type qualifiers in abstract declarator");
return decl;
}
+
+/* INIT is a constructor that forms DECL's initializer. If the final
+ element initializes a flexible array field, add the size of that
+ initializer to DECL's size. */
+
+static void
+add_flexible_array_elts_to_size (tree decl, tree init)
+{
+ tree elt, type;
+
+ if (VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (init)))
+ return;
+
+ elt = VEC_last (constructor_elt, CONSTRUCTOR_ELTS (init))->value;
+ type = TREE_TYPE (elt);
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_SIZE (type) == NULL_TREE
+ && TYPE_DOMAIN (type) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ {
+ complete_array_type (&type, elt, false);
+ DECL_SIZE (decl)
+ = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
+ DECL_SIZE_UNIT (decl)
+ = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type));
+ }
+}
\f
/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
/* Set attributes here so if duplicate decl, will have proper attributes. */
decl_attributes (&decl, attributes, 0);
+#if WANT_C99_INLINE_SEMANTICS
+ /* Handle gnu_inline attribute. */
+ if (declspecs->inline_p
+ && flag_isoc99
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
+ {
+ if (declspecs->storage_class == csc_auto && current_scope != file_scope)
+ ;
+ else if (declspecs->storage_class != csc_static)
+ DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl);
+ }
+#endif /* WANT_C99_INLINE_SEMANTICS */
+
if (TREE_CODE (decl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (decl)))
{
warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
decl);
+ /* C99 6.7.4p3: An inline definition of a function with external
+ linkage shall not contain a definition of a modifiable object
+ with static storage duration... */
+ if (TREE_CODE (decl) == VAR_DECL
+ && current_scope != file_scope
+ && TREE_STATIC (decl)
+ && DECL_DECLARED_INLINE_P (current_function_decl)
+ && DECL_EXTERNAL (current_function_decl))
+ pedwarn ("%q+D is static but declared in inline function %qD "
+ "which is not static", decl, current_function_decl);
+
/* Add this decl to the current scope.
TEM may equal DECL or it may be a previous decl of the same name. */
tem = pushdecl (decl);
if (TREE_CODE (decl) == VAR_DECL)
{
+ if (init && TREE_CODE (init) == CONSTRUCTOR)
+ add_flexible_array_elts_to_size (decl, init);
+
if (DECL_SIZE (decl) == 0 && TREE_TYPE (decl) != error_mark_node
&& COMPLETE_TYPE_P (TREE_TYPE (decl)))
layout_decl (decl, 0);
/* If #pragma weak was used, mark the decl weak now. */
maybe_apply_pragma_weak (decl);
- /* If this is a variable definition, determine its ELF visibility. */
- if (TREE_CODE (decl) == VAR_DECL
- && TREE_STATIC (decl)
- && !DECL_EXTERNAL (decl))
- c_determine_visibility (decl);
-
/* Output the assembler code and/or RTL code for variables and functions,
unless the type is an undefined structure or union.
If not, it will get done when the type is completed. */
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
{
+ /* Determine the ELF visibility. */
+ if (TREE_PUBLIC (decl))
+ c_determine_visibility (decl);
+
/* This is a no-op in c-lang.c or something real in objc-act.c. */
if (c_dialect_objc ())
objc_check_decl (decl);
- if (asmspec)
+ if (asmspec)
{
/* If this is not a static variable, issue a warning.
It doesn't make any sense to give an ASMSPEC for an
&& !TREE_STATIC (decl))
warning (0, "ignoring asm-specifier for non-static local "
"variable %q+D", decl);
- else if (C_DECL_REGISTER (decl))
- change_decl_assembler_name (decl, get_identifier (asmspec));
else
set_user_assembler_name (decl, asmspec);
}
-
+
if (DECL_FILE_SCOPE_P (decl))
{
if (DECL_INITIAL (decl) == NULL_TREE
add_stmt (build_stmt (DECL_EXPR, decl));
}
}
-
+
if (!DECL_FILE_SCOPE_P (decl))
{
}
/* If this was marked 'used', be sure it will be output. */
- if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+ if (!flag_unit_at_a_time && lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
mark_decl_referenced (decl);
if (TREE_CODE (decl) == TYPE_DECL)
TREE_ASM_WRITTEN (b->decl) = 1;
}
\f
-static GTY(()) int compound_literal_number;
-
/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
literal, which may be an incomplete array type completed by the
initializer; INIT is a CONSTRUCTOR that initializes the compound
if (TREE_STATIC (decl))
{
- /* This decl needs a name for the assembler output. We also need
- a unique suffix to be added to the name. */
- char *name;
-
- ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal",
- compound_literal_number);
- compound_literal_number++;
- DECL_NAME (decl) = get_identifier (name);
+ /* This decl needs a name for the assembler output. */
+ set_compound_literal_name (decl);
DECL_DEFER_OUTPUT (decl) = 1;
DECL_COMDAT (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
type_mv = TYPE_MAIN_VARIANT (*type);
if (pedantic
+ && !in_system_header
&& type_mv != integer_type_node
&& type_mv != unsigned_type_node
&& type_mv != boolean_type_node)
{
struct lang_type *lt = TYPE_LANG_SPECIFIC (*type);
if (!lt
- || w < min_precision (lt->enum_min, TYPE_UNSIGNED (*type))
+ || w < min_precision (lt->enum_min, TYPE_UNSIGNED (*type))
|| w < min_precision (lt->enum_max, TYPE_UNSIGNED (*type)))
warning (0, "%qs is narrower than values of its type", name);
}
}
-/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */
-static tree
-c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
-{
- /* Extended integer types of the same width as a standard type have
- lesser rank, so those of the same width as int promote to int or
- unsigned int and are valid for printf formats expecting int or
- unsigned int. To avoid such special cases, avoid creating
- extended integer types for bit-fields if a standard integer type
- is available. */
- if (width == TYPE_PRECISION (integer_type_node))
- return unsignedp ? unsigned_type_node : integer_type_node;
- if (width == TYPE_PRECISION (signed_char_type_node))
- return unsignedp ? unsigned_char_type_node : signed_char_type_node;
- if (width == TYPE_PRECISION (short_integer_type_node))
- return unsignedp ? short_unsigned_type_node : short_integer_type_node;
- if (width == TYPE_PRECISION (long_integer_type_node))
- return unsignedp ? long_unsigned_type_node : long_integer_type_node;
- if (width == TYPE_PRECISION (long_long_integer_type_node))
- return (unsignedp ? long_long_unsigned_type_node
- : long_long_integer_type_node);
- return build_nonstandard_integer_type (width, unsignedp);
-}
\f
/* Given declspecs and a declarator,
determine the name and type of the object declared
int type_quals = TYPE_UNQUALIFIED;
const char *name, *orig_name;
tree typedef_type = 0;
- int funcdef_flag = 0;
+ bool funcdef_flag = false;
bool funcdef_syntax = false;
int size_varies = 0;
tree decl_attr = declspecs->decl_attr;
int array_ptr_quals = TYPE_UNQUALIFIED;
tree array_ptr_attrs = NULL_TREE;
int array_parm_static = 0;
+ bool array_parm_vla_unspec_p = false;
tree returned_attrs = NULL_TREE;
bool bitfield = width != NULL;
tree element_type;
struct c_arg_info *arg_info = 0;
if (decl_context == FUNCDEF)
- funcdef_flag = 1, decl_context = NORMAL;
+ funcdef_flag = true, decl_context = NORMAL;
/* Look inside a declarator for the name being declared
and get it as a string, for an error message. */
if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS)
warn_deprecated_use (declspecs->type);
+ if ((decl_context == NORMAL || decl_context == FIELD)
+ && current_scope == file_scope
+ && variably_modified_type_p (type, NULL_TREE))
+ {
+ error ("variably modified %qs at file scope", name);
+ type = integer_type_node;
+ }
+
typedef_type = type;
size_varies = C_TYPE_VARIABLE_SIZE (type);
&& !funcdef_flag)
{
/* 'extern' with initialization is invalid if not at file scope. */
- if (current_scope == file_scope)
- warning (0, "%qs initialized and declared %<extern%>", name);
+ if (current_scope == file_scope)
+ {
+ /* It is fine to have 'extern const' when compiling at C
+ and C++ intersection. */
+ if (!(warn_cxx_compat && constp))
+ warning (0, "%qs initialized and declared %<extern%>", name);
+ }
else
error ("%qs has both %<extern%> and initializer", name);
}
array_ptr_quals = declarator->u.array.quals;
array_ptr_attrs = declarator->u.array.attrs;
array_parm_static = declarator->u.array.static_p;
-
+ array_parm_vla_unspec_p = declarator->u.array.vla_unspec_p;
+
declarator = declarator->declarator;
/* Check for some types that there cannot be arrays of. */
-
+
if (VOID_TYPE_P (type))
{
error ("declaration of %qs as array of voids", name);
type = error_mark_node;
}
-
+
if (TREE_CODE (type) == FUNCTION_TYPE)
{
error ("declaration of %qs as array of functions", name);
type = error_mark_node;
}
-
+
if (pedantic && !in_system_header && flexible_array_type_p (type))
pedwarn ("invalid use of structure with flexible array member");
-
+
if (size == error_mark_node)
type = error_mark_node;
-
+
if (type == error_mark_node)
continue;
/* Strip NON_LVALUE_EXPRs since we aren't using as an
lvalue. */
STRIP_TYPE_NOPS (size);
-
+
if (!INTEGRAL_TYPE_P (TREE_TYPE (size)))
{
error ("size of array %qs has non-integer type", name);
size = integer_one_node;
}
-
+
if (pedantic && integer_zerop (size))
pedwarn ("ISO C forbids zero-size array %qs", name);
-
+
if (TREE_CODE (size) == INTEGER_CST)
{
constant_expression_warning (size);
size = integer_one_node;
}
}
+ else if ((decl_context == NORMAL || decl_context == FIELD)
+ && current_scope == file_scope)
+ {
+ error ("variably modified %qs at file scope", name);
+ size = integer_one_node;
+ }
else
{
/* Make sure the array size remains visibly
nonconstant even if it is (eg) a const variable
with known value. */
size_varies = 1;
-
+
if (!flag_isoc99 && pedantic)
{
if (TREE_CONSTANT (size))
if (integer_zerop (size))
{
- /* A zero-length array cannot be represented with
- an unsigned index type, which is what we'll
- get with build_index_type. Create an
- open-ended range instead. */
+ /* A zero-length array cannot be represented with
+ an unsigned index type, which is what we'll
+ get with build_index_type. Create an
+ open-ended range instead. */
itype = build_range_type (sizetype, size, NULL_TREE);
}
else
convert (index_type,
size_one_node));
- /* If that overflowed, the array is too big. ???
+ /* If that overflowed, the array is too big. ???
While a size of INT_MAX+1 technically shouldn't
cause an overflow (because we subtract 1), the
overflow is recorded during the conversion to
type = error_mark_node;
continue;
}
-
+
itype = build_index_type (itype);
}
}
identical to GCC's zero-length array extension. */
itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
}
+ else if (decl_context == PARM)
+ {
+ if (array_parm_vla_unspec_p)
+ {
+ if (! orig_name)
+ {
+ /* C99 6.7.5.2p4 */
+ error ("%<[*]%> not allowed in other than a declaration");
+ }
+
+ itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+ size_varies = 1;
+ }
+ }
+ else if (decl_context == TYPENAME)
+ {
+ if (array_parm_vla_unspec_p)
+ {
+ /* The error is printed elsewhere. We use this to
+ avoid messing up with incomplete array types of
+ the same type, that would otherwise be modified
+ below. */
+ itype = build_range_type (sizetype, size_zero_node,
+ NULL_TREE);
+ }
+ }
/* Complain about arrays of incomplete types. */
if (!COMPLETE_TYPE_P (type))
{
error ("array type has incomplete element type");
- type = error_mark_node;
+ type = error_mark_node;
}
else
+ /* When itype is NULL, a shared incomplete array type is
+ returned for all array of a given type. Elsewhere we
+ make sure we don't complete that type before copying
+ it, but here we want to make sure we don't ever
+ modify the shared type, so we gcc_assert (itype)
+ below. */
type = build_array_type (type, itype);
- if (size_varies)
- C_TYPE_VARIABLE_SIZE (type) = 1;
-
- /* The GCC extension for zero-length arrays differs from
- ISO flexible array members in that sizeof yields
- zero. */
- if (size && integer_zerop (size))
+ if (type != error_mark_node)
{
- TYPE_SIZE (type) = bitsize_zero_node;
- TYPE_SIZE_UNIT (type) = size_zero_node;
+ if (size_varies)
+ {
+ /* It is ok to modify type here even if itype is
+ NULL: if size_varies, we're in a
+ multi-dimensional array and the inner type has
+ variable size, so the enclosing shared array type
+ must too. */
+ if (size && TREE_CODE (size) == INTEGER_CST)
+ type
+ = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ C_TYPE_VARIABLE_SIZE (type) = 1;
+ }
+
+ /* The GCC extension for zero-length arrays differs from
+ ISO flexible array members in that sizeof yields
+ zero. */
+ if (size && integer_zerop (size))
+ {
+ gcc_assert (itype);
+ TYPE_SIZE (type) = bitsize_zero_node;
+ TYPE_SIZE_UNIT (type) = size_zero_node;
+ }
+ if (array_parm_vla_unspec_p)
+ {
+ gcc_assert (itype);
+ /* The type is complete. C99 6.7.5.2p4 */
+ TYPE_SIZE (type) = bitsize_zero_node;
+ TYPE_SIZE_UNIT (type) = size_zero_node;
+ }
}
if (decl_context != PARM
type for the function to return. */
if (type == error_mark_node)
continue;
-
+
size_varies = 0;
/* Warn about some types functions can't return. */
inner layer of declarator. */
arg_info = declarator->u.arg_info;
arg_types = grokparms (arg_info, really_funcdef);
+ if (really_funcdef)
+ put_pending_sizes (arg_info->pending_sizes);
/* Type qualifiers before the return type of the function
qualify the return type, not the function type. */
if (type_quals)
{
- /* Type qualifiers on a function return type are
+ /* Type qualifiers on a function return type are
normally permitted by the standard but have no
effect, so give a warning at -Wreturn-type.
Qualifiers on a void return type are banned on
else
warning (OPT_Wreturn_type,
"type qualifiers ignored on function return type");
-
+
type = c_build_qualified_type (type, type_quals);
}
type_quals = TYPE_UNQUALIFIED;
-
+
type = build_function_type (type, arg_types);
declarator = declarator->declarator;
-
+
/* Set the TYPE_CONTEXTs for each tagged type which is local to
the formal parameter list of this FUNCTION_TYPE to point to
the FUNCTION_TYPE node itself. */
{
tree link;
-
+
for (link = arg_info->tags;
link;
link = TREE_CHAIN (link))
type = c_build_qualified_type (type, type_quals);
size_varies = 0;
+ /* When the pointed-to type involves components of variable size,
+ care must be taken to ensure that the size evaluation code is
+ emitted early enough to dominate all the possible later uses
+ and late enough for the variables on which it depends to have
+ been assigned.
+
+ This is expected to happen automatically when the pointed-to
+ type has a name/declaration of it's own, but special attention
+ is required if the type is anonymous.
+
+ We handle the NORMAL and FIELD contexts here by attaching an
+ artificial TYPE_DECL to such pointed-to type. This forces the
+ sizes evaluation at a safe point and ensures it is not deferred
+ until e.g. within a deeper conditional context.
+
+ We expect nothing to be needed here for PARM or TYPENAME.
+ Pushing a TYPE_DECL at this point for TYPENAME would actually
+ be incorrect, as we might be in the middle of an expression
+ with side effects on the pointed-to type size "arguments" prior
+ to the pointer declaration point and the fake TYPE_DECL in the
+ enclosing context would force the size evaluation prior to the
+ side effects. */
+
+ if (!TYPE_NAME (type)
+ && (decl_context == NORMAL || decl_context == FIELD)
+ && variably_modified_type_p (type, NULL_TREE))
+ {
+ tree decl = build_decl (TYPE_DECL, NULL_TREE, type);
+ DECL_ARTIFICIAL (decl) = 1;
+ pushdecl (decl);
+ finish_decl (decl, NULL_TREE, NULL_TREE);
+ TYPE_NAME (type) = decl;
+ }
+
type = build_pointer_type (type);
-
+
/* Process type qualifiers (such as const or volatile)
that were given inside the `*'. */
type_quals = declarator->u.pointer_quals;
return decl;
}
- /* Detect the case of an array type of unspecified size
- which came, as such, direct from a typedef name.
- We must copy the type, so that each identifier gets
- a distinct type, so that each identifier's size can be
- controlled separately by its own initializer. */
-
- if (type != 0 && typedef_type != 0
- && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0
- && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type))
- {
- type = build_array_type (TREE_TYPE (type), 0);
- if (size_varies)
- C_TYPE_VARIABLE_SIZE (type) = 1;
- }
-
/* If this is a type name (such as, in a cast or sizeof),
compute the type and return it now. */
return type;
}
+ if (pedantic && decl_context == FIELD
+ && variably_modified_type_p (type, NULL_TREE))
+ {
+ /* C99 6.7.2.1p8 */
+ pedwarn ("a member of a structure or union cannot have a variably modified type");
+ }
+
/* Aside from typedefs and type names (handle above),
`void' at top level (not within pointer)
is allowed only in public variables.
type = build_pointer_type (type);
}
else if (TREE_CODE (type) != ERROR_MARK
- && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
+ && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
{
error ("field %qs has incomplete type", name);
type = error_mark_node;
}
else if (storage_class == csc_static)
{
- error ("invalid storage class for function %qs", name);
- if (funcdef_flag)
+ error ("invalid storage class for function %qs", name);
+ if (funcdef_flag)
storage_class = declspecs->storage_class = csc_none;
else
return 0;
GCC to signify a forward declaration of a nested function. */
if (storage_class == csc_auto && current_scope != file_scope)
DECL_EXTERNAL (decl) = 0;
+ /* In C99, a function which is declared 'inline' with 'extern'
+ is not an external reference (which is confusing). It
+ means that the later definition of the function must be output
+ in this file, C99 6.7.4p6. In GNU C89, a function declared
+ 'extern inline' is an external reference. */
+ else if (declspecs->inline_p && storage_class != csc_static)
+#if WANT_C99_INLINE_SEMANTICS
+ DECL_EXTERNAL (decl) = (storage_class == csc_extern) == !flag_isoc99;
+#else
+ DECL_EXTERNAL (decl) = (storage_class == csc_extern);
+#endif
else
- DECL_EXTERNAL (decl) = 1;
+ DECL_EXTERNAL (decl) = !initialized;
/* Record absence of global scope for `static' or `auto'. */
TREE_PUBLIC (decl)
the abstract origin pointing between the declarations,
which will confuse dwarf2out. */
if (initialized)
- {
- DECL_INLINE (decl) = 1;
- if (storage_class == csc_extern)
- current_extern_inline = 1;
- }
+ DECL_INLINE (decl) = 1;
}
/* If -finline-functions, assume it can be inlined. This does
two things: let the function be deferred until it is actually
/* At file scope, the presence of a `static' or `register' storage
class specifier, or the absence of all storage class specifiers
makes this declaration a definition (perhaps tentative). Also,
- the absence of both `static' and `register' makes it public. */
+ the absence of `static' makes it public. */
if (current_scope == file_scope)
{
- TREE_PUBLIC (decl) = !(storage_class == csc_static
- || storage_class == csc_register);
+ TREE_PUBLIC (decl) = storage_class != csc_static;
TREE_STATIC (decl) = !extern_ref;
}
/* Not at file scope, only `static' makes a static definition. */
}
}
+ if (storage_class == csc_extern
+ && variably_modified_type_p (type, NULL_TREE))
+ {
+ /* C99 6.7.5.2p2 */
+ error ("object with variably modified type must have no linkage");
+ }
+
/* Record `register' declaration for warnings on &
and in case doing stupid register allocation. */
}
\f
/* Decode the parameter-list info for a function type or function definition.
- The argument is the value returned by `get_parm_info' (or made in parse.y
+ The argument is the value returned by `get_parm_info' (or made in c-parse.c
if there is an identifier list instead of a parameter decl list).
These two functions are separate because when a function returns
or receives functions then each is called multiple times but the order
{
tree arg_types = arg_info->types;
+ if (funcdef_flag && arg_info->had_vla_unspec)
+ {
+ /* A function definition isn't function prototype scope C99 6.2.1p4. */
+ /* C99 6.7.5.2p4 */
+ error ("%<[*]%> not allowed in other than function prototype scope");
+ }
+
if (arg_types == 0 && !funcdef_flag && !in_system_header)
warning (OPT_Wstrict_prototypes,
"function declaration isn%'t a prototype");
arg_info->tags = 0;
arg_info->types = 0;
arg_info->others = 0;
+ arg_info->pending_sizes = 0;
+ arg_info->had_vla_unspec = current_scope->had_vla_unspec;
/* The bindings in this scope must not get put into a block.
We will take care of deleting the binding nodes. */
(by 'const' or 'volatile'), or has a storage class specifier
('register'), then the behavior is undefined; issue an error.
Typedefs for 'void' are OK (see DR#157). */
- if (b->prev == 0 /* one binding */
+ if (b->prev == 0 /* one binding */
&& TREE_CODE (b->decl) == PARM_DECL /* which is a parameter */
&& !DECL_NAME (b->decl) /* anonymous */
&& VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */
arg_info->tags = tags;
arg_info->types = types;
arg_info->others = others;
+ arg_info->pending_sizes = get_pending_sizes ();
return arg_info;
}
\f
if (ref && TREE_CODE (ref) == code)
{
if (TYPE_SIZE (ref))
- {
+ {
if (code == UNION_TYPE)
error ("redefinition of %<union %E%>", name);
- else
+ else
error ("redefinition of %<struct %E%>", name);
}
else if (C_TYPE_BEING_DEFINED (ref))
{
if (code == UNION_TYPE)
error ("nested redefinition of %<union %E%>", name);
- else
+ else
error ("nested redefinition of %<struct %E%>", name);
+ /* Don't create structures that contain themselves. */
+ ref = NULL_TREE;
}
}
- else
- {
- /* Otherwise create a forward-reference just so the tag is in scope. */
+ /* Otherwise create a forward-reference just so the tag is in scope. */
+
+ if (ref == NULL_TREE || TREE_CODE (ref) != code)
+ {
ref = make_node (code);
pushtag (name, ref);
}
saw_named_field = 0;
for (x = fieldlist; x; x = TREE_CHAIN (x))
{
+ if (TREE_TYPE (x) == error_mark_node)
+ continue;
+
DECL_CONTEXT (x) = t;
- DECL_PACKED (x) |= TYPE_PACKED (t);
+
+ if (TYPE_PACKED (t) && TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)
+ DECL_PACKED (x) = 1;
/* If any field is const, the structure type is pseudo-const. */
if (TREE_READONLY (x))
for (x = fieldlist; x; x = TREE_CHAIN (x))
{
- if (len > 15 || DECL_NAME (x) == NULL)
- break;
- len += 1;
+ if (len > 15 || DECL_NAME (x) == NULL)
+ break;
+ len += 1;
}
if (len > 15)
{
- tree *field_array;
- struct lang_type *space;
- struct sorted_fields_type *space2;
+ tree *field_array;
+ struct lang_type *space;
+ struct sorted_fields_type *space2;
- len += list_length (x);
+ len += list_length (x);
- /* Use the same allocation policy here that make_node uses, to
- ensure that this lives as long as the rest of the struct decl.
- All decls in an inline function need to be saved. */
+ /* Use the same allocation policy here that make_node uses, to
+ ensure that this lives as long as the rest of the struct decl.
+ All decls in an inline function need to be saved. */
- space = GGC_CNEW (struct lang_type);
- space2 = GGC_NEWVAR (struct sorted_fields_type,
+ space = GGC_CNEW (struct lang_type);
+ space2 = GGC_NEWVAR (struct sorted_fields_type,
sizeof (struct sorted_fields_type) + len * sizeof (tree));
- len = 0;
+ len = 0;
space->s = space2;
field_array = &space2->elts[0];
- for (x = fieldlist; x; x = TREE_CHAIN (x))
- {
- field_array[len++] = x;
-
- /* If there is anonymous struct or union, break out of the loop. */
- if (DECL_NAME (x) == NULL)
- break;
- }
- /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */
- if (x == NULL)
- {
- TYPE_LANG_SPECIFIC (t) = space;
- TYPE_LANG_SPECIFIC (t)->s->len = len;
- field_array = TYPE_LANG_SPECIFIC (t)->s->elts;
- qsort (field_array, len, sizeof (tree), field_decl_cmp);
- }
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ {
+ field_array[len++] = x;
+
+ /* If there is anonymous struct or union, break out of the loop. */
+ if (DECL_NAME (x) == NULL)
+ break;
+ }
+ /* Found no anonymous struct/union. Add the TYPE_LANG_SPECIFIC. */
+ if (x == NULL)
+ {
+ TYPE_LANG_SPECIFIC (t) = space;
+ TYPE_LANG_SPECIFIC (t)->s->len = len;
+ field_array = TYPE_LANG_SPECIFIC (t)->s->elts;
+ qsort (field_array, len, sizeof (tree), field_decl_cmp);
+ }
}
}
{
TYPE_FIELDS (x) = TYPE_FIELDS (t);
TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
- TYPE_ALIGN (x) = TYPE_ALIGN (t);
- TYPE_USER_ALIGN (x) = TYPE_USER_ALIGN (t);
C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
/* If we're inside a function proper, i.e. not file-scope and not still
parsing parameters, then arrange for the size of a variable sized type
to be bound now. */
- if (cur_stmt_list && variably_modified_type_p (t, NULL))
+ if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE))
add_stmt (build_stmt (DECL_EXPR, build_decl (TYPE_DECL, NULL, t)));
return t;
current_function_returns_null = 0;
current_function_returns_abnormally = 0;
warn_about_return_type = 0;
- current_extern_inline = 0;
c_switch_stack = NULL;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
decl1);
+#if WANT_C99_INLINE_SEMANTICS
+ /* Handle gnu_inline attribute. */
+ if (declspecs->inline_p
+ && flag_isoc99
+ && TREE_CODE (decl1) == FUNCTION_DECL
+ && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)))
+ {
+ if (declspecs->storage_class != csc_static)
+ DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1);
+ }
+#endif /* WANT_C99_INLINE_SEMANTICS */
+
announce_function (decl1);
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
/* If this definition isn't a prototype and we had a prototype declaration
before, copy the arg type info from that prototype. */
old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope);
+ if (old_decl && TREE_CODE (old_decl) != FUNCTION_DECL)
+ old_decl = 0;
current_function_prototype_locus = UNKNOWN_LOCATION;
current_function_prototype_built_in = false;
current_function_prototype_arg_types = NULL_TREE;
warning (OPT_Wmissing_declarations,
"%q+D was used with no declaration before its definition", decl1);
- /* This is a definition, not a reference.
- So normally clear DECL_EXTERNAL.
- However, `extern inline' acts like a declaration
- except for defining how to inline. So set DECL_EXTERNAL in that case. */
- DECL_EXTERNAL (decl1) = current_extern_inline;
-
/* This function exists in static storage.
(This does not mean `static' in the C sense!) */
TREE_STATIC (decl1) = 1;
/* Warn for unlikely, improbable, or stupid declarations of `main'. */
if (warn_main > 0 && MAIN_NAME_P (DECL_NAME (decl1)))
{
- tree args;
- int argct = 0;
-
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
!= integer_type_node)
pedwarn ("return type of %q+D is not %<int%>", decl1);
- for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args;
- args = TREE_CHAIN (args))
- {
- tree type = args ? TREE_VALUE (args) : 0;
-
- if (type == void_type_node)
- break;
-
- ++argct;
- switch (argct)
- {
- case 1:
- if (TYPE_MAIN_VARIANT (type) != integer_type_node)
- pedwarn ("first argument of %q+D should be %<int%>", decl1);
- break;
-
- case 2:
- if (TREE_CODE (type) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
- != char_type_node))
- pedwarn ("second argument of %q+D should be %<char **%>",
- decl1);
- break;
-
- case 3:
- if (TREE_CODE (type) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
- != char_type_node))
- pedwarn ("third argument of %q+D should probably be "
- "%<char **%>", decl1);
- break;
- }
- }
-
- /* It is intentional that this message does not mention the third
- argument because it's only mentioned in an appendix of the
- standard. */
- if (argct > 0 && (argct < 2 || argct > 3))
- pedwarn ("%q+D takes only zero or two arguments", decl1);
+ check_main_parameter_types(decl1);
if (!TREE_PUBLIC (decl1))
pedwarn ("%q+D is normally a non-static function", decl1);
cfun->x_dont_save_pending_sizes_p = 1;
}
\f
-/* Handle attribute((warn_unused_result)) on FNDECL and all its nested
- functions. */
+/* Emit diagnostics that require gimple input for detection. Operate on
+ FNDECL and all its nested functions. */
static void
-c_warn_unused_result_recursively (tree fndecl)
+c_gimple_diagnostics_recursively (tree fndecl)
{
struct cgraph_node *cgn;
/* Handle attribute((warn_unused_result)). Relies on gimple input. */
c_warn_unused_result (&DECL_SAVED_TREE (fndecl));
+ /* Notice when OpenMP structured block constraints are violated. */
+ if (flag_openmp)
+ diagnose_omp_structured_block_errors (fndecl);
+
/* Finalize all nested functions now. */
cgn = cgraph_node (fndecl);
for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
- c_warn_unused_result_recursively (cgn->decl);
+ c_gimple_diagnostics_recursively (cgn->decl);
}
/* Finish up a function declaration and compile that function
{
tree args = DECL_ARGUMENTS (fndecl);
for (; args; args = TREE_CHAIN (args))
- {
- tree type = TREE_TYPE (args);
- if (INTEGRAL_TYPE_P (type)
- && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
- DECL_ARG_TYPE (args) = integer_type_node;
- }
+ {
+ tree type = TREE_TYPE (args);
+ if (INTEGRAL_TYPE_P (type)
+ && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
+ DECL_ARG_TYPE (args) = integer_type_node;
+ }
}
if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node)
&& !undef_nested_function)
{
if (!decl_function_context (fndecl))
- {
- c_genericize (fndecl);
- c_warn_unused_result_recursively (fndecl);
+ {
+ c_genericize (fndecl);
+ c_gimple_diagnostics_recursively (fndecl);
/* ??? Objc emits functions after finalizing the compilation unit.
This should be cleaned up later and this conditional removed. */
}
cgraph_finalize_function (fndecl, false);
- }
+ }
else
- {
- /* Register this function with cgraph just far enough to get it
- added to our parent's nested function list. Handy, since the
- C front end doesn't have such a list. */
- (void) cgraph_node (fndecl);
- }
+ {
+ /* Register this function with cgraph just far enough to get it
+ added to our parent's nested function list. Handy, since the
+ C front end doesn't have such a list. */
+ (void) cgraph_node (fndecl);
+ }
}
if (!decl_function_context (fndecl))
if (DECL_STATIC_CONSTRUCTOR (fndecl)
&& targetm.have_ctors_dtors)
targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
- DEFAULT_INIT_PRIORITY);
+ DEFAULT_INIT_PRIORITY);
if (DECL_STATIC_DESTRUCTOR (fndecl)
&& targetm.have_ctors_dtors)
targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
- DEFAULT_INIT_PRIORITY);
+ DEFAULT_INIT_PRIORITY);
}
\f
/* Check the declarations given in a for-loop for satisfying the C99
- constraints. */
-void
+ constraints. If exactly one such decl is found, return it. */
+
+tree
check_for_loop_decls (void)
{
struct c_binding *b;
+ tree one_decl = NULL_TREE;
+ int n_decls = 0;
+
if (!flag_isoc99)
{
the C99 for loop scope. This doesn't make much sense, so don't
allow it. */
error ("%<for%> loop initial declaration used outside C99 mode");
- return;
+ return NULL_TREE;
}
/* C99 subclause 6.8.5 paragraph 3:
error ("declaration of non-variable %q+D in %<for%> loop "
"initial declaration", decl);
}
+
+ n_decls++;
+ one_decl = decl;
}
+
+ return n_decls == 1 ? one_decl : NULL_TREE;
}
\f
/* Save and reinitialize the variables
p->returns_null = current_function_returns_null;
p->returns_abnormally = current_function_returns_abnormally;
p->warn_about_return_type = warn_about_return_type;
- p->extern_inline = current_extern_inline;
}
/* Restore the variables used during compilation of a C function. */
current_function_returns_null = p->returns_null;
current_function_returns_abnormally = p->returns_abnormally;
warn_about_return_type = p->warn_about_return_type;
- current_extern_inline = p->extern_inline;
f->language = NULL;
}
else if (specs->typespec_word == cts_float)
error ("both %<long%> and %<float%> in "
"declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat32)
+ error ("both %<long%> and %<_Decimal32%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat64)
+ error ("both %<long%> and %<_Decimal64%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat128)
+ error ("both %<long%> and %<_Decimal128%> in "
+ "declaration specifiers");
else
specs->long_p = true;
break;
else if (specs->typespec_word == cts_double)
error ("both %<short%> and %<double%> in "
"declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat32)
+ error ("both %<short%> and %<_Decimal32%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat64)
+ error ("both %<short%> and %<_Decimal64%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat128)
+ error ("both %<short%> and %<_Decimal128%> in "
+ "declaration specifiers");
else
specs->short_p = true;
break;
else if (specs->typespec_word == cts_double)
error ("both %<signed%> and %<double%> in "
"declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat32)
+ error ("both %<signed%> and %<_Decimal32%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat64)
+ error ("both %<signed%> and %<_Decimal64%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat128)
+ error ("both %<signed%> and %<_Decimal128%> in "
+ "declaration specifiers");
else
specs->signed_p = true;
break;
else if (specs->typespec_word == cts_double)
error ("both %<unsigned%> and %<double%> in "
"declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat32)
+ error ("both %<unsigned%> and %<_Decimal32%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat64)
+ error ("both %<unsigned%> and %<_Decimal64%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat128)
+ error ("both %<unsigned%> and %<_Decimal128%> in "
+ "declaration specifiers");
else
specs->unsigned_p = true;
break;
else if (specs->typespec_word == cts_bool)
error ("both %<complex%> and %<_Bool%> in "
"declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat32)
+ error ("both %<complex%> and %<_Decimal32%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat64)
+ error ("both %<complex%> and %<_Decimal64%> in "
+ "declaration specifiers");
+ else if (specs->typespec_word == cts_dfloat128)
+ error ("both %<complex%> and %<_Decimal128%> in "
+ "declaration specifiers");
else
specs->complex_p = true;
break;
else
specs->typespec_word = cts_double;
return specs;
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ {
+ const char *str;
+ if (i == RID_DFLOAT32)
+ str = "_Decimal32";
+ else if (i == RID_DFLOAT64)
+ str = "_Decimal64";
+ else
+ str = "_Decimal128";
+ if (specs->long_long_p)
+ error ("both %<long long%> and %<%s%> in "
+ "declaration specifiers", str);
+ if (specs->long_p)
+ error ("both %<long%> and %<%s%> in "
+ "declaration specifiers", str);
+ else if (specs->short_p)
+ error ("both %<short%> and %<%s%> in "
+ "declaration specifiers", str);
+ else if (specs->signed_p)
+ error ("both %<signed%> and %<%s%> in "
+ "declaration specifiers", str);
+ else if (specs->unsigned_p)
+ error ("both %<unsigned%> and %<%s%> in "
+ "declaration specifiers", str);
+ else if (specs->complex_p)
+ error ("both %<complex%> and %<%s%> in "
+ "declaration specifiers", str);
+ else if (i == RID_DFLOAT32)
+ specs->typespec_word = cts_dfloat32;
+ else if (i == RID_DFLOAT64)
+ specs->typespec_word = cts_dfloat64;
+ else
+ specs->typespec_word = cts_dfloat128;
+ }
+ if (!targetm.decimal_float_supported_p ())
+ error ("decimal floating point not supported for this target");
+ if (pedantic)
+ pedwarn ("ISO C does not support decimal floating point");
+ return specs;
default:
/* ObjC reserved word "id", handled below. */
break;
: double_type_node);
}
break;
+ case cts_dfloat32:
+ case cts_dfloat64:
+ case cts_dfloat128:
+ gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p
+ && !specs->signed_p && !specs->unsigned_p && !specs->complex_p);
+ if (specs->typespec_word == cts_dfloat32)
+ specs->type = dfloat32_type_node;
+ else if (specs->typespec_word == cts_dfloat64)
+ specs->type = dfloat64_type_node;
+ else
+ specs->type = dfloat128_type_node;
+ break;
default:
gcc_unreachable ();
}
cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
}
-/* Perform final processing on one file scope's declarations (or the
- external scope's declarations), GLOBALS. */
+/* A subroutine of c_write_global_declarations. Perform final processing
+ on one file scope's declarations (or the external scope's declarations),
+ GLOBALS. */
+
static void
c_write_global_declarations_1 (tree globals)
{
- size_t len = list_length (globals);
- tree *vec = XNEWVEC (tree, len);
- size_t i;
tree decl;
+ bool reconsider;
/* Process the decls in the order they were written. */
- for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
+ for (decl = globals; decl; decl = TREE_CHAIN (decl))
{
- vec[i] = decl;
/* Check for used but undefined static functions using the C
standard's definition of "used", and set TREE_NO_WARNING so
that check_global_declarations doesn't repeat the check. */
pedwarn ("%q+F used but never defined", decl);
TREE_NO_WARNING (decl) = 1;
}
+
+ wrapup_global_declaration_1 (decl);
}
- wrapup_global_declarations (vec, len);
- check_global_declarations (vec, len);
+ do
+ {
+ reconsider = false;
+ for (decl = globals; decl; decl = TREE_CHAIN (decl))
+ reconsider |= wrapup_global_declaration_2 (decl);
+ }
+ while (reconsider);
+
+ for (decl = globals; decl; decl = TREE_CHAIN (decl))
+ check_global_declaration_1 (decl);
+}
+
+/* A subroutine of c_write_global_declarations Emit debug information for each
+ of the declarations in GLOBALS. */
+
+static void
+c_write_global_declarations_2 (tree globals)
+{
+ tree decl;
- free (vec);
+ for (decl = globals; decl ; decl = TREE_CHAIN (decl))
+ debug_hooks->global_decl (decl);
}
+/* Preserve the external declarations scope across a garbage collect. */
+static GTY(()) tree ext_block;
+
void
c_write_global_declarations (void)
{
- tree ext_block, t;
+ tree t;
/* We don't want to do this if generating a PCH. */
if (pch_file)
external_scope = 0;
gcc_assert (!current_scope);
- /* Process all file scopes in this compilation, and the external_scope,
- through wrapup_global_declarations and check_global_declarations. */
- for (t = all_translation_units; t; t = TREE_CHAIN (t))
- c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
if (ext_block)
{
tree tmp = BLOCK_VARS (ext_block);
int flags;
FILE * stream = dump_begin (TDI_tu, &flags);
if (stream && tmp)
- {
- dump_node (tmp, flags & ~TDF_SLIM, stream);
- dump_end (TDI_tu, stream);
- }
+ {
+ dump_node (tmp, flags & ~TDF_SLIM, stream);
+ dump_end (TDI_tu, stream);
+ }
}
+
+ /* Process all file scopes in this compilation, and the external_scope,
+ through wrapup_global_declarations and check_global_declarations. */
+ for (t = all_translation_units; t; t = TREE_CHAIN (t))
+ c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
c_write_global_declarations_1 (BLOCK_VARS (ext_block));
/* Generate functions to call static constructors and destructors
/* We're done parsing; proceed to optimize and emit assembly.
FIXME: shouldn't be the front end's responsibility to call this. */
cgraph_optimize ();
+
+ /* After cgraph has had a chance to emit everything that's going to
+ be emitted, output debug information for globals. */
+ if (errorcount == 0 && sorrycount == 0)
+ {
+ timevar_push (TV_SYMOUT);
+ for (t = all_translation_units; t; t = TREE_CHAIN (t))
+ c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t)));
+ c_write_global_declarations_2 (BLOCK_VARS (ext_block));
+ timevar_pop (TV_SYMOUT);
+ }
+
+ ext_block = NULL;
}
#include "gt-c-decl.h"