/* Process declarations and variables for C compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GCC.
#include "intl.h"
#include "tree.h"
#include "tree-inline.h"
-#include "rtl.h"
#include "flags.h"
#include "function.h"
#include "output.h"
-#include "expr.h"
#include "c-tree.h"
#include "toplev.h"
-#include "ggc.h"
#include "tm_p.h"
#include "cpplib.h"
#include "target.h"
#include "debug.h"
#include "opts.h"
#include "timevar.h"
-#include "c-common.h"
-#include "c-pragma.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "c-family/c-pragma.h"
#include "c-lang.h"
#include "langhooks.h"
-#include "tree-mudflap.h"
-#include "gimple.h"
#include "tree-iterator.h"
-#include "diagnostic.h"
+#include "diagnostic-core.h"
#include "tree-dump.h"
#include "cgraph.h"
#include "hashtab.h"
-#include "libfuncs.h"
-#include "except.h"
#include "langhooks-def.h"
#include "pointer-set.h"
-#include "gimple.h"
#include "plugin.h"
+#include "c-family/c-ada-spec.h"
/* In grokdeclarator, distinguish syntactic contexts of declarators. */
enum decl_context
tree c_break_label;
tree c_cont_label;
-/* Linked list of TRANSLATION_UNIT_DECLS for the translation units
- included in this invocation. Note that the current translation
- unit is not included in this list. */
-
-static GTY(()) tree all_translation_units;
-
/* A list of decls to be made automatically visible in each file scope. */
static GTY(()) tree visible_builtins;
static bool undef_nested_function;
-/* True means global_bindings_p should return false even if the scope stack
- says we are in file scope. */
-bool c_override_global_bindings_to_false;
-
\f
/* Each c_binding structure describes one binding of an identifier to
a decl. All the decls in a scope - irrespective of namespace - are
/* The resulting tree type. */
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
- chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *) TYPE_NEXT_VARIANT (&%h.generic) : ((union lang_tree_node *) TREE_CHAIN (&%h.generic))"))) lang_tree_node
+ chain_next ("(union lang_tree_node *) c_tree_chain_next (&%h.generic)"))) lang_tree_node
{
union tree_node GTY ((tag ("0"),
desc ("tree_node_structure (&%h)")))
up searching for labels when popping scopes, particularly since
labels are normally only found at function scope. */
BOOL_BITFIELD has_label_bindings : 1;
+
+ /* True if we should issue a warning if a goto statement crosses any
+ of the bindings. We still need to check the list of bindings to
+ find the specific ones we need to warn about. This is true if
+ decl_jump_unsafe would return true for any of the bindings. This
+ is used to avoid looping over all the bindings unnecessarily. */
+ BOOL_BITFIELD has_jump_unsafe_decl : 1;
};
/* The scope currently in effect. */
/* Add T to the statement-tree. Non-side-effect statements need to be
recorded during statement expressions. */
+ if (!building_stmt_list_p ())
+ push_stmt_list ();
append_to_statement_list_force (t, &cur_stmt_list);
return t;
}
\f
+/* Return true if we will want to say something if a goto statement
+ crosses DECL. */
+
+static bool
+decl_jump_unsafe (tree decl)
+{
+ if (error_operand_p (decl))
+ return false;
+
+ /* Always warn about crossing variably modified types. */
+ if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL)
+ && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+ return true;
+
+ /* Otherwise, only warn if -Wgoto-misses-init and this is an
+ initialized automatic decl. */
+ if (warn_jump_misses_init
+ && TREE_CODE (decl) == VAR_DECL
+ && !TREE_STATIC (decl)
+ && DECL_INITIAL (decl) != NULL_TREE)
+ return true;
+
+ return false;
+}
+\f
void
c_print_identifier (FILE *file, tree node, int indent)
binding_freelist = b->prev;
}
else
- b = GGC_NEW (struct c_binding);
+ b = ggc_alloc_c_binding ();
b->shadowed = 0;
b->decl = decl;
b->prev = scope->bindings;
scope->bindings = b;
+ if (decl_jump_unsafe (decl))
+ scope->has_jump_unsafe_decl = 1;
+
if (!name)
return;
complete_array_type (&TREE_TYPE (decl), NULL_TREE, true);
- layout_decl (decl, 0);
+ relayout_decl (decl);
}
}
}
record_inline_static (location_t loc, tree func, tree decl,
enum c_inline_static_type type)
{
- struct c_inline_static *csi = GGC_NEW (struct c_inline_static);
+ struct c_inline_static *csi = ggc_alloc_c_inline_static ();
csi->location = loc;
csi->function = func;
csi->static_decl = decl;
p->left_stmt_expr = false;
}
-/* Return true if we will want to say something if a goto statement
- crosses DECL. */
-
-static bool
-decl_jump_unsafe (tree decl)
-{
- if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
- return false;
-
- /* Always warn about crossing variably modified types. */
- if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL)
- && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
- return true;
-
- /* Otherwise, only warn if -Wgoto-misses-init and this is an
- initialized automatic decl. */
- if (warn_jump_misses_init
- && TREE_CODE (decl) == VAR_DECL
- && !TREE_STATIC (decl)
- && DECL_INITIAL (decl) != NULL_TREE)
- return true;
-
- return false;
-}
-
/* Update spot bindings P as we pop out of SCOPE. Return true if we
should push decls for a label. */
}
}
-/* Nonzero if we are currently in file scope. */
+/* Return true if we are in the global binding level. */
-int
+bool
global_bindings_p (void)
{
- return (current_scope == file_scope && !c_override_global_bindings_to_false
- ? -1
- : 0);
+ return current_scope == file_scope;
}
void
scope_freelist = scope->outer;
}
else
- scope = GGC_CNEW (struct c_scope);
+ scope = ggc_alloc_cleared_c_scope ();
/* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */
if (current_scope)
{
struct c_label_vars *label_vars;
struct c_binding *b1;
+ bool hjud;
unsigned int ix;
struct c_goto_bindings *g;
label_vars = b->u.label;
b1 = label_vars->label_bindings.bindings_in_scope;
+ if (label_vars->label_bindings.scope == NULL)
+ hjud = false;
+ else
+ hjud = label_vars->label_bindings.scope->has_jump_unsafe_decl;
if (update_spot_bindings (scope, &label_vars->label_bindings))
{
/* This label is defined in this scope. */
- for (; b1 != NULL; b1 = b1->prev)
+ if (hjud)
{
- /* A goto from later in the function to this
- label will never see the initialization of
- B1, if any. Save it to issue a warning if
- needed. */
- if (decl_jump_unsafe (b1->decl))
- VEC_safe_push (tree, gc, label_vars->decls_in_scope,
- b1->decl);
+ for (; b1 != NULL; b1 = b1->prev)
+ {
+ /* A goto from later in the function to this
+ label will never see the initialization
+ of B1, if any. Save it to issue a
+ warning if needed. */
+ if (decl_jump_unsafe (b1->decl))
+ VEC_safe_push (tree, gc,
+ label_vars->decls_in_scope,
+ b1->decl);
+ }
}
}
/* Update the bindings of any goto statements associated
with this label. */
- for (ix = 0;
- VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
- ++ix)
+ FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g)
update_spot_bindings (scope, &g->goto_bindings);
}
}
context = current_function_decl;
else if (scope == file_scope)
{
- tree file_decl = build_decl (UNKNOWN_LOCATION,
- TRANSLATION_UNIT_DECL, 0, 0);
- TREE_CHAIN (file_decl) = all_translation_units;
- all_translation_units = file_decl;
+ tree file_decl = build_translation_unit_decl (NULL_TREE);
context = file_decl;
}
else
warn_for_unused_label (p);
/* Labels go in BLOCK_VARS. */
- TREE_CHAIN (p) = BLOCK_VARS (block);
+ DECL_CHAIN (p) = BLOCK_VARS (block);
BLOCK_VARS (block) = p;
gcc_assert (I_LABEL_BINDING (b->id) == b);
I_LABEL_BINDING (b->id) = b->shadowed;
case VAR_DECL:
/* Warnings for unused variables. */
- if (!TREE_USED (p)
+ if ((!TREE_USED (p) || !DECL_READ_P (p))
&& !TREE_NO_WARNING (p)
&& !DECL_IN_SYSTEM_HEADER (p)
&& DECL_NAME (p)
&& !DECL_ARTIFICIAL (p)
&& scope != file_scope
&& scope != external_scope)
- warning (OPT_Wunused_variable, "unused variable %q+D", p);
+ {
+ if (!TREE_USED (p))
+ warning (OPT_Wunused_variable, "unused variable %q+D", p);
+ else if (DECL_CONTEXT (p) == current_function_decl)
+ warning_at (DECL_SOURCE_LOCATION (p),
+ OPT_Wunused_but_set_variable,
+ "variable %qD set but not used", p);
+ }
if (b->inner_comp)
{
binding in the home scope. */
if (!b->nested)
{
- TREE_CHAIN (p) = BLOCK_VARS (block);
+ DECL_CHAIN (p) = BLOCK_VARS (block);
BLOCK_VARS (block) = p;
}
- else if (VAR_OR_FUNCTION_DECL_P (p))
+ else if (VAR_OR_FUNCTION_DECL_P (p) && scope != file_scope)
{
/* For block local externs add a special
DECL_EXTERNAL decl for debug info generation. */
}
if (b->locus != UNKNOWN_LOCATION)
DECL_SOURCE_LOCATION (extp) = b->locus;
- TREE_CHAIN (extp) = BLOCK_VARS (block);
+ DECL_CHAIN (extp) = BLOCK_VARS (block);
BLOCK_VARS (block) = extp;
}
- /* If this is the file scope, and we are processing more
- than one translation unit in this compilation, set
- DECL_CONTEXT of each decl to the TRANSLATION_UNIT_DECL.
- This makes same_translation_unit_p work, and causes
- static declarations to be given disambiguating suffixes. */
- if (scope == file_scope && num_in_fnames > 1)
+ /* If this is the file scope set DECL_CONTEXT of each decl to
+ the TRANSLATION_UNIT_DECL. This makes same_translation_unit_p
+ work. */
+ if (scope == file_scope)
{
DECL_CONTEXT (p) = context;
- if (TREE_CODE (p) == TYPE_DECL)
+ if (TREE_CODE (p) == TYPE_DECL
+ && TREE_TYPE (p) != error_mark_node)
set_type_context (TREE_TYPE (p), context);
}
start_fname_decls ();
- for (decl = visible_builtins; decl; decl = TREE_CHAIN (decl))
+ for (decl = visible_builtins; decl; decl = DECL_CHAIN (decl))
bind (DECL_NAME (decl), decl, file_scope,
/*invisible=*/false, /*nested=*/true, DECL_SOURCE_LOCATION (decl));
}
continue;
label_vars = b->u.label;
++label_vars->label_bindings.stmt_exprs;
- for (ix = 0;
- VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
- ++ix)
+ FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g)
++g->goto_bindings.stmt_exprs;
}
}
label_vars->label_bindings.left_stmt_expr = true;
label_vars->label_bindings.stmt_exprs = 0;
}
- for (ix = 0;
- VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
- ++ix)
+ FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g)
{
--g->goto_bindings.stmt_exprs;
if (g->goto_bindings.stmt_exprs < 0)
if (TREE_CODE (olddecl) != FUNCTION_DECL
|| !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype))
- || !((TYPE_ARG_TYPES (oldtype) == 0 && DECL_INITIAL (olddecl) == 0)
- ||
- (TYPE_ARG_TYPES (newtype) == 0 && DECL_INITIAL (newdecl) == 0)))
+ || !((!prototype_p (oldtype) && DECL_INITIAL (olddecl) == 0)
+ || (!prototype_p (newtype) && DECL_INITIAL (newdecl) == 0)))
return;
t = TYPE_ARG_TYPES (oldtype);
/* Redeclaration of a type is a constraint violation (6.7.2.3p1),
but silently ignore the redeclaration if either is in a system
- header. (Conflicting redeclarations were handled above.) */
+ header. (Conflicting redeclarations were handled above.) This
+ is allowed for C11 if the types are the same, not just
+ compatible. */
if (TREE_CODE (newdecl) == TYPE_DECL)
{
+ bool types_different = false;
+ int comptypes_result;
+
+ comptypes_result
+ = comptypes_check_different_types (oldtype, newtype, &types_different);
+
+ if (comptypes_result != 1 || types_different)
+ {
+ error ("redefinition of typedef %q+D with different type", newdecl);
+ locate_old_decl (olddecl);
+ return false;
+ }
+
if (DECL_IN_SYSTEM_HEADER (newdecl)
|| DECL_IN_SYSTEM_HEADER (olddecl)
|| TREE_NO_WARNING (newdecl)
|| TREE_NO_WARNING (olddecl))
return true; /* Allow OLDDECL to continue in use. */
- error ("redefinition of typedef %q+D", newdecl);
- locate_old_decl (olddecl);
- return false;
+ if (variably_modified_type_p (newtype, NULL))
+ {
+ error ("redefinition of typedef %q+D with variably modified type",
+ newdecl);
+ locate_old_decl (olddecl);
+ }
+ else if (pedantic && !flag_isoc11)
+ {
+ pedwarn (input_location, OPT_pedantic,
+ "redefinition of typedef %q+D", newdecl);
+ locate_old_decl (olddecl);
+ }
+
+ return true;
}
/* Function declarations can either be 'static' or 'extern' (no
&& !C_DECL_DECLARED_BUILTIN (olddecl)
&& (!TREE_PUBLIC (newdecl)
|| (DECL_INITIAL (newdecl)
- && !TYPE_ARG_TYPES (TREE_TYPE (newdecl)))))
+ && !prototype_p (TREE_TYPE (newdecl)))))
{
warning (OPT_Wshadow, "declaration of %q+D shadows "
"a built-in function", newdecl);
/* If we have a prototype after an old-style function definition,
the argument types must be checked specially. */
else if (DECL_INITIAL (olddecl)
- && !TYPE_ARG_TYPES (oldtype) && TYPE_ARG_TYPES (newtype)
+ && !prototype_p (oldtype) && prototype_p (newtype)
&& TYPE_ACTUAL_ARG_TYPES (oldtype)
&& !validate_proto_after_old_defn (newdecl, newtype, oldtype))
{
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);
+ && prototype_p (TREE_TYPE (newdecl)));
bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
- && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
+ && prototype_p (TREE_TYPE (olddecl)));
bool extern_changed = false;
/* For real parm decl following a forward decl, rechain the old decl
DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
C_DECL_DECLARED_BUILTIN (newdecl) = 1;
if (new_is_prototype)
- C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
+ {
+ C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
+ if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
+ {
+ enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
+ switch (fncode)
+ {
+ /* If a compatible prototype of these builtin functions
+ is seen, assume the runtime implements it with the
+ expected semantics. */
+ case BUILT_IN_STPCPY:
+ if (builtin_decl_explicit_p (fncode))
+ set_builtin_decl_implicit_p (fncode, true);
+ break;
+ default:
+ break;
+ }
+ }
+ }
else
C_DECL_BUILTIN_PROTOTYPE (newdecl)
= C_DECL_BUILTIN_PROTOTYPE (olddecl);
DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl);
DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
- gimple_set_body (newdecl, gimple_body (olddecl));
DECL_ARGUMENTS (newdecl) = copy_list (DECL_ARGUMENTS (olddecl));
- for (t = DECL_ARGUMENTS (newdecl); t ; t = TREE_CHAIN (t))
+ for (t = DECL_ARGUMENTS (newdecl); t ; t = DECL_CHAIN (t))
DECL_CONTEXT (t) = newdecl;
/* See if we've got a function to instantiate from. */
TREE_USED (newdecl) = 1;
else if (TREE_USED (newdecl))
TREE_USED (olddecl) = 1;
+ if (TREE_CODE (olddecl) == VAR_DECL || TREE_CODE (olddecl) == PARM_DECL)
+ DECL_READ_P (newdecl) |= DECL_READ_P (olddecl);
if (DECL_PRESERVE_P (olddecl))
DECL_PRESERVE_P (newdecl) = 1;
else if (DECL_PRESERVE_P (newdecl))
memcpy ((char *) olddecl + sizeof (struct tree_common),
(char *) newdecl + sizeof (struct tree_common),
sizeof (struct tree_decl_common) - sizeof (struct tree_common));
+ DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl);
switch (TREE_CODE (olddecl))
{
case FUNCTION_DECL:
- gimple_set_body (olddecl, gimple_body (newdecl));
- /* fall through */
-
case FIELD_DECL:
case VAR_DECL:
case PARM_DECL:
/* Is anything being shadowed? Invisible decls do not count. */
for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed)
- if (b->decl && b->decl != new_decl && !b->invisible)
+ if (b->decl && b->decl != new_decl && !b->invisible
+ && (b->decl == error_mark_node
+ || diagnostic_report_warnings_p (global_dc,
+ DECL_SOURCE_LOCATION (b->decl))))
{
tree old_decl = b->decl;
skip_external_and_shadow_checks:
if (TREE_CODE (x) == TYPE_DECL)
- set_underlying_type (x);
+ {
+ /* So this is a typedef, set its underlying type. */
+ set_underlying_type (x);
+
+ /* If X is a typedef defined in the current function, record it
+ for the purpose of implementing the -Wunused-local-typedefs
+ warning. */
+ record_locally_defined_typedef (x);
+ }
bind (name, x, scope, /*invisible=*/false, nested, locus);
}
else
{
- error_at (loc, "%qE undeclared (first use in this function)", id);
+ if (!objc_diagnose_private_ivar (id))
+ error_at (loc, "%qE undeclared (first use in this function)", id);
if (!already)
{
inform (loc, "each undeclared identifier is reported only"
DECL_CONTEXT (label) = current_function_decl;
DECL_MODE (label) = VOIDmode;
- label_vars = GGC_NEW (struct c_label_vars);
+ label_vars = ggc_alloc_c_label_vars ();
label_vars->shadowed = NULL;
set_spot_bindings (&label_vars->label_bindings, defining);
label_vars->decls_in_scope = make_tree_vector ();
tree label;
struct c_label_vars *label_vars;
- if (current_function_decl == 0)
+ if (current_function_scope == 0)
{
error ("label %qE referenced outside of any function", name);
return 0;
{
struct c_goto_bindings *g;
- g = GGC_NEW (struct c_goto_bindings);
+ g = ggc_alloc_c_goto_bindings ();
g->loc = loc;
set_spot_bindings (&g->goto_bindings, true);
VEC_safe_push (c_goto_bindings_p, gc, label_vars->gotos, g);
...
goto lab;
Issue a warning or error. */
- for (ix = 0; VEC_iterate (tree, label_vars->decls_in_scope, ix, decl); ++ix)
+ FOR_EACH_VEC_ELT (tree, label_vars->decls_in_scope, ix, decl)
warn_about_goto (loc, label, decl);
if (label_vars->label_bindings.left_stmt_expr)
unsigned int ix;
struct c_goto_bindings *g;
- for (ix = 0;
- VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
- ++ix)
+ FOR_EACH_VEC_ELT (c_goto_bindings_p, label_vars->gotos, ix, g)
{
struct c_binding *b;
struct c_scope *scope;
/* We have a goto to this label. The goto is going forward. In
g->scope, the goto is going to skip any binding which was
defined after g->bindings_in_scope. */
- for (b = g->goto_bindings.scope->bindings;
- b != g->goto_bindings.bindings_in_scope;
- b = b->prev)
+ if (g->goto_bindings.scope->has_jump_unsafe_decl)
{
- if (decl_jump_unsafe (b->decl))
- warn_about_goto (g->loc, label, b->decl);
+ for (b = g->goto_bindings.scope->bindings;
+ b != g->goto_bindings.bindings_in_scope;
+ b = b->prev)
+ {
+ if (decl_jump_unsafe (b->decl))
+ warn_about_goto (g->loc, label, b->decl);
+ }
}
/* We also need to warn about decls defined in any scopes
scope = scope->outer)
{
gcc_assert (scope != NULL);
- if (scope == label_vars->label_bindings.scope)
- b = label_vars->label_bindings.bindings_in_scope;
- else
- b = scope->bindings;
- for (; b != NULL; b = b->prev)
+ if (scope->has_jump_unsafe_decl)
{
- if (decl_jump_unsafe (b->decl))
- warn_about_goto (g->loc, label, b->decl);
+ if (scope == label_vars->label_bindings.scope)
+ b = label_vars->label_bindings.bindings_in_scope;
+ else
+ b = scope->bindings;
+ for (; b != NULL; b = b->prev)
+ {
+ if (decl_jump_unsafe (b->decl))
+ warn_about_goto (g->loc, label, b->decl);
+ }
}
}
struct c_binding *b;
gcc_assert (scope != NULL);
+
+ if (!scope->has_jump_unsafe_decl)
+ continue;
+
for (b = scope->bindings; b != NULL; b = b->prev)
{
if (decl_jump_unsafe (b->decl))
{
struct c_binding *b = I_SYMBOL_BINDING (name);
if (b && !b->invisible)
- return b->decl;
+ {
+ maybe_record_typedef_use (b->decl);
+ return b->decl;
+ }
return 0;
}
using preprocessed headers. */
input_location = BUILTINS_LOCATION;
- build_common_tree_nodes (flag_signed_char, false);
-
c_common_nodes_and_builtins ();
/* In C, comparisons and TRUTH_* expressions have type int. */
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))
+ && (!seen_error () || current_function_scope))
{
DECL_CONTEXT (decl) = current_function_decl;
bind (id, decl, current_function_scope,
tree id = DECL_NAME (decl);
const char *name = IDENTIFIER_POINTER (id);
- C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
+ C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type);
/* Should never be called on a symbol with a preexisting meaning. */
gcc_assert (!I_SYMBOL_BINDING (id));
needing to be explicitly declared. See push_file_scope. */
if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
{
- TREE_CHAIN (decl) = visible_builtins;
+ DECL_CHAIN (decl) = visible_builtins;
visible_builtins = decl;
}
tree id = DECL_NAME (decl);
const char *name = IDENTIFIER_POINTER (id);
- C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
+ C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type);
/* Should never be called on a symbol with a preexisting meaning. */
gcc_assert (!I_SYMBOL_BINDING (id));
needing to be explicitly declared. See push_file_scope. */
if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
{
- TREE_CHAIN (decl) = visible_builtins;
+ DECL_CHAIN (decl) = visible_builtins;
visible_builtins = decl;
}
warned = 1;
}
}
- else if (!declspecs->tag_defined_p
+ else if (declspecs->typespec_kind != ctsk_tagdef
+ && declspecs->typespec_kind != ctsk_tagfirstref
&& declspecs->storage_class != csc_none)
{
if (warned != 1)
warned = 1;
pending_xref_error ();
}
- else if (!declspecs->tag_defined_p
+ else if (declspecs->typespec_kind != ctsk_tagdef
+ && declspecs->typespec_kind != ctsk_tagfirstref
&& (declspecs->const_p
|| declspecs->volatile_p
|| declspecs->restrict_p
warned = 1;
pending_xref_error ();
}
+ else if (declspecs->typespec_kind != ctsk_tagdef
+ && declspecs->typespec_kind != ctsk_tagfirstref
+ && declspecs->alignas_p)
+ {
+ if (warned != 1)
+ pedwarn (input_location, 0,
+ "empty declaration with %<_Alignas%> "
+ "does not redeclare tag");
+ warned = 1;
+ pending_xref_error ();
+ }
else
{
pending_invalid_xref = 0;
warned = 1;
}
+ if (declspecs->noreturn_p)
+ {
+ error ("%<_Noreturn%> in empty declaration");
+ warned = 1;
+ }
+
if (current_scope == file_scope && declspecs->storage_class == csc_auto)
{
error ("%<auto%> in file-scope empty declaration");
warned = 2;
}
+ if (!warned && !in_system_header && declspecs->alignas_p)
+ {
+ warning (0, "useless %<_Alignas%> in empty declaration");
+ warned = 2;
+ }
+
if (warned != 1)
{
if (!found_tag)
&& !specs->unsigned_p
&& !specs->complex_p
&& !specs->inline_p
+ && !specs->noreturn_p
&& !specs->thread_p);
return quals;
}
return 0;
if (expr)
- add_stmt (expr);
+ add_stmt (fold_convert (void_type_node, expr));
if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
warning (OPT_Wmain, "%q+D is usually a function", decl);
prototypes file (if requested). */
if (TREE_CODE (decl) == FUNCTION_DECL)
- gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0);
+ gen_aux_info_record (decl, 0, 0, prototype_p (TREE_TYPE (decl)));
/* ANSI specifies that a tentative definition which is not merged with
a non-tentative definition behaves exactly like a definition with an
if (ce->kind == cdk_function)
{
tree args = ce->u.arg_info->parms;
- for (; args; args = TREE_CHAIN (args))
+ for (; args; args = DECL_CHAIN (args))
{
tree type = TREE_TYPE (args);
if (type && INTEGRAL_TYPE_P (type)
record_inline_static (input_location, current_function_decl,
decl, csi_modifiable);
+ if (c_dialect_objc ()
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL))
+ objc_check_global_decl (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);
return tem;
}
+/* Subroutine of finish_decl. TYPE is the type of an uninitialized object
+ DECL or the non-array element type if DECL is an uninitialized array.
+ If that type has a const member, diagnose this. */
+
+static void
+diagnose_uninitialized_cst_member (tree decl, tree type)
+{
+ tree field;
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ tree field_type;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ field_type = strip_array_types (TREE_TYPE (field));
+
+ if (TYPE_QUALS (field_type) & TYPE_QUAL_CONST)
+ {
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
+ "uninitialized const member in %qT is invalid in C++",
+ strip_array_types (TREE_TYPE (decl)));
+ inform (DECL_SOURCE_LOCATION (field), "%qD should be initialized", field);
+ }
+
+ if (TREE_CODE (field_type) == RECORD_TYPE
+ || TREE_CODE (field_type) == UNION_TYPE)
+ diagnose_uninitialized_cst_member (decl, field_type);
+ }
+}
+
/* Finish processing of a declaration;
install its initial value.
If ORIGTYPE is not NULL_TREE, it is the original type of INIT.
b_ext = b_ext->shadowed;
if (b_ext)
{
- if (b_ext->u.type)
+ if (b_ext->u.type && comptypes (b_ext->u.type, type))
b_ext->u.type = composite_type (b_ext->u.type, type);
else
b_ext->u.type = type;
if (DECL_INITIAL (decl))
TREE_TYPE (DECL_INITIAL (decl)) = type;
- layout_decl (decl, 0);
+ relayout_decl (decl);
}
if (TREE_CODE (decl) == VAR_DECL)
}
if (TREE_USED (type))
- TREE_USED (decl) = 1;
+ {
+ TREE_USED (decl) = 1;
+ DECL_READ_P (decl) = 1;
+ }
}
/* If this is a function and an assembler name is specified, reset DECL_RTL
- so we can give it its new name. Also, update built_in_decls if it
+ so we can give it its new name. Also, update builtin_decl if it
was a normal built-in. */
if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
{
when a tentative file-scope definition is seen.
But at end of compilation, do output code for them. */
DECL_DEFER_OUTPUT (decl) = 1;
+ if (asmspec && C_DECL_REGISTER (decl))
+ DECL_HARD_REGISTER (decl) = 1;
rest_of_decl_compilation (decl, true, 0);
}
else
rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
}
- /* At the end of a declaration, throw away any variable type sizes
- of types defined inside that declaration. There is no use
- computing them in the following function definition. */
- if (current_scope == file_scope)
- get_pending_sizes ();
-
/* Install a cleanup (aka destructor) if one was given. */
if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
{
/* Don't warn about decl unused; the cleanup uses it. */
TREE_USED (decl) = 1;
TREE_USED (cleanup_decl) = 1;
+ DECL_READ_P (decl) = 1;
push_cleanup (decl, cleanup, false);
}
if (warn_cxx_compat
&& TREE_CODE (decl) == VAR_DECL
- && TREE_READONLY (decl)
&& !DECL_EXTERNAL (decl)
&& DECL_INITIAL (decl) == NULL_TREE)
- warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
- "uninitialized const %qD is invalid in C++", decl);
+ {
+ type = strip_array_types (type);
+ if (TREE_READONLY (decl))
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
+ "uninitialized const %qD is invalid in C++", decl);
+ else if ((TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ && C_TYPE_FIELDS_READONLY (type))
+ diagnose_uninitialized_cst_member (decl, type);
+ }
+
+ invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
}
-/* Given a parsed parameter declaration, decode it into a PARM_DECL. */
+/* Given a parsed parameter declaration, decode it into a PARM_DECL.
+ EXPR is NULL or a pointer to an expression that needs to be
+ evaluated for the side effects of array size expressions in the
+ parameters. */
tree
-grokparm (const struct c_parm *parm)
+grokparm (const struct c_parm *parm, tree *expr)
{
tree attrs = parm->attrs;
tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
- NULL, &attrs, NULL, NULL, DEPRECATED_NORMAL);
+ NULL, &attrs, expr, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
}
/* Given a parsed parameter declaration, decode it into a PARM_DECL
- and push that on the current scope. */
+ and push that on the current scope. EXPR is a pointer to an
+ expression that needs to be evaluated for the side effects of array
+ size expressions in the parameters. */
void
-push_parm_decl (const struct c_parm *parm)
+push_parm_decl (const struct c_parm *parm, tree *expr)
{
tree attrs = parm->attrs;
tree decl;
decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
- &attrs, NULL, NULL, DEPRECATED_NORMAL);
+ &attrs, expr, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
decl = pushdecl (decl);
tree complit;
tree stmt;
- if (type == error_mark_node)
+ if (type == error_mark_node
+ || init == error_mark_node)
return error_mark_node;
decl = build_decl (loc, VAR_DECL, NULL_TREE, type);
TREE_STATIC (decl) = (current_scope == file_scope);
DECL_CONTEXT (decl) = current_function_decl;
TREE_USED (decl) = 1;
+ DECL_READ_P (decl) = 1;
TREE_TYPE (decl) = type;
TREE_READONLY (decl) = TYPE_READONLY (type);
store_init_value (loc, decl, init, NULL_TREE);
void
check_compound_literal_type (location_t loc, struct c_type_name *type_name)
{
- if (warn_cxx_compat && type_name->specs->tag_defined_p)
+ if (warn_cxx_compat
+ && (type_name->specs->typespec_kind == ctsk_tagdef
+ || type_name->specs->typespec_kind == ctsk_tagfirstref))
warning_at (loc, OPT_Wc___compat,
"defining a type in a compound literal is invalid in C++");
}
x = TYPE_FIELDS (type);
if (x == NULL_TREE)
return false;
- while (TREE_CHAIN (x) != NULL_TREE)
- x = TREE_CHAIN (x);
+ while (DECL_CHAIN (x) != NULL_TREE)
+ x = DECL_CHAIN (x);
if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
&& TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
&& TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
return true;
return false;
case UNION_TYPE:
- for (x = TYPE_FIELDS (type); x != NULL_TREE; x = TREE_CHAIN (x))
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
{
if (flexible_array_type_p (TREE_TYPE (x)))
return true;
{
error ("width of %qs exceeds its type", name);
w = max_width;
- *width = build_int_cst (NULL_TREE, w);
+ *width = build_int_cst (integer_type_node, w);
}
else
w = tree_low_cst (*width, 1);
}
}
-/* Given a size SIZE that may not be a constant, return a SAVE_EXPR to
- serve as the actual size-expression for a type or decl. This is
- like variable_size in stor-layout.c, but we make global_bindings_p
- return negative to avoid calls to that function from outside the
- front end resulting in errors at file scope, then call this version
- instead from front-end code. */
-
-static tree
-c_variable_size (tree size)
-{
- tree save;
-
- if (TREE_CONSTANT (size))
- return size;
-
- size = save_expr (size);
-
- save = skip_simple_arithmetic (size);
-
- if (cfun && cfun->dont_save_pending_sizes_p)
- return size;
-
- if (!global_bindings_p ())
- put_pending_size (save);
-
- return size;
-}
-
/* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
const char *errmsg;
tree expr_dummy;
bool expr_const_operands_dummy;
+ enum c_declarator_kind first_non_attr_kind;
+ unsigned int alignas_align = 0;
+ if (TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
if (expr == NULL)
expr = &expr_dummy;
if (expr_const_operands == NULL)
{
const struct c_declarator *decl = declarator;
+ first_non_attr_kind = cdk_attrs;
while (decl)
switch (decl->kind)
{
case cdk_pointer:
funcdef_syntax = (decl->kind == cdk_function);
decl = decl->declarator;
+ if (first_non_attr_kind == cdk_attrs)
+ first_non_attr_kind = decl->kind;
break;
case cdk_attrs:
loc = decl->id_loc;
if (decl->u.id)
name = decl->u.id;
+ if (first_non_attr_kind == cdk_attrs)
+ first_non_attr_kind = decl->kind;
decl = 0;
break;
error_at (loc, "conflicting named address spaces (%s vs %s)",
c_addr_space_name (as1), c_addr_space_name (as2));
- if (!flag_gen_aux_info && (TYPE_QUALS (element_type)))
+ if ((TREE_CODE (type) == ARRAY_TYPE
+ || first_non_attr_kind == cdk_array)
+ && TYPE_QUALS (element_type))
type = TYPE_MAIN_VARIANT (type);
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
MINUS_EXPR, which allows the -1 to get folded
with the +1 that happens when building TYPE_SIZE. */
if (size_varies)
- size = c_variable_size (size);
+ size = save_expr (size);
if (this_size_varies && TREE_CODE (size) == INTEGER_CST)
size = build2 (COMPOUND_EXPR, TREE_TYPE (size),
integer_zero_node, size);
convert (index_type,
size_one_node));
- /* 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
- index_type, before the subtraction. Handling
- this case seems like an unnecessary
- complication. */
- if (TREE_CODE (itype) == INTEGER_CST
- && TREE_OVERFLOW (itype))
+ /* The above overflows when size does not fit
+ in index_type.
+ ??? While a size of INT_MAX+1 technically shouldn't
+ cause an overflow (because we subtract 1), handling
+ this case seems like an unnecessary complication. */
+ if (TREE_CODE (size) == INTEGER_CST
+ && !int_fits_type_p (size, index_type))
{
if (name)
error_at (loc, "size of array %qE is too large",
}
}
- /* Complain about arrays of incomplete types. */
+ /* Complain about arrays of incomplete types. */
if (!COMPLETE_TYPE_P (type))
{
error_at (loc, "array type has incomplete element type");
if (size && integer_zerop (size))
{
gcc_assert (itype);
+ type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
TYPE_SIZE (type) = bitsize_zero_node;
TYPE_SIZE_UNIT (type) = size_zero_node;
SET_TYPE_STRUCTURAL_EQUALITY (type);
{
gcc_assert (itype);
/* The type is complete. C99 6.7.5.2p4 */
+ type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
TYPE_SIZE (type) = bitsize_zero_node;
TYPE_SIZE_UNIT (type) = size_zero_node;
SET_TYPE_STRUCTURAL_EQUALITY (type);
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. */
the formal parameter list of this FUNCTION_TYPE to point to
the FUNCTION_TYPE node itself. */
{
- tree link;
+ c_arg_tag *tag;
+ unsigned ix;
- for (link = arg_info->tags;
- link;
- link = TREE_CHAIN (link))
- TYPE_CONTEXT (TREE_VALUE (link)) = type;
+ FOR_EACH_VEC_ELT_REVERSE (c_arg_tag, arg_info->tags, ix, tag)
+ TYPE_CONTEXT (tag->type) = type;
}
break;
}
if (bitfield)
check_bitfield_type_and_width (&type, width, name);
+ /* Reject invalid uses of _Alignas. */
+ if (declspecs->alignas_p)
+ {
+ if (storage_class == csc_typedef)
+ error_at (loc, "alignment specified for typedef %qE", name);
+ else if (storage_class == csc_register)
+ error_at (loc, "alignment specified for %<register%> object %qE",
+ name);
+ else if (decl_context == PARM)
+ {
+ if (name)
+ error_at (loc, "alignment specified for parameter %qE", name);
+ else
+ error_at (loc, "alignment specified for unnamed parameter");
+ }
+ else if (bitfield)
+ {
+ if (name)
+ error_at (loc, "alignment specified for bit-field %qE", name);
+ else
+ error_at (loc, "alignment specified for unnamed bit-field");
+ }
+ else if (TREE_CODE (type) == FUNCTION_TYPE)
+ error_at (loc, "alignment specified for function %qE", name);
+ else if (declspecs->align_log != -1)
+ {
+ alignas_align = 1U << declspecs->align_log;
+ if (alignas_align < TYPE_ALIGN_UNIT (type))
+ {
+ if (name)
+ error_at (loc, "%<_Alignas%> specifiers cannot reduce "
+ "alignment of %qE", name);
+ else
+ error_at (loc, "%<_Alignas%> specifiers cannot reduce "
+ "alignment of unnamed field");
+ alignas_align = 0;
+ }
+ }
+ }
+
/* Did array size calculations overflow? */
if (TREE_CODE (type) == ARRAY_TYPE
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
if (declspecs->inline_p)
pedwarn (loc, 0,"typedef %q+D declared %<inline%>", decl);
+ if (declspecs->noreturn_p)
+ pedwarn (loc, 0,"typedef %q+D declared %<_Noreturn%>", decl);
if (warn_cxx_compat && declarator->u.id != NULL_TREE)
{
/* Note that the grammar rejects storage classes in typenames
and fields. */
gcc_assert (storage_class == csc_none && !threadp
- && !declspecs->inline_p);
+ && !declspecs->inline_p && !declspecs->noreturn_p);
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
pedwarn (loc, OPT_pedantic,
DECL_ARG_TYPE (decl) = promoted_type;
if (declspecs->inline_p)
pedwarn (loc, 0, "parameter %q+D declared %<inline%>", decl);
+ if (declspecs->noreturn_p)
+ pedwarn (loc, 0, "parameter %q+D declared %<_Noreturn%>", decl);
}
else if (decl_context == FIELD)
{
/* Note that the grammar rejects storage classes in typenames
and fields. */
gcc_assert (storage_class == csc_none && !threadp
- && !declspecs->inline_p);
+ && !declspecs->inline_p && !declspecs->noreturn_p);
/* Structure field. It may not be a function. */
if (storage_class == csc_register || threadp)
{
error_at (loc, "invalid storage class for function %qE", name);
- }
+ }
else if (current_scope != file_scope)
{
/* Function declaration not at file scope. Storage
pedwarn (loc, OPT_pedantic,
"ISO C forbids qualified function types");
- /* GNU C interprets a volatile-qualified function type to indicate
- that the function does not return. */
- if ((type_quals & TYPE_QUAL_VOLATILE)
- && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
- warning_at (loc, 0, "%<noreturn%> function returns non-void value");
-
/* Every function declaration is an external reference
(DECL_EXTERNAL) except for those which are not at file
scope and are explicitly declared "auto". This is
if (declspecs->default_int_p)
C_FUNCTION_IMPLICIT_INT (decl) = 1;
- /* Record presence of `inline', if it is reasonable. */
+ /* Record presence of `inline' and `_Noreturn', if it is
+ reasonable. */
if (flag_hosted && MAIN_NAME_P (declarator->u.id))
{
if (declspecs->inline_p)
pedwarn (loc, 0, "cannot inline function %<main%>");
+ if (declspecs->noreturn_p)
+ pedwarn (loc, 0, "%<main%> declared %<_Noreturn%>");
+ }
+ else
+ {
+ if (declspecs->inline_p)
+ /* Record that the function is declared `inline'. */
+ DECL_DECLARED_INLINE_P (decl) = 1;
+ if (declspecs->noreturn_p)
+ {
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_pedantic,
+ "ISO C99 does not support %<_Noreturn%>");
+ else
+ pedwarn (loc, OPT_pedantic,
+ "ISO C90 does not support %<_Noreturn%>");
+ }
+ TREE_THIS_VOLATILE (decl) = 1;
+ }
}
- else if (declspecs->inline_p)
- /* Record that the function is declared `inline'. */
- DECL_DECLARED_INLINE_P (decl) = 1;
}
else
{
if (declspecs->inline_p)
pedwarn (loc, 0, "variable %q+D declared %<inline%>", decl);
+ if (declspecs->noreturn_p)
+ pedwarn (loc, 0, "variable %q+D declared %<_Noreturn%>", decl);
/* At file scope, an initialized extern declaration may follow
a static declaration. In that case, DECL_EXTERNAL will be
/* Record constancy and volatility. */
c_apply_type_quals_to_decl (type_quals, decl);
+ /* Apply _Alignas specifiers. */
+ if (alignas_align)
+ {
+ DECL_ALIGN (decl) = alignas_align * BITS_PER_UNIT;
+ DECL_USER_ALIGN (decl) = 1;
+ }
+
/* If a type has volatile components, it should be stored in memory.
Otherwise, the fact that those components are volatile
will be ignored, and would even crash the compiler.
else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE)
{
if (!funcdef_flag)
- pedwarn (input_location, 0, "parameter names (without types) in function declaration");
+ {
+ pedwarn (input_location, 0, "parameter names (without types) in function declaration");
+ arg_info->parms = NULL_TREE;
+ }
+ else
+ arg_info->parms = arg_info->types;
- arg_info->parms = arg_info->types;
arg_info->types = 0;
return 0;
}
for (parm = arg_info->parms, typelt = arg_types, parmno = 1;
parm;
- parm = TREE_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++)
+ parm = DECL_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++)
{
type = TREE_VALUE (typelt);
if (type == error_mark_node)
TREE_VALUE (typelt) = error_mark_node;
TREE_TYPE (parm) = error_mark_node;
+ arg_types = NULL_TREE;
}
else if (VOID_TYPE_P (type))
{
error (errmsg);
TREE_VALUE (typelt) = error_mark_node;
TREE_TYPE (parm) = error_mark_node;
+ arg_types = NULL_TREE;
}
if (DECL_NAME (parm) && TREE_USED (parm))
}
}
+/* Allocate and initialize a c_arg_info structure from the parser's
+ obstack. */
+
+struct c_arg_info *
+build_arg_info (void)
+{
+ struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+ ret->parms = NULL_TREE;
+ ret->tags = NULL;
+ ret->types = NULL_TREE;
+ ret->others = NULL_TREE;
+ ret->pending_sizes = NULL;
+ ret->had_vla_unspec = 0;
+ return ret;
+}
+
/* Take apart the current scope and return a c_arg_info structure with
info on a parameter list just parsed.
This structure is later fed to 'grokparms' and 'store_parm_decls'.
ELLIPSIS being true means the argument list ended in '...' so don't
- append a sentinel (void_list_node) to the end of the type-list. */
+ append a sentinel (void_list_node) to the end of the type-list.
+
+ EXPR is NULL or an expression that needs to be evaluated for the
+ side effects of array size expressions in the parameters. */
struct c_arg_info *
-get_parm_info (bool ellipsis)
+get_parm_info (bool ellipsis, tree expr)
{
struct c_binding *b = current_scope->bindings;
- struct c_arg_info *arg_info = XOBNEW (&parser_obstack,
- struct c_arg_info);
+ struct c_arg_info *arg_info = build_arg_info ();
+
tree parms = 0;
- tree tags = 0;
+ VEC(c_arg_tag,gc) *tags = NULL;
tree types = 0;
tree others = 0;
static bool explained_incomplete_types = false;
bool gave_void_only_once_err = false;
- arg_info->parms = 0;
- 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.
{
tree decl = b->decl;
tree type = TREE_TYPE (decl);
+ c_arg_tag *tag;
const char *keyword;
switch (TREE_CODE (decl))
else
{
/* Valid parameter, add it to the list. */
- TREE_CHAIN (decl) = parms;
+ DECL_CHAIN (decl) = parms;
parms = decl;
/* Since there is a prototype, args are passed in their
}
}
- tags = tree_cons (b->id, decl, tags);
+ tag = VEC_safe_push (c_arg_tag, gc, tags, NULL);
+ tag->id = b->id;
+ tag->type = decl;
break;
case CONST_DECL:
type itself. FUNCTION_DECLs appear when there is an implicit
function declaration in the parameter list. */
- TREE_CHAIN (decl) = others;
+ /* When we reinsert this decl in the function body, we need
+ to reconstruct whether it was marked as nested. */
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+ ? b->nested
+ : !b->nested);
+ DECL_CHAIN (decl) = others;
others = decl;
/* fall through */
arg_info->tags = tags;
arg_info->types = types;
arg_info->others = others;
- arg_info->pending_sizes = get_pending_sizes ();
+ arg_info->pending_sizes = expr;
return arg_info;
}
\f
is the anonymous union extension. Similarly for struct.
If this is something of the form "struct foo;", then
- If MS extensions are enabled, this is handled as an
- anonymous struct.
+ If MS or Plan 9 extensions are enabled, this is handled as
+ an anonymous struct.
Otherwise this is a forward declaration of a structure tag.
If this is something of the form "foo;" and foo is a TYPE_DECL, then
- If MS extensions are enabled and foo names a structure, then
- again this is an anonymous struct.
+ If foo names a structure or union without a tag, then this
+ is an anonymous struct (this is permitted by C11).
+ If MS or Plan 9 extensions are enabled and foo names a
+ structure, then again this is an anonymous struct.
Otherwise this is an error.
Oh what a horrid tangled web we weave. I wonder if MS consciously
bool ok = false;
if (type_ok
- && (flag_ms_extensions || !declspecs->typedef_p))
+ && (flag_ms_extensions
+ || flag_plan9_extensions
+ || !declspecs->typedef_p))
{
- if (flag_ms_extensions)
+ if (flag_ms_extensions || flag_plan9_extensions)
ok = true;
- else if (flag_iso)
- ok = false;
else if (TYPE_NAME (type) == NULL)
ok = true;
else
pedwarn (loc, 0, "declaration does not declare anything");
return NULL_TREE;
}
- pedwarn (loc, OPT_pedantic, "ISO C doesn%'t support unnamed structs/unions");
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_pedantic,
+ "ISO C99 doesn%'t support unnamed structs/unions");
+ else
+ pedwarn (loc, OPT_pedantic,
+ "ISO C90 doesn%'t support unnamed structs/unions");
+ }
}
value = grokdeclarator (declarator, declspecs, FIELD, false,
return value;
}
\f
+/* Subroutine of detect_field_duplicates: return whether X and Y,
+ which are both fields in the same struct, have duplicate field
+ names. */
+
+static bool
+is_duplicate_field (tree x, tree y)
+{
+ if (DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y))
+ return true;
+
+ /* When using -fplan9-extensions, an anonymous field whose name is a
+ typedef can duplicate a field name. */
+ if (flag_plan9_extensions
+ && (DECL_NAME (x) == NULL_TREE || DECL_NAME (y) == NULL_TREE))
+ {
+ tree xt, xn, yt, yn;
+
+ xt = TREE_TYPE (x);
+ if (DECL_NAME (x) != NULL_TREE)
+ xn = DECL_NAME (x);
+ else if ((TREE_CODE (xt) == RECORD_TYPE || TREE_CODE (xt) == UNION_TYPE)
+ && TYPE_NAME (xt) != NULL_TREE
+ && TREE_CODE (TYPE_NAME (xt)) == TYPE_DECL)
+ xn = DECL_NAME (TYPE_NAME (xt));
+ else
+ xn = NULL_TREE;
+
+ yt = TREE_TYPE (y);
+ if (DECL_NAME (y) != NULL_TREE)
+ yn = DECL_NAME (y);
+ else if ((TREE_CODE (yt) == RECORD_TYPE || TREE_CODE (yt) == UNION_TYPE)
+ && TYPE_NAME (yt) != NULL_TREE
+ && TREE_CODE (TYPE_NAME (yt)) == TYPE_DECL)
+ yn = DECL_NAME (TYPE_NAME (yt));
+ else
+ yn = NULL_TREE;
+
+ if (xn != NULL_TREE && xn == yn)
+ return true;
+ }
+
+ return false;
+}
+
+/* Subroutine of detect_field_duplicates: add the fields of FIELDLIST
+ to HTAB, giving errors for any duplicates. */
+
+static void
+detect_field_duplicates_hash (tree fieldlist, htab_t htab)
+{
+ tree x, y;
+ void **slot;
+
+ for (x = fieldlist; x ; x = DECL_CHAIN (x))
+ if ((y = DECL_NAME (x)) != 0)
+ {
+ slot = htab_find_slot (htab, y, INSERT);
+ if (*slot)
+ {
+ error ("duplicate member %q+D", x);
+ DECL_NAME (x) = NULL_TREE;
+ }
+ *slot = y;
+ }
+ else if (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)
+ {
+ detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab);
+
+ /* When using -fplan9-extensions, an anonymous field whose
+ name is a typedef can duplicate a field name. */
+ if (flag_plan9_extensions
+ && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE
+ && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)
+ {
+ tree xn = DECL_NAME (TYPE_NAME (TREE_TYPE (x)));
+ slot = htab_find_slot (htab, xn, INSERT);
+ if (*slot)
+ error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x)));
+ *slot = xn;
+ }
+ }
+}
+
/* Generate an error for any duplicate field names in FIELDLIST. Munge
the list such that this does not present a problem later. */
tree x, y;
int timeout = 10;
+ /* If the struct is the list of instance variables of an Objective-C
+ class, then we need to check all the instance variables of
+ superclasses when checking for duplicates (since you can't have
+ an instance variable in a subclass with the same name as an
+ instance variable in a superclass). We pass on this job to the
+ Objective-C compiler. objc_detect_field_duplicates() will return
+ false if we are not checking the list of instance variables and
+ the C frontend should proceed with the standard field duplicate
+ checks. If we are checking the list of instance variables, the
+ ObjC frontend will do the check, emit the errors if needed, and
+ then return true. */
+ if (c_dialect_objc ())
+ if (objc_detect_field_duplicates (false))
+ return;
+
/* First, see if there are more than "a few" fields.
This is trivially true if there are zero or one fields. */
- if (!fieldlist)
- return;
- x = TREE_CHAIN (fieldlist);
- if (!x)
+ if (!fieldlist || !DECL_CHAIN (fieldlist))
return;
+ x = fieldlist;
do {
timeout--;
- x = TREE_CHAIN (x);
+ if (DECL_NAME (x) == NULL_TREE
+ && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE))
+ timeout = 0;
+ x = DECL_CHAIN (x);
} while (timeout > 0 && x);
- /* If there were "few" fields, avoid the overhead of allocating
- a hash table. Instead just do the nested traversal thing. */
+ /* If there were "few" fields and no anonymous structures or unions,
+ avoid the overhead of allocating a hash table. Instead just do
+ the nested traversal thing. */
if (timeout > 0)
{
- for (x = TREE_CHAIN (fieldlist); x ; x = TREE_CHAIN (x))
- if (DECL_NAME (x))
+ for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x))
+ /* When using -fplan9-extensions, we can have duplicates
+ between typedef names and fields. */
+ if (DECL_NAME (x)
+ || (flag_plan9_extensions
+ && DECL_NAME (x) == NULL_TREE
+ && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)
+ && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE
+ && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL))
{
for (y = fieldlist; y != x; y = TREE_CHAIN (y))
- if (DECL_NAME (y) == DECL_NAME (x))
+ if (is_duplicate_field (y, x))
{
error ("duplicate member %q+D", x);
DECL_NAME (x) = NULL_TREE;
else
{
htab_t htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
- void **slot;
-
- for (x = fieldlist; x ; x = TREE_CHAIN (x))
- if ((y = DECL_NAME (x)) != 0)
- {
- slot = htab_find_slot (htab, y, INSERT);
- if (*slot)
- {
- error ("duplicate member %q+D", x);
- DECL_NAME (x) = NULL_TREE;
- }
- *slot = y;
- }
+ detect_field_duplicates_hash (fieldlist, htab);
htab_delete (htab);
}
}
because the flag is used to issue visibility warnings, and we
only want to issue those warnings if the type is referenced
outside of the struct declaration. */
- for (ix = 0; VEC_iterate (tree, struct_parse_info->struct_types, ix, x); ++ix)
+ FOR_EACH_VEC_ELT (tree, struct_parse_info->struct_types, ix, x)
C_TYPE_DEFINED_IN_STRUCT (x) = 1;
/* The TYPEDEFS_SEEN field of STRUCT_PARSE_INFO is a list of
a pointer_set because identifiers are interned. */
struct pointer_set_t *tset = pointer_set_create ();
- for (ix = 0;
- VEC_iterate (tree, struct_parse_info->typedefs_seen, ix, x);
- ++ix)
+ FOR_EACH_VEC_ELT (tree, struct_parse_info->typedefs_seen, ix, x)
pointer_set_insert (tset, DECL_NAME (x));
- for (x = fieldlist; x != NULL_TREE; x = TREE_CHAIN (x))
+ for (x = fieldlist; x != NULL_TREE; x = DECL_CHAIN (x))
{
- if (pointer_set_contains (tset, DECL_NAME (x)))
+ if (DECL_NAME (x) != NULL_TREE
+ && pointer_set_contains (tset, DECL_NAME (x)))
{
warning_at (DECL_SOURCE_LOCATION (x), OPT_Wc___compat,
("using %qD as both field and typedef name is "
/* For each field which has a binding and which was not defined in
an enclosing struct, clear the in_struct field. */
- for (ix = 0;
- VEC_iterate (c_binding_ptr, struct_parse_info->fields, ix, b);
- ++ix)
+ FOR_EACH_VEC_ELT (c_binding_ptr, struct_parse_info->fields, ix, b)
b->in_struct = 0;
}
if (pedantic)
{
- for (x = fieldlist; x; x = TREE_CHAIN (x))
- if (DECL_NAME (x) != 0)
- break;
+ for (x = fieldlist; x; x = DECL_CHAIN (x))
+ {
+ if (DECL_NAME (x) != 0)
+ break;
+ if (flag_isoc11
+ && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE))
+ break;
+ }
if (x == 0)
{
until now.) */
saw_named_field = 0;
- for (x = fieldlist; x; x = TREE_CHAIN (x))
+ for (x = fieldlist; x; x = DECL_CHAIN (x))
{
if (TREE_TYPE (x) == error_mark_node)
continue;
else
{
/* A field that is pseudo-const makes the structure likewise. */
- tree t1 = TREE_TYPE (x);
- while (TREE_CODE (t1) == ARRAY_TYPE)
- t1 = TREE_TYPE (t1);
+ tree t1 = strip_array_types (TREE_TYPE (x));
if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (t1))
C_TYPE_FIELDS_READONLY (t) = 1;
"flexible array member in union");
TREE_TYPE (x) = error_mark_node;
}
- else if (TREE_CHAIN (x) != NULL_TREE)
+ else if (DECL_CHAIN (x) != NULL_TREE)
{
error_at (DECL_SOURCE_LOCATION (x),
"flexible array member not at end of struct");
pedwarn (DECL_SOURCE_LOCATION (x), OPT_pedantic,
"invalid use of structure with flexible array member");
- if (DECL_NAME (x))
+ if (DECL_NAME (x)
+ || TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)
saw_named_field = 1;
}
DECL_INITIAL (*fieldlistp) = 0;
}
else
- fieldlistp = &TREE_CHAIN (*fieldlistp);
+ fieldlistp = &DECL_CHAIN (*fieldlistp);
}
/* Now we have the truly final field list.
{
int len = 0;
- for (x = fieldlist; x; x = TREE_CHAIN (x))
+ for (x = fieldlist; x; x = DECL_CHAIN (x))
{
if (len > 15 || DECL_NAME (x) == NULL)
break;
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,
- sizeof (struct sorted_fields_type) + len * sizeof (tree));
+ space = ggc_alloc_cleared_lang_type (sizeof (struct lang_type));
+ space2 = ggc_alloc_sorted_fields_type
+ (sizeof (struct sorted_fields_type) + len * sizeof (tree));
len = 0;
space->s = space2;
field_array = &space2->elts[0];
- for (x = fieldlist; x; x = TREE_CHAIN (x))
+ for (x = fieldlist; x; x = DECL_CHAIN (x))
{
field_array[len++] = x;
/* 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_TREE))
+ if (building_stmt_list_p () && variably_modified_type_p (t, NULL_TREE))
add_stmt (build_stmt (loc,
DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t)));
/* Record the min/max values so that we can warn about bit-field
enumerations that are too small for the values. */
- lt = GGC_CNEW (struct lang_type);
+ lt = ggc_alloc_cleared_lang_type (sizeof (struct lang_type));
lt->enum_min = minnode;
lt->enum_max = maxnode;
TYPE_LANG_SPECIFIC (enumtype) = lt;
/* Build and install a CONST_DECL for one value of the
current enumeration type (one that was begun with start_enum).
- LOC is the location of the enumerator.
+ DECL_LOC is the location of the enumerator.
+ LOC is the location of the '=' operator if any, DECL_LOC otherwise.
Return a tree-list containing the CONST_DECL and its value.
Assignment of sequential values by default is handled here. */
tree
-build_enumerator (location_t loc,
+build_enumerator (location_t decl_loc, location_t loc,
struct c_enum_contents *the_enum, tree name, tree value)
{
tree decl, type;
/* Set basis for default for next value. */
the_enum->enum_next_value
- = build_binary_op
- (EXPR_HAS_LOCATION (value) ? EXPR_LOCATION (value) : input_location,
- PLUS_EXPR, value, integer_one_node, 0);
+ = build_binary_op (EXPR_LOC_OR_HERE (value),
+ PLUS_EXPR, value, integer_one_node, 0);
the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value);
/* Now create a declaration for the enum value name. */
>= TYPE_PRECISION (integer_type_node)
&& TYPE_UNSIGNED (type)));
- decl = build_decl (loc, CONST_DECL, name, type);
+ decl = build_decl (decl_loc, CONST_DECL, name, type);
DECL_INITIAL (decl) = convert (type, value);
pushdecl (decl);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
- if (decl1 == 0)
+ if (decl1 == 0
+ || TREE_CODE (decl1) != FUNCTION_DECL)
return 0;
loc = DECL_SOURCE_LOCATION (decl1);
error_mark_node is replaced below (in pop_scope) with the BLOCK. */
DECL_INITIAL (decl1) = error_mark_node;
+ /* A nested function is not global. */
+ if (current_function_decl != 0)
+ TREE_PUBLIC (decl1) = 0;
+
/* 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);
current_function_prototype_locus = UNKNOWN_LOCATION;
current_function_prototype_built_in = false;
current_function_prototype_arg_types = NULL_TREE;
- if (TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
+ if (!prototype_p (TREE_TYPE (decl1)))
{
if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (decl1)),
/* Optionally warn of old-fashioned def with no previous prototype. */
if (warn_strict_prototypes
&& old_decl != error_mark_node
- && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0
+ && !prototype_p (TREE_TYPE (decl1))
&& C_DECL_ISNT_PROTOTYPE (old_decl))
warning_at (loc, OPT_Wstrict_prototypes,
"function declaration isn%'t a prototype");
&& old_decl != 0
&& old_decl != error_mark_node
&& TREE_USED (old_decl)
- && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0)
+ && !prototype_p (TREE_TYPE (old_decl)))
warning_at (loc, OPT_Wmissing_prototypes,
"%qD was used with no prototype before its definition", decl1);
/* Optionally warn of any global def with no previous declaration. */
(This does not mean `static' in the C sense!) */
TREE_STATIC (decl1) = 1;
- /* A nested function is not global. */
- if (current_function_decl != 0)
- TREE_PUBLIC (decl1) = 0;
-
/* This is the earliest point at which we might know the assembler
name of the function. Thus, if it's set before this, die horribly. */
gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1));
store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info)
{
tree decl;
+ c_arg_tag *tag;
+ unsigned ix;
if (current_scope->bindings)
{
/* Now make all the parameter declarations visible in the function body.
We can bypass most of the grunt work of pushdecl. */
- for (decl = arg_info->parms; decl; decl = TREE_CHAIN (decl))
+ for (decl = arg_info->parms; decl; decl = DECL_CHAIN (decl))
{
DECL_CONTEXT (decl) = current_function_decl;
if (DECL_NAME (decl))
DECL_ARGUMENTS (fndecl) = arg_info->parms;
/* Now make all the ancillary declarations visible, likewise. */
- for (decl = arg_info->others; decl; decl = TREE_CHAIN (decl))
+ for (decl = arg_info->others; decl; decl = DECL_CHAIN (decl))
{
DECL_CONTEXT (decl) = current_function_decl;
if (DECL_NAME (decl))
bind (DECL_NAME (decl), decl, current_scope,
- /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
+ /*invisible=*/false,
+ /*nested=*/(TREE_CODE (decl) == FUNCTION_DECL),
+ UNKNOWN_LOCATION);
}
/* And all the tag declarations. */
- for (decl = arg_info->tags; decl; decl = TREE_CHAIN (decl))
- if (TREE_PURPOSE (decl))
- bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope,
+ FOR_EACH_VEC_ELT_REVERSE (c_arg_tag, arg_info->tags, ix, tag)
+ if (tag->id)
+ bind (tag->id, tag->type, current_scope,
/*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
}
if (b && B_IN_CURRENT_SCOPE (b))
{
decl = b->decl;
+ /* Skip erroneous parameters. */
+ if (decl == error_mark_node)
+ continue;
/* If we got something other than a PARM_DECL it is an error. */
if (TREE_CODE (decl) != PARM_DECL)
error_at (DECL_SOURCE_LOCATION (decl),
for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm))
if (TREE_PURPOSE (parm))
{
- TREE_CHAIN (last) = TREE_PURPOSE (parm);
+ DECL_CHAIN (last) = TREE_PURPOSE (parm);
last = TREE_PURPOSE (parm);
}
- TREE_CHAIN (last) = 0;
+ DECL_CHAIN (last) = 0;
}
pointer_set_destroy (seen_args);
type = current_function_prototype_arg_types;
parm || (type && TREE_VALUE (type) != error_mark_node
&& (TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node));
- parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
+ parm = DECL_CHAIN (parm), type = TREE_CHAIN (type))
{
if (parm == 0 || type == 0
|| TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
{
tree actual = 0, last = 0, type;
- for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm))
+ for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
{
type = tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), NULL_TREE);
if (last)
/* Initialize the RTL code for the function. */
allocate_struct_function (fndecl, false);
+ if (warn_unused_local_typedefs)
+ cfun->language = ggc_alloc_cleared_language_function ();
+
/* Begin the statement tree for this function. */
DECL_SAVED_TREE (fndecl) = push_stmt_list ();
because we throw away the array type in favor of a pointer type, and
thus won't naturally see the SAVE_EXPR containing the increment. All
other pending sizes would be handled by gimplify_parameters. */
- {
- tree t;
- for (t = nreverse (get_pending_sizes ()); t ; t = TREE_CHAIN (t))
- add_stmt (TREE_VALUE (t));
- }
-
- /* Even though we're inside a function body, we still don't want to
- call expand_expr to calculate the size of a variable-sized array.
- We haven't necessarily assigned RTL to all variables yet, so it's
- not safe to try to expand expressions involving them. */
- cfun->dont_save_pending_sizes_p = 1;
+ if (arg_info->pending_sizes)
+ add_stmt (arg_info->pending_sizes);
}
\f
/* Finish up a function declaration and compile that function
- all the way to assembler language output. The free the storage
+ all the way to assembler language output. Then free the storage
for the function definition.
This is called after parsing the body of the function definition. */
finish_function (void)
{
tree fndecl = current_function_decl;
+
+ if (c_dialect_objc ())
+ objc_finish_function ();
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
{
tree args = DECL_ARGUMENTS (fndecl);
- for (; args; args = TREE_CHAIN (args))
+ for (; args; args = DECL_CHAIN (args))
{
tree type = TREE_TYPE (args);
if (INTEGRAL_TYPE_P (type)
TREE_NO_WARNING (fndecl) = 1;
}
+ /* Complain about parameters that are only set, but never otherwise used. */
+ if (warn_unused_but_set_parameter)
+ {
+ tree decl;
+
+ for (decl = DECL_ARGUMENTS (fndecl);
+ decl;
+ decl = DECL_CHAIN (decl))
+ if (TREE_USED (decl)
+ && TREE_CODE (decl) == PARM_DECL
+ && !DECL_READ_P (decl)
+ && DECL_NAME (decl)
+ && !DECL_ARTIFICIAL (decl)
+ && !TREE_NO_WARNING (decl))
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wunused_but_set_parameter,
+ "parameter %qD set but not used", decl);
+ }
+
+ /* Complain about locally defined typedefs that are not used in this
+ function. */
+ maybe_warn_unused_local_typedefs ();
+
/* Store the end of the function, so that we get good line number
info for the epilogue. */
cfun->function_end_locus = input_location;
/* 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);
+ (void) cgraph_get_create_node (fndecl);
}
}
if (!decl_function_context (fndecl))
undef_nested_function = false;
+ if (cfun->language != NULL)
+ {
+ ggc_free (cfun->language);
+ cfun->language = NULL;
+ }
+
/* We're leaving the context of this function, so zap cfun.
It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
tree_rest_of_compilation. */
\f
/* Check the declarations given in a for-loop for satisfying the C99
constraints. If exactly one such decl is found, return it. LOC is
- the location of the opening parenthesis of the for loop. */
+ the location of the opening parenthesis of the for loop. The last
+ parameter allows you to control the "for loop initial declarations
+ are only allowed in C99 mode". Normally, you should pass
+ flag_isoc99 as that parameter. But in some cases (Objective-C
+ foreach loop, for example) we want to run the checks in this
+ function even if not in C99 mode, so we allow the caller to turn
+ off the error about not being in C99 mode.
+*/
tree
-check_for_loop_decls (location_t loc)
+check_for_loop_decls (location_t loc, bool turn_off_iso_c99_error)
{
struct c_binding *b;
tree one_decl = NULL_TREE;
int n_decls = 0;
- if (!flag_isoc99)
+ if (!turn_off_iso_c99_error)
{
static bool hint = true;
/* If we get here, declarations have been used in a for loop without
void
c_push_function_context (void)
{
- struct language_function *p;
- p = GGC_NEW (struct language_function);
- cfun->language = p;
+ struct language_function *p = cfun->language;
+ /* cfun->language might have been already allocated by the use of
+ -Wunused-local-typedefs. In that case, just re-use it. */
+ if (p == NULL)
+ cfun->language = p = ggc_alloc_cleared_language_function ();
p->base.x_stmt_tree = c_stmt_tree;
+ c_stmt_tree.x_cur_stmt_list
+ = VEC_copy (tree, gc, c_stmt_tree.x_cur_stmt_list);
p->x_break_label = c_break_label;
p->x_cont_label = c_cont_label;
p->x_switch_stack = c_switch_stack;
pop_function_context ();
p = cfun->language;
- cfun->language = NULL;
+ /* When -Wunused-local-typedefs is in effect, cfun->languages is
+ used to store data throughout the life time of the current cfun,
+ So don't deallocate it. */
+ if (!warn_unused_local_typedefs)
+ cfun->language = NULL;
if (DECL_STRUCT_FUNCTION (current_function_decl) == 0
&& DECL_SAVED_TREE (current_function_decl) == NULL_TREE)
return 0;
}
+/* In C, the only C-linkage public declaration is at file scope. */
+
+tree
+c_linkage_bindings (tree name)
+{
+ return identifier_global_value (name);
+}
+
/* Record a builtin type for C. If NAME is non-NULL, it is the name used;
otherwise the name is found in ridpointers from RID_INDEX. */
ret->expr = 0;
ret->decl_attr = 0;
ret->attrs = 0;
+ ret->align_log = -1;
ret->typespec_word = cts_none;
ret->storage_class = csc_none;
ret->expr_const_operands = true;
ret->declspecs_seen_p = false;
- ret->type_seen_p = false;
+ ret->typespec_kind = ctsk_none;
ret->non_sc_seen_p = false;
ret->typedef_p = false;
- ret->tag_defined_p = false;
ret->explicit_signed_p = false;
ret->deprecated_p = false;
ret->default_int_p = false;
ret->unsigned_p = false;
ret->complex_p = false;
ret->inline_p = false;
+ ret->noreturn_p = false;
ret->thread_p = false;
ret->const_p = false;
ret->volatile_p = false;
ret->restrict_p = false;
ret->saturating_p = false;
+ ret->alignas_p = false;
ret->address_space = ADDR_SPACE_GENERIC;
return ret;
}
tree type = spec.spec;
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
- specs->type_seen_p = true;
+ specs->typespec_kind = spec.kind;
if (TREE_DEPRECATED (type))
specs->deprecated_p = true;
error_at (loc,
("both %<long%> and %<void%> in "
"declaration specifiers"));
+ else if (specs->typespec_word == cts_int128)
+ error_at (loc,
+ ("both %<long%> and %<__int128%> in "
+ "declaration specifiers"));
else if (specs->typespec_word == cts_bool)
error_at (loc,
("both %<long%> and %<_Bool%> in "
error_at (loc,
("both %<short%> and %<void%> in "
"declaration specifiers"));
+ else if (specs->typespec_word == cts_int128)
+ error_at (loc,
+ ("both %<short%> and %<__int128%> in "
+ "declaration specifiers"));
else if (specs->typespec_word == cts_bool)
error_at (loc,
("both %<short%> and %<_Bool%> in "
dupe = specs->saturating_p;
pedwarn (loc, OPT_pedantic,
"ISO C does not support saturating types");
- if (specs->typespec_word == cts_void)
+ if (specs->typespec_word == cts_int128)
+ {
+ error_at (loc,
+ ("both %<_Sat%> and %<__int128%> in "
+ "declaration specifiers"));
+ }
+ else if (specs->typespec_word == cts_void)
error_at (loc,
("both %<_Sat%> and %<void%> in "
"declaration specifiers"));
else
{
/* "void", "_Bool", "char", "int", "float", "double", "_Decimal32",
- "_Decimal64", "_Decimal128", "_Fract" or "_Accum". */
+ "__int128", "_Decimal64", "_Decimal128", "_Fract" or "_Accum". */
if (specs->typespec_word != cts_none)
{
error_at (loc,
}
switch (i)
{
+ case RID_INT128:
+ if (int128_integer_type_node == NULL_TREE)
+ {
+ error_at (loc, "%<__int128%> is not supported for this target");
+ return specs;
+ }
+ if (!in_system_header)
+ pedwarn (loc, OPT_pedantic,
+ "ISO C does not support %<__int128%> type");
+
+ if (specs->long_p)
+ error_at (loc,
+ ("both %<__int128%> and %<long%> in "
+ "declaration specifiers"));
+ else if (specs->saturating_p)
+ error_at (loc,
+ ("both %<_Sat%> and %<__int128%> in "
+ "declaration specifiers"));
+ else if (specs->short_p)
+ error_at (loc,
+ ("both %<__int128%> and %<short%> in "
+ "declaration specifiers"));
+ else
+ specs->typespec_word = cts_int128;
+ return specs;
case RID_VOID:
if (specs->long_p)
error_at (loc,
else
specs->type = TREE_TYPE (t);
}
- else if (TREE_CODE (type) != ERROR_MARK)
+ else
{
- if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
- specs->tag_defined_p = true;
- if (spec.kind == ctsk_typeof)
+ if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof)
{
specs->typedef_p = true;
if (spec.expr)
dupe = false;
specs->inline_p = true;
break;
+ case RID_NORETURN:
+ /* Duplicate _Noreturn is permitted. */
+ dupe = false;
+ specs->noreturn_p = true;
+ break;
case RID_THREAD:
dupe = specs->thread_p;
if (specs->storage_class == csc_auto)
return specs;
}
+/* Add an _Alignas specifier (expression ALIGN, or type whose
+ alignment is ALIGN) to the declaration specifiers SPECS, returning
+ SPECS. */
+struct c_declspecs *
+declspecs_add_alignas (struct c_declspecs *specs, tree align)
+{
+ int align_log;
+ specs->alignas_p = true;
+ if (align == error_mark_node)
+ return specs;
+ align_log = check_user_alignment (align, true);
+ if (align_log > specs->align_log)
+ specs->align_log = align_log;
+ return specs;
+}
+
/* Combine "long", "short", "signed", "unsigned" and "_Complex" type
specifiers with any other type specifier to determine the resulting
type. This is where ISO C checks on complex types are made, since
gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p
&& !specs->signed_p && !specs->unsigned_p
&& !specs->complex_p);
+
+ /* Set a dummy type. */
+ if (TREE_CODE (specs->type) == ERROR_MARK)
+ specs->type = integer_type_node;
return specs;
}
specs->type = build_complex_type (specs->type);
}
break;
+ case cts_int128:
+ gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p);
+ gcc_assert (!(specs->signed_p && specs->unsigned_p));
+ specs->type = (specs->unsigned_p
+ ? int128_unsigned_type_node
+ : int128_integer_type_node);
+ if (specs->complex_p)
+ {
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C does not support complex integer types");
+ specs->type = build_complex_type (specs->type);
+ }
+ break;
case cts_int:
gcc_assert (!(specs->long_p && specs->short_p));
gcc_assert (!(specs->signed_p && specs->unsigned_p));
bool reconsider;
/* Process the decls in the order they were written. */
- for (decl = globals; decl; decl = TREE_CHAIN (decl))
+ for (decl = globals; decl; decl = DECL_CHAIN (decl))
{
/* Check for used but undefined static functions using the C
standard's definition of "used", and set TREE_NO_WARNING so
do
{
reconsider = false;
- for (decl = globals; decl; decl = TREE_CHAIN (decl))
+ for (decl = globals; decl; decl = DECL_CHAIN (decl))
reconsider |= wrapup_global_declaration_2 (decl);
}
while (reconsider);
- for (decl = globals; decl; decl = TREE_CHAIN (decl))
+ for (decl = globals; decl; decl = DECL_CHAIN (decl))
check_global_declaration_1 (decl);
}
{
tree decl;
- for (decl = globals; decl ; decl = TREE_CHAIN (decl))
+ for (decl = globals; decl ; decl = DECL_CHAIN (decl))
debug_hooks->global_decl (decl);
}
+/* Callback to collect a source_ref from a DECL. */
+
+static void
+collect_source_ref_cb (tree decl)
+{
+ if (!DECL_IS_BUILTIN (decl))
+ collect_source_ref (LOCATION_FILE (decl_sloc (decl, false)));
+}
+
/* Preserve the external declarations scope across a garbage collect. */
static GTY(()) tree ext_block;
+/* Collect all references relevant to SOURCE_FILE. */
+
+static void
+collect_all_refs (const char *source_file)
+{
+ tree t;
+ unsigned i;
+
+ FOR_EACH_VEC_ELT (tree, all_translation_units, i, t)
+ collect_ada_nodes (BLOCK_VARS (DECL_INITIAL (t)), source_file);
+
+ collect_ada_nodes (BLOCK_VARS (ext_block), source_file);
+}
+
+/* Iterate over all global declarations and call CALLBACK. */
+
+static void
+for_each_global_decl (void (*callback) (tree decl))
+{
+ tree t;
+ tree decls;
+ tree decl;
+ unsigned i;
+
+ FOR_EACH_VEC_ELT (tree, all_translation_units, i, t)
+ {
+ decls = DECL_INITIAL (t);
+ for (decl = BLOCK_VARS (decls); decl; decl = TREE_CHAIN (decl))
+ callback (decl);
+ }
+
+ for (decl = BLOCK_VARS (ext_block); decl; decl = TREE_CHAIN (decl))
+ callback (decl);
+}
+
void
c_write_global_declarations (void)
{
tree t;
+ unsigned i;
/* We don't want to do this if generating a PCH. */
if (pch_file)
return;
- /* Don't waste time on further processing if -fsyntax-only.
- Continue for warning and errors issued during lowering though. */
- if (flag_syntax_only)
- return;
+ timevar_start (TV_PHASE_DEFERRED);
+
+ /* Do the Objective-C stuff. This is where all the Objective-C
+ module stuff gets generated (symtab, class/protocol/selector
+ lists etc). */
+ if (c_dialect_objc ())
+ objc_write_global_declarations ();
/* Close the external scope. */
ext_block = pop_scope ();
external_scope = 0;
gcc_assert (!current_scope);
+ /* Handle -fdump-ada-spec[-slim]. */
+ if (dump_enabled_p (TDI_ada))
+ {
+ /* Build a table of files to generate specs for */
+ if (get_dump_file_info (TDI_ada)->flags & TDF_SLIM)
+ collect_source_ref (main_input_filename);
+ else
+ for_each_global_decl (collect_source_ref_cb);
+
+ dump_ada_specs (collect_all_refs, NULL);
+ }
+
if (ext_block)
{
tree tmp = BLOCK_VARS (ext_block);
/* 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))
+ FOR_EACH_VEC_ELT (tree, all_translation_units, i, t)
c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
c_write_global_declarations_1 (BLOCK_VARS (ext_block));
+ timevar_stop (TV_PHASE_DEFERRED);
+ timevar_start (TV_PHASE_CGRAPH);
+
/* We're done parsing; proceed to optimize and emit assembly.
FIXME: shouldn't be the front end's responsibility to call this. */
cgraph_finalize_compilation_unit ();
+ timevar_stop (TV_PHASE_CGRAPH);
+ timevar_start (TV_PHASE_DBGINFO);
+
/* 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)
+ if (!seen_error ())
{
timevar_push (TV_SYMOUT);
- for (t = all_translation_units; t; t = TREE_CHAIN (t))
+ FOR_EACH_VEC_ELT (tree, all_translation_units, i, 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;
+ timevar_stop (TV_PHASE_DBGINFO);
+}
+
+/* Register reserved keyword WORD as qualifier for address space AS. */
+
+void
+c_register_addr_space (const char *word, addr_space_t as)
+{
+ int rid = RID_FIRST_ADDR_SPACE + as;
+ tree id;
+
+ /* Address space qualifiers are only supported
+ in C with GNU extensions enabled. */
+ if (c_dialect_objc () || flag_no_asm)
+ return;
+
+ id = get_identifier (word);
+ C_SET_RID_CODE (id, rid);
+ C_IS_RESERVED_WORD (id) = 1;
+ ridpointers [rid] = id;
}
#include "gt-c-decl.h"