#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "input.h"
#include "tm.h"
#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 "langhooks.h"
#include "tree-mudflap.h"
#include "tree-gimple.h"
#include "diagnostic.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"
#ifdef ENABLE_LLVM
#include "llvm.h"
#endif
enum decl_context
{ NORMAL,
FUNCDEF,
BLOCKDEF,
PARM,
FIELD,
TYPENAME};
tree pending_invalid_xref;
location_t pending_invalid_xref_location;
bool c_eh_initialized_p;
static tree enum_next_value;
static int enum_overflow;
static location_t current_function_prototype_locus;
static bool current_function_prototype_built_in;
static tree current_function_prototype_arg_types;
static struct c_arg_info *current_function_arg_info;
struct obstack parser_obstack;
static GTY(()) struct stmt_tree_s c_stmt_tree;
tree c_break_label;
tree c_cont_label;
static GTY(()) tree all_translation_units;
static GTY(()) tree visible_builtins;
int current_function_returns_value;
int current_function_returns_null;
int current_function_returns_abnormally;
static int warn_about_return_type;
static bool undef_nested_function;
bool c_override_global_bindings_to_false;
struct c_binding GTY((chain_next ("%h.prev")))
{
tree decl;
tree type;
tree id;
struct c_binding *prev;
struct c_binding *shadowed;
unsigned int depth : 28;
BOOL_BITFIELD invisible : 1;
BOOL_BITFIELD nested : 1;
BOOL_BITFIELD inner_comp : 1;
};
#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth)
#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth)
#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 )
#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 )
#define I_SYMBOL_BINDING(node) \
(((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->symbol_binding)
#define I_SYMBOL_DECL(node) \
(I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0)
#define I_TAG_BINDING(node) \
(((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->tag_binding)
#define I_TAG_DECL(node) \
(I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0)
#define I_LABEL_BINDING(node) \
(((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->label_binding)
#define I_LABEL_DECL(node) \
(I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0)
struct lang_identifier GTY(())
{
struct c_common_identifier common_id;
struct c_binding *symbol_binding;
struct c_binding *tag_binding;
struct c_binding *label_binding;
};
extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate
[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1];
union lang_tree_node
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)")))
{
union tree_node GTY ((tag ("0"),
desc ("tree_node_structure (&%h)")))
generic;
struct lang_identifier GTY ((tag ("1"))) identifier;
};
struct c_scope GTY((chain_next ("%h.outer")))
{
struct c_scope *outer;
struct c_scope *outer_function;
struct c_binding *bindings;
tree blocks;
tree blocks_last;
unsigned int depth : 28;
BOOL_BITFIELD parm_flag : 1;
BOOL_BITFIELD had_vla_unspec : 1;
BOOL_BITFIELD warned_forward_parm_decls : 1;
BOOL_BITFIELD function_body : 1;
BOOL_BITFIELD keep : 1;
};
static GTY(()) struct c_scope *current_scope;
static GTY(()) struct c_scope *current_function_scope;
static GTY(()) struct c_scope *file_scope;
static GTY(()) struct c_scope *external_scope;
static GTY((deletable)) struct c_scope *scope_freelist;
static GTY((deletable)) struct c_binding *binding_freelist;
#define SCOPE_LIST_APPEND(scope, list, decl) do { \
struct c_scope *s_ = (scope); \
tree d_ = (decl); \
if (s_->list##_last) \
TREE_CHAIN (s_->list##_last) = d_; \
else \
s_->list = d_; \
s_->list##_last = d_; \
} while (0)
#define SCOPE_LIST_CONCAT(tscope, to, fscope, from) do { \
struct c_scope *t_ = (tscope); \
struct c_scope *f_ = (fscope); \
if (t_->to##_last) \
TREE_CHAIN (t_->to##_last) = f_->from; \
else \
t_->to = f_->from; \
t_->to##_last = f_->from##_last; \
} while (0)
static bool keep_next_level_flag;
static bool next_is_function_body;
static GTY(()) tree static_ctors;
static GTY(()) tree static_dtors;
static tree lookup_name_in_scope (tree, struct c_scope *);
static tree c_make_fname_decl (tree, int);
static tree grokdeclarator (const struct c_declarator *,
struct c_declspecs *,
enum decl_context, bool, tree *);
static tree grokparms (struct c_arg_info *, bool);
static void layout_array_type (tree);
tree
add_stmt (tree t)
{
enum tree_code code = TREE_CODE (t);
if (EXPR_P (t) && code != LABEL_EXPR)
{
if (!EXPR_HAS_LOCATION (t))
SET_EXPR_LOCATION (t, input_location);
}
if (code == LABEL_EXPR || code == CASE_LABEL_EXPR)
STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1;
append_to_statement_list_force (t, &cur_stmt_list);
return t;
}
enum deprecated_states {
DEPRECATED_NORMAL,
DEPRECATED_SUPPRESS
, DEPRECATED_UNAVAILABLE_SUPPRESS
};
static enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
void
c_print_identifier (FILE *file, tree node, int indent)
{
print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4);
print_node (file, "tag", I_TAG_DECL (node), indent + 4);
print_node (file, "label", I_LABEL_DECL (node), indent + 4);
if (C_IS_RESERVED_WORD (node))
{
tree rid = ridpointers[C_RID_CODE (node)];
indent_to (file, indent + 4);
fprintf (file, "rid %p \"%s\"",
(void *) rid, IDENTIFIER_POINTER (rid));
}
}
static void
bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested)
{
struct c_binding *b, **here;
if (binding_freelist)
{
b = binding_freelist;
binding_freelist = b->prev;
}
else
b = GGC_NEW (struct c_binding);
b->shadowed = 0;
b->decl = decl;
b->id = name;
b->depth = scope->depth;
b->invisible = invisible;
b->nested = nested;
b->inner_comp = 0;
b->type = 0;
b->prev = scope->bindings;
scope->bindings = b;
if (!name)
return;
switch (TREE_CODE (decl))
{
case LABEL_DECL: here = &I_LABEL_BINDING (name); break;
case ENUMERAL_TYPE:
case UNION_TYPE:
case RECORD_TYPE: here = &I_TAG_BINDING (name); break;
case VAR_DECL:
case FUNCTION_DECL:
case TYPE_DECL:
case CONST_DECL:
case PARM_DECL:
case ERROR_MARK: here = &I_SYMBOL_BINDING (name); break;
default:
gcc_unreachable ();
}
while (*here && (*here)->depth > scope->depth)
here = &(*here)->shadowed;
b->shadowed = *here;
*here = b;
}
static struct c_binding *
free_binding_and_advance (struct c_binding *b)
{
struct c_binding *prev = b->prev;
memset (b, 0, sizeof (struct c_binding));
b->prev = binding_freelist;
binding_freelist = b;
return prev;
}
void
c_finish_incomplete_decl (tree decl)
{
if (TREE_CODE (decl) == VAR_DECL)
{
tree type = TREE_TYPE (decl);
if (type != error_mark_node
&& TREE_CODE (type) == ARRAY_TYPE
&& !DECL_EXTERNAL (decl)
&& TYPE_DOMAIN (type) == 0)
{
warning (0, "array %q+D assumed to have one element", decl);
complete_array_type (&TREE_TYPE (decl), NULL_TREE, true);
layout_decl (decl, 0);
}
}
}
void *
objc_get_current_scope (void)
{
return current_scope;
}
void
objc_mark_locals_volatile (void *enclosing_blk)
{
struct c_scope *scope;
struct c_binding *b;
for (scope = current_scope;
scope && scope != enclosing_blk;
scope = scope->outer)
{
for (b = scope->bindings; b; b = b->prev)
objc_volatilize_decl (b->decl);
if (scope->function_body)
break;
}
}
int
global_bindings_p (void)
{
return current_scope == file_scope && !c_override_global_bindings_to_false;
}
void
keep_next_level (void)
{
keep_next_level_flag = true;
}
void
declare_parm_level (void)
{
current_scope->parm_flag = true;
}
void
push_scope (void)
{
if (next_is_function_body)
{
current_scope->parm_flag = false;
current_scope->function_body = true;
current_scope->keep = true;
current_scope->outer_function = current_function_scope;
current_function_scope = current_scope;
keep_next_level_flag = false;
next_is_function_body = false;
}
else
{
struct c_scope *scope;
if (scope_freelist)
{
scope = scope_freelist;
scope_freelist = scope->outer;
}
else
scope = GGC_CNEW (struct c_scope);
scope->keep = keep_next_level_flag;
scope->outer = current_scope;
scope->depth = current_scope ? (current_scope->depth + 1) : 0;
if (current_scope && scope->depth == 0)
{
scope->depth--;
sorry ("GCC supports only %u nested scopes", scope->depth);
}
current_scope = scope;
keep_next_level_flag = false;
}
}
static void
set_type_context (tree type, tree context)
{
for (type = TYPE_MAIN_VARIANT (type); type;
type = TYPE_NEXT_VARIANT (type))
TYPE_CONTEXT (type) = context;
}
tree
pop_scope (void)
{
struct c_scope *scope = current_scope;
tree block, context, p;
struct c_binding *b;
bool functionbody = scope->function_body;
bool keep = functionbody || scope->keep || scope->bindings;
c_end_vm_scope (scope->depth);
block = 0;
if (keep)
{
block = make_node (BLOCK);
BLOCK_SUBBLOCKS (block) = scope->blocks;
TREE_USED (block) = 1;
for (p = scope->blocks; p; p = TREE_CHAIN (p))
BLOCK_SUPERCONTEXT (p) = block;
BLOCK_VARS (block) = 0;
}
if (scope->function_body)
context = current_function_decl;
else if (scope == file_scope)
{
tree file_decl = build_decl (TRANSLATION_UNIT_DECL, 0, 0);
TREE_CHAIN (file_decl) = all_translation_units;
all_translation_units = file_decl;
context = file_decl;
}
else
context = block;
for (b = scope->bindings; b; b = free_binding_and_advance (b))
{
p = b->decl;
switch (TREE_CODE (p))
{
case LABEL_DECL:
if (TREE_USED (p) && !DECL_INITIAL (p))
{
error ("label %q+D used but not defined", p);
DECL_INITIAL (p) = error_mark_node;
}
else if (!TREE_USED (p) && warn_unused_label &&
strncmp( IDENTIFIER_POINTER (DECL_NAME (p)), "LASM$", 5) != 0)
{
if (DECL_INITIAL (p))
warning (0, "label %q+D defined but not used", p);
else
warning (0, "label %q+D declared but not defined", p);
}
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;
case ENUMERAL_TYPE:
case UNION_TYPE:
case RECORD_TYPE:
set_type_context (p, context);
if (b->id)
{
gcc_assert (I_TAG_BINDING (b->id) == b);
I_TAG_BINDING (b->id) = b->shadowed;
}
break;
case FUNCTION_DECL:
if (!TREE_ASM_WRITTEN (p)
&& DECL_INITIAL (p) != 0
&& TREE_ADDRESSABLE (p)
&& DECL_ABSTRACT_ORIGIN (p) != 0
&& DECL_ABSTRACT_ORIGIN (p) != p)
TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1;
if (!DECL_EXTERNAL (p)
&& !DECL_INITIAL (p)
&& scope != file_scope
&& scope != external_scope)
{
error ("nested function %q+D declared but never defined", p);
undef_nested_function = true;
}
else if (DECL_DECLARED_INLINE_P (p)
&& TREE_PUBLIC (p)
&& !DECL_INITIAL (p)
&& !flag_gnu89_inline)
pedwarn ("%Jinline function %qD declared but never defined", p, p);
goto common_symbol;
case VAR_DECL:
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)
warning (OPT_Wunused_variable, "unused variable %q+D", p);
if (b->inner_comp)
{
error ("type of array %q+D completed incompatibly with"
" implicit initialization", p);
}
case TYPE_DECL:
case CONST_DECL:
common_symbol:
if (!b->nested)
{
TREE_CHAIN (p) = BLOCK_VARS (block);
BLOCK_VARS (block) = p;
}
if (scope == file_scope && num_in_fnames > 1)
{
DECL_CONTEXT (p) = context;
if (TREE_CODE (p) == TYPE_DECL)
set_type_context (TREE_TYPE (p), context);
}
case PARM_DECL:
case ERROR_MARK:
if (b->id)
{
gcc_assert (I_SYMBOL_BINDING (b->id) == b);
I_SYMBOL_BINDING (b->id) = b->shadowed;
if (b->shadowed && b->shadowed->type)
TREE_TYPE (b->shadowed->decl) = b->shadowed->type;
}
break;
default:
gcc_unreachable ();
}
}
if ((scope->function_body || scope == file_scope) && context)
{
DECL_INITIAL (context) = block;
BLOCK_SUPERCONTEXT (block) = context;
}
else if (scope->outer)
{
if (block)
SCOPE_LIST_APPEND (scope->outer, blocks, block);
else if (scope->blocks)
SCOPE_LIST_CONCAT (scope->outer, blocks, scope, blocks);
}
current_scope = scope->outer;
if (scope->function_body)
current_function_scope = scope->outer_function;
memset (scope, 0, sizeof (struct c_scope));
scope->outer = scope_freelist;
scope_freelist = scope;
return block;
}
void
push_file_scope (void)
{
tree decl;
if (file_scope)
return;
push_scope ();
file_scope = current_scope;
start_fname_decls ();
for (decl = visible_builtins; decl; decl = TREE_CHAIN (decl))
bind (DECL_NAME (decl), decl, file_scope,
false, true);
}
void
pop_file_scope (void)
{
while (current_scope != file_scope)
pop_scope ();
finish_fname_decls ();
if (pch_file)
{
c_common_write_pch ();
return;
}
pop_scope ();
file_scope = 0;
maybe_apply_pending_pragma_weaks ();
cgraph_finalize_compilation_unit ();
}
void
insert_block (tree block)
{
TREE_USED (block) = 1;
SCOPE_LIST_APPEND (current_scope, blocks, block);
}
static void
pushtag (tree name, tree type)
{
if (name && !TYPE_NAME (type))
TYPE_NAME (type) = name;
bind (name, type, current_scope, false, false);
TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type));
TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type));
}
static tree
match_builtin_function_types (tree newtype, tree oldtype)
{
tree newrettype, oldrettype;
tree newargs, oldargs;
tree trytype, tryargs;
oldrettype = TREE_TYPE (oldtype);
newrettype = TREE_TYPE (newtype);
if (TYPE_MODE (oldrettype) != TYPE_MODE (newrettype))
return 0;
oldargs = TYPE_ARG_TYPES (oldtype);
newargs = TYPE_ARG_TYPES (newtype);
tryargs = newargs;
while (oldargs || newargs)
{
if (!oldargs
|| !newargs
|| !TREE_VALUE (oldargs)
|| !TREE_VALUE (newargs)
|| TYPE_MODE (TREE_VALUE (oldargs))
!= TYPE_MODE (TREE_VALUE (newargs)))
return 0;
oldargs = TREE_CHAIN (oldargs);
newargs = TREE_CHAIN (newargs);
}
trytype = build_function_type (newrettype, tryargs);
return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype));
}
static void
diagnose_arglist_conflict (tree newdecl, tree olddecl,
tree newtype, tree oldtype)
{
tree t;
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)))
return;
t = TYPE_ARG_TYPES (oldtype);
if (t == 0)
t = TYPE_ARG_TYPES (newtype);
for (; t; t = TREE_CHAIN (t))
{
tree type = TREE_VALUE (t);
if (TREE_CHAIN (t) == 0
&& TYPE_MAIN_VARIANT (type) != void_type_node)
{
inform ("a parameter list with an ellipsis can%'t match "
"an empty parameter name list declaration");
break;
}
if (c_type_promotes_to (type) != type)
{
inform ("an argument type that has a default promotion can%'t match "
"an empty parameter name list declaration");
break;
}
}
}
static bool
validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
{
tree newargs, oldargs;
int i;
#define END_OF_ARGLIST(t) ((t) == void_type_node)
oldargs = TYPE_ACTUAL_ARG_TYPES (oldtype);
newargs = TYPE_ARG_TYPES (newtype);
i = 1;
for (;;)
{
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;
if (END_OF_ARGLIST (oldargtype))
{
error ("prototype for %q+D declares more arguments "
"than previous old-style definition", newdecl);
return false;
}
else if (END_OF_ARGLIST (newargtype))
{
error ("prototype for %q+D declares fewer arguments "
"than previous old-style definition", newdecl);
return false;
}
else if (!comptypes (oldargtype, newargtype))
{
error ("prototype for %q+D declares argument %d"
" with incompatible type",
newdecl, i);
return false;
}
oldargs = TREE_CHAIN (oldargs);
newargs = TREE_CHAIN (newargs);
i++;
}
warning (0, "prototype for %q+D follows non-prototype definition",
newdecl);
return true;
#undef END_OF_ARGLIST
}
static void
locate_old_decl (tree decl, void (*diag)(const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2))
{
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
;
else if (DECL_INITIAL (decl))
diag (G_("previous definition of %q+D was here"), decl);
else if (C_DECL_IMPLICIT (decl))
diag (G_("previous implicit declaration of %q+D was here"), decl);
else
diag (G_("previous declaration of %q+D was here"), decl);
}
static bool
diagnose_mismatched_decls (tree newdecl, tree olddecl,
tree *newtypep, tree *oldtypep)
{
tree newtype, oldtype;
bool pedwarned = false;
bool warned = false;
bool retval = true;
#define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL) \
&& DECL_EXTERNAL (DECL))
if (olddecl == error_mark_node || newdecl == error_mark_node)
return false;
*oldtypep = oldtype = TREE_TYPE (olddecl);
*newtypep = newtype = TREE_TYPE (newdecl);
if (oldtype == error_mark_node || newtype == error_mark_node)
return false;
if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
{
if (!(TREE_CODE (olddecl) == FUNCTION_DECL
&& DECL_BUILT_IN (olddecl)
&& !C_DECL_DECLARED_BUILTIN (olddecl)))
{
error ("%q+D redeclared as different kind of symbol", newdecl);
locate_old_decl (olddecl, error);
}
else if (TREE_PUBLIC (newdecl))
warning (0, "built-in function %q+D declared as non-function",
newdecl);
else
warning (OPT_Wshadow, "declaration of %q+D shadows "
"a built-in function", newdecl);
return false;
}
if (TREE_CODE (olddecl) == CONST_DECL)
{
error ("redeclaration of enumerator %q+D", newdecl);
locate_old_decl (olddecl, error);
return false;
}
if (!comptypes (oldtype, newtype))
{
if (TREE_CODE (olddecl) == FUNCTION_DECL
&& DECL_BUILT_IN (olddecl) && !C_DECL_DECLARED_BUILTIN (olddecl))
{
tree trytype = match_builtin_function_types (newtype, oldtype);
if (trytype && comptypes (newtype, trytype))
*oldtypep = oldtype = trytype;
else
{
warning (0, "conflicting types for built-in function %q+D",
newdecl);
return false;
}
}
else if (TREE_CODE (olddecl) == FUNCTION_DECL
&& DECL_IS_BUILTIN (olddecl))
{
TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
return false;
}
else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl)
&& TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
&& C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl))
{
pedwarn ("conflicting types for %q+D", newdecl);
TREE_TYPE (newdecl) = *newtypep = newtype = oldtype;
C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
pedwarned = true;
}
else if (TREE_CODE (newdecl) == FUNCTION_DECL
&& TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == void_type_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node
&& C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl))
{
pedwarn ("conflicting types for %q+D", newdecl);
TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype;
pedwarned = true;
}
else
{
bool warn = false;
if (disable_typechecking_for_spec_flag
&& TREE_PUBLIC (olddecl)
&& TREE_PUBLIC (newdecl)
&& ((TREE_CODE (olddecl) == VAR_DECL
&& TREE_CODE (newdecl) == VAR_DECL
&& !same_translation_unit_p (olddecl, newdecl))
|| (TREE_CODE (olddecl) == FUNCTION_DECL
&& TREE_CODE (newdecl) == FUNCTION_DECL)))
warn = true;
if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype))
if (warn)
warning (0, "conflicting type qualifiers for %q+D", newdecl);
else
error ("conflicting type qualifiers for %q+D", newdecl);
else
if (warn)
warning (0, "conflicting types for %q+D", newdecl);
else
error ("conflicting types for %q+D", newdecl);
diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
locate_old_decl (olddecl, warn ? warning0 : error);
if (warn && TREE_CODE (olddecl) == VAR_DECL)
{
HOST_WIDE_INT newalias;
if (TYPE_ALIAS_SET_KNOWN_P (oldtype))
{
newalias = TYPE_ALIAS_SET (oldtype);
if (TYPE_ALIAS_SET_KNOWN_P (newtype)
&& newalias != TYPE_ALIAS_SET (oldtype))
internal_error ("%Jalias set conflict for '%D'",
newdecl, newdecl);
}
else if (TYPE_ALIAS_SET_KNOWN_P (newtype))
newalias = TYPE_ALIAS_SET (newtype);
else
newalias = new_alias_set ();
TYPE_ALIAS_SET (oldtype) = newalias;
TYPE_ALIAS_SET (newtype) = newalias;
if (!DECL_SIZE (newdecl))
DECL_DUPLICATE_DECL (newdecl) = 1;
else if (!DECL_SIZE (olddecl))
DECL_DUPLICATE_DECL (olddecl) = 1;
else if (tree_int_cst_lt (DECL_SIZE (newdecl),
DECL_SIZE (olddecl)))
DECL_DUPLICATE_DECL (newdecl) = 1;
else
DECL_DUPLICATE_DECL (olddecl) = 1;
}
return false;
}
}
if (TREE_CODE (newdecl) == TYPE_DECL)
{
if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl))
return true;
error ("redefinition of typedef %q+D", newdecl);
locate_old_decl (olddecl, error);
return false;
}
else if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
if (DECL_BUILT_IN (olddecl)
&& !C_DECL_DECLARED_BUILTIN (olddecl)
&& (!TREE_PUBLIC (newdecl)
|| (DECL_INITIAL (newdecl)
&& !TYPE_ARG_TYPES (TREE_TYPE (newdecl)))))
{
warning (OPT_Wshadow, "declaration of %q+D shadows "
"a built-in function", newdecl);
return false;
}
if (DECL_INITIAL (newdecl))
{
if (DECL_INITIAL (olddecl))
{
if ((!DECL_EXTERN_INLINE (olddecl)
|| DECL_EXTERN_INLINE (newdecl)
|| (!flag_gnu89_inline
&& (!DECL_DECLARED_INLINE_P (olddecl)
|| !lookup_attribute ("gnu_inline",
DECL_ATTRIBUTES (olddecl)))
&& (!DECL_DECLARED_INLINE_P (newdecl)
|| !lookup_attribute ("gnu_inline",
DECL_ATTRIBUTES (newdecl))))
)
&& same_translation_unit_p (newdecl, olddecl))
{
error ("redefinition of %q+D", newdecl);
locate_old_decl (olddecl, error);
return false;
}
}
}
else if (DECL_INITIAL (olddecl)
&& !TYPE_ARG_TYPES (oldtype) && TYPE_ARG_TYPES (newtype)
&& TYPE_ACTUAL_ARG_TYPES (oldtype)
&& !validate_proto_after_old_defn (newdecl, newtype, oldtype))
{
locate_old_decl (olddecl, error);
return false;
}
if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl))
{
if (!DECL_IS_BUILTIN (olddecl)
&& !DECL_EXTERN_INLINE (olddecl))
{
error ("static declaration of %q+D follows "
"non-static declaration", newdecl);
locate_old_decl (olddecl, error);
}
return false;
}
else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl))
{
if (DECL_CONTEXT (olddecl))
{
error ("non-static declaration of %q+D follows "
"static declaration", newdecl);
locate_old_decl (olddecl, error);
return false;
}
else if (warn_traditional)
{
warning (OPT_Wtraditional, "non-static declaration of %q+D "
"follows static declaration", newdecl);
warned = true;
}
}
}
else if (TREE_CODE (newdecl) == VAR_DECL)
{
if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (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 "
"non-thread-local declaration", newdecl);
else
error ("non-thread-local declaration of %q+D follows "
"thread-local declaration", newdecl);
locate_old_decl (olddecl, error);
return false;
}
if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
{
error ("redefinition of %q+D", newdecl);
locate_old_decl (olddecl, error);
return false;
}
if (DECL_FILE_SCOPE_P (newdecl)
&& TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl))
{
if (DECL_EXTERNAL (newdecl))
{
if (!DECL_FILE_SCOPE_P (olddecl))
{
error ("extern declaration of %q+D follows "
"declaration with no linkage", newdecl);
locate_old_decl (olddecl, error);
return false;
}
else if (warn_traditional)
{
warning (OPT_Wtraditional, "non-static declaration of %q+D "
"follows static declaration", newdecl);
warned = true;
}
}
else
{
if (TREE_PUBLIC (newdecl))
error ("non-static declaration of %q+D follows "
"static declaration", newdecl);
else
error ("static declaration of %q+D follows "
"non-static declaration", newdecl);
locate_old_decl (olddecl, error);
return false;
}
}
else if (!DECL_FILE_SCOPE_P (newdecl))
{
if (DECL_EXTERNAL (newdecl))
{
}
else if (DECL_EXTERNAL (olddecl))
{
error ("declaration of %q+D with no linkage follows "
"extern declaration", newdecl);
locate_old_decl (olddecl, error);
}
else
{
error ("redeclaration of %q+D with no linkage", newdecl);
locate_old_decl (olddecl, error);
}
return false;
}
}
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))
{
warning (0, "redeclaration of %q+D with different visibility "
"(old visibility preserved)", newdecl);
warned = true;
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
if (DECL_DECLARED_INLINE_P (newdecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
{
warning (OPT_Wattributes, "inline declaration of %qD follows "
"declaration with attribute noinline", newdecl);
warned = true;
}
else if (DECL_DECLARED_INLINE_P (olddecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
{
warning (OPT_Wattributes, "declaration of %q+D with attribute "
"noinline follows inline declaration ", newdecl);
warned = true;
}
if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)
&& same_translation_unit_p (olddecl, newdecl)
&& flag_gnu89_inline)
{
if (TREE_USED (olddecl))
{
warning (0, "%q+D declared inline after being called", olddecl);
warned = true;
}
else if (DECL_INITIAL (olddecl))
{
warning (0, "%q+D declared inline after its definition", olddecl);
warned = true;
}
}
}
else
{
if (TREE_CODE (newdecl) == PARM_DECL
&& (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl)))
{
error ("redefinition of parameter %q+D", newdecl);
locate_old_decl (olddecl, error);
return false;
}
}
if (!warned && !pedwarned
&& warn_redundant_decls
&& !(TREE_CODE (newdecl) == FUNCTION_DECL
&& DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))
&& !(TREE_CODE (newdecl) == FUNCTION_DECL
&& !DECL_BUILT_IN (newdecl)
&& DECL_BUILT_IN (olddecl)
&& !C_DECL_DECLARED_BUILTIN (olddecl))
&& !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl))
&& !(TREE_CODE (newdecl) == PARM_DECL
&& TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl))
&& !(TREE_CODE (newdecl) == VAR_DECL
&& DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)))
{
warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D",
newdecl);
warned = true;
}
if (warned || pedwarned)
locate_old_decl (olddecl, pedwarned ? pedwarn : warning0);
#undef DECL_EXTERN_INLINE
return retval;
}
static void
merge_decls (tree newdecl, tree olddecl, tree newtype, tree 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);
bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
&& TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
bool extern_changed = false;
if (TREE_CODE (newdecl) == PARM_DECL
&& TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl))
{
struct c_binding *b, **here;
for (here = ¤t_scope->bindings; *here; here = &(*here)->prev)
if ((*here)->decl == olddecl)
goto found;
gcc_unreachable ();
found:
b = *here;
*here = b->prev;
b->prev = current_scope->bindings;
current_scope->bindings = b;
TREE_ASM_WRITTEN (olddecl) = 0;
}
DECL_ATTRIBUTES (newdecl)
= targetm.merge_decl_attributes (olddecl, newdecl);
TREE_TYPE (newdecl)
= TREE_TYPE (olddecl)
= composite_type (newtype, oldtype);
if (!comptypes (oldtype, TREE_TYPE (newdecl)))
{
if (TREE_TYPE (newdecl) != error_mark_node)
layout_type (TREE_TYPE (newdecl));
if (TREE_CODE (newdecl) != FUNCTION_DECL
&& TREE_CODE (newdecl) != TYPE_DECL
&& TREE_CODE (newdecl) != CONST_DECL)
layout_decl (newdecl, 0);
}
else
{
DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
DECL_MODE (newdecl) = DECL_MODE (olddecl);
if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
{
DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
}
}
if (TREE_READONLY (newdecl))
TREE_READONLY (olddecl) = 1;
if (TREE_THIS_VOLATILE (newdecl))
TREE_THIS_VOLATILE (olddecl) = 1;
if (TREE_DEPRECATED (newdecl))
TREE_DEPRECATED (olddecl) = 1;
if (TREE_UNAVAILABLE (newdecl))
TREE_UNAVAILABLE (olddecl) = 1;
if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
|| (old_is_prototype && !new_is_prototype
&& !C_DECL_BUILTIN_PROTOTYPE (olddecl)))
DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
if (DECL_INITIAL (newdecl) == 0)
DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
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;
}
if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
{
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_SECTION_NAME (newdecl) == NULL_TREE)
DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
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_weak (newdecl, olddecl);
if (TREE_CODE (newdecl) == FUNCTION_DECL
&& !flag_gnu89_inline
&& current_scope == file_scope
&& (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;
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
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);
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 (new_is_definition && DECL_INITIAL (olddecl))
{
if (TREE_USED (olddecl)
&& !flag_unit_at_a_time
&& cgraph_function_possibly_inlined_p (olddecl))
(*debug_hooks->outlining_inline_function) (olddecl);
DECL_INLINE (newdecl) = 0;
DECL_UNINLINABLE (newdecl) = 1;
}
else
{
if (DECL_DECLARED_INLINE_P (newdecl)
|| DECL_DECLARED_INLINE_P (olddecl))
DECL_DECLARED_INLINE_P (newdecl) = 1;
if (DECL_EXPLICIT_INLINE_P (olddecl))
DECL_EXPLICIT_INLINE_P (newdecl) = 1;
DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
= (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
}
if (DECL_BUILT_IN (olddecl))
{
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);
}
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);
if (DECL_INLINE (olddecl) && !DECL_UNINLINABLE (newdecl))
{
DECL_INLINE (newdecl) = 1;
DECL_ABSTRACT_ORIGIN (newdecl)
= DECL_ABSTRACT_ORIGIN (olddecl);
}
}
else
{
if (DECL_DECLARED_INLINE_P (newdecl)
&& !DECL_UNINLINABLE (newdecl))
DECL_INLINE (newdecl) = 1;
}
}
extern_changed = DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl);
{
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));
switch (TREE_CODE (olddecl))
{
case FIELD_DECL:
case VAR_DECL:
case PARM_DECL:
case LABEL_DECL:
case RESULT_DECL:
case CONST_DECL:
case TYPE_DECL:
case FUNCTION_DECL:
memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
(char *) newdecl + sizeof (struct tree_decl_common),
tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_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));
}
DECL_UID (olddecl) = olddecl_uid;
DECL_CONTEXT (olddecl) = olddecl_context;
}
#ifndef ENABLE_LLVM
if (DECL_RTL_SET_P (olddecl)
&& (TREE_CODE (olddecl) == FUNCTION_DECL
|| (TREE_CODE (olddecl) == VAR_DECL
&& TREE_STATIC (olddecl))))
make_decl_rtl (olddecl);
#else
if (DECL_LLVM_SET_P (olddecl)
&& (TREE_CODE (olddecl) == FUNCTION_DECL
|| (TREE_CODE (olddecl) == VAR_DECL
&& TREE_STATIC (olddecl))))
make_decl_llvm (olddecl);
#endif
if (extern_changed && !new_is_definition
&& TREE_CODE (olddecl) == FUNCTION_DECL && DECL_INITIAL (olddecl))
cgraph_finalize_function (olddecl, false);
}
static bool
duplicate_decls (tree newdecl, tree olddecl)
{
tree newtype = NULL, oldtype = NULL;
if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype))
{
TREE_NO_WARNING (olddecl) = 1;
return false;
}
merge_decls (newdecl, olddecl, newtype, oldtype);
return true;
}
static void
warn_if_shadowing (tree new_decl)
{
struct c_binding *b;
if (!warn_shadow
|| DECL_IS_BUILTIN (new_decl)
|| DECL_FROM_INLINE (new_decl))
return;
for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed)
if (b->decl && b->decl != new_decl && !b->invisible)
{
tree old_decl = b->decl;
if (old_decl == error_mark_node)
{
warning (OPT_Wshadow, "declaration of %q+D shadows previous "
"non-variable", new_decl);
break;
}
else if (TREE_CODE (old_decl) == PARM_DECL)
warning (OPT_Wshadow, "declaration of %q+D shadows a parameter",
new_decl);
else if (DECL_FILE_SCOPE_P (old_decl))
warning (OPT_Wshadow, "declaration of %q+D shadows a global "
"declaration", new_decl);
else if (TREE_CODE (old_decl) == FUNCTION_DECL
&& DECL_BUILT_IN (old_decl))
{
warning (OPT_Wshadow, "declaration of %q+D shadows "
"a built-in function", new_decl);
break;
}
else
warning (OPT_Wshadow, "declaration of %q+D shadows a previous local",
new_decl);
warning (OPT_Wshadow, "%Jshadowed declaration is here", old_decl);
break;
}
}
static void
clone_underlying_type (tree x)
{
if (DECL_IS_BUILTIN (x))
{
if (TYPE_NAME (TREE_TYPE (x)) == 0)
TYPE_NAME (TREE_TYPE (x)) = x;
}
else if (TREE_TYPE (x) != error_mark_node
&& DECL_ORIGINAL_TYPE (x) == NULL_TREE)
{
tree tt = TREE_TYPE (x);
DECL_ORIGINAL_TYPE (x) = tt;
tt = build_variant_type_copy (tt);
TYPE_NAME (tt) = x;
TREE_USED (tt) = TREE_USED (x);
TREE_TYPE (x) = tt;
}
}
tree
pushdecl (tree x)
{
tree name = DECL_NAME (x);
struct c_scope *scope = current_scope;
struct c_binding *b;
bool nested = false;
if (TREE_CODE (x) == FUNCTION_DECL && !DECL_LANG_SPECIFIC (x))
DECL_LANG_SPECIFIC (x) = GGC_CNEW (struct lang_decl);
if (current_function_decl
&& ((TREE_CODE (x) != FUNCTION_DECL && TREE_CODE (x) != VAR_DECL)
|| DECL_INITIAL (x) || !DECL_EXTERNAL (x)))
DECL_CONTEXT (x) = current_function_decl;
if ((TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == TYPE_DECL)
&& variably_modified_type_p (TREE_TYPE (x), NULL_TREE))
c_begin_vm_scope (scope->depth);
if (!name)
{
bind (name, x, scope, false, false);
return x;
}
b = I_SYMBOL_BINDING (name);
if (b && B_IN_SCOPE (b, scope))
{
struct c_binding *b_ext, *b_use;
tree type = TREE_TYPE (x);
tree visdecl = b->decl;
tree vistype = TREE_TYPE (visdecl);
if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
&& COMPLETE_TYPE_P (TREE_TYPE (x)))
b->inner_comp = false;
b_use = b;
b_ext = b;
if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl))
{
while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext))
b_ext = b_ext->shadowed;
if (b_ext)
{
b_use = b_ext;
if (b_use->type)
TREE_TYPE (b_use->decl) = b_use->type;
}
}
if (duplicate_decls (x, b_use->decl))
{
if (b_use != b)
{
tree thistype;
if (comptypes (vistype, type))
thistype = composite_type (vistype, type);
else
thistype = TREE_TYPE (b_use->decl);
b_use->type = TREE_TYPE (b_use->decl);
if (TREE_CODE (b_use->decl) == FUNCTION_DECL
&& DECL_BUILT_IN (b_use->decl))
thistype
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES
(b_use->type));
TREE_TYPE (b_use->decl) = thistype;
}
return b_use->decl;
}
else
goto skip_external_and_shadow_checks;
}
if (DECL_EXTERNAL (x) || scope == file_scope)
{
tree type = TREE_TYPE (x);
tree vistype = 0;
tree visdecl = 0;
bool type_saved = false;
if (b && !B_IN_EXTERNAL_SCOPE (b)
&& (TREE_CODE (b->decl) == FUNCTION_DECL
|| TREE_CODE (b->decl) == VAR_DECL)
&& DECL_FILE_SCOPE_P (b->decl))
{
visdecl = b->decl;
vistype = TREE_TYPE (visdecl);
}
if (scope != file_scope
&& !DECL_IN_SYSTEM_HEADER (x))
warning (OPT_Wnested_externs, "nested extern declaration of %qD", x);
while (b && !B_IN_EXTERNAL_SCOPE (b))
{
if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved)
{
b->type = TREE_TYPE (b->decl);
type_saved = true;
}
if (B_IN_FILE_SCOPE (b)
&& TREE_CODE (b->decl) == VAR_DECL
&& TREE_STATIC (b->decl)
&& TREE_CODE (TREE_TYPE (b->decl)) == ARRAY_TYPE
&& !TYPE_DOMAIN (TREE_TYPE (b->decl))
&& TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type)
&& TYPE_MAX_VALUE (TYPE_DOMAIN (type))
&& !integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
{
b->inner_comp = true;
}
b = b->shadowed;
}
if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
&& b->type)
TREE_TYPE (b->decl) = b->type;
if (b
&& (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
&& duplicate_decls (x, b->decl))
{
tree thistype;
if (vistype)
{
if (comptypes (vistype, type))
thistype = composite_type (vistype, type);
else
thistype = TREE_TYPE (b->decl);
}
else
thistype = type;
b->type = TREE_TYPE (b->decl);
if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl))
thistype
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES (b->type));
TREE_TYPE (b->decl) = thistype;
bind (name, b->decl, scope, false, true);
return b->decl;
}
else if (TREE_PUBLIC (x))
{
if (visdecl && !b && duplicate_decls (x, visdecl))
{
nested = true;
x = visdecl;
}
else
{
bind (name, x, external_scope, true,
false);
nested = true;
}
}
}
if (TREE_CODE (x) != PARM_DECL)
warn_if_shadowing (x);
skip_external_and_shadow_checks:
if (TREE_CODE (x) == TYPE_DECL)
clone_underlying_type (x);
bind (name, x, scope, false, nested);
if (TREE_TYPE (x) != error_mark_node
&& !COMPLETE_TYPE_P (TREE_TYPE (x)))
{
tree element = TREE_TYPE (x);
while (TREE_CODE (element) == ARRAY_TYPE)
element = TREE_TYPE (element);
element = TYPE_MAIN_VARIANT (element);
if ((TREE_CODE (element) == RECORD_TYPE
|| TREE_CODE (element) == UNION_TYPE)
&& (TREE_CODE (x) != TYPE_DECL
|| TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE)
&& !COMPLETE_TYPE_P (element))
C_TYPE_INCOMPLETE_VARS (element)
= tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element));
}
return x;
}
tree
pushdecl_top_level (tree x)
{
tree name;
bool nested = false;
gcc_assert (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == CONST_DECL);
name = DECL_NAME (x);
gcc_assert (TREE_CODE (x) == CONST_DECL || !I_SYMBOL_BINDING (name));
if (TREE_PUBLIC (x))
{
bind (name, x, external_scope, true, false);
nested = true;
}
if (file_scope)
bind (name, x, file_scope, false, nested);
return x;
}
static void
implicit_decl_warning (tree id, tree olddecl)
{
void (*diag) (const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2);
switch (mesg_implicit_function_declaration)
{
case 0: return;
case 1: diag = warning0; break;
case 2: diag = error; break;
default: gcc_unreachable ();
}
diag (G_("implicit declaration of function %qE"), id);
if (olddecl)
locate_old_decl (olddecl, diag);
}
tree
implicitly_declare (tree functionid)
{
struct c_binding *b;
tree decl = 0;
tree asmspec_tree;
for (b = I_SYMBOL_BINDING (functionid); b; b = b->shadowed)
{
if (B_IN_SCOPE (b, external_scope))
{
decl = b->decl;
break;
}
}
if (decl)
{
if (decl == error_mark_node)
return decl;
if (!DECL_BUILT_IN (decl) && DECL_IS_BUILTIN (decl))
{
bind (functionid, decl, file_scope,
false, true);
return decl;
}
else
{
tree newtype = default_function_type;
if (b->type)
TREE_TYPE (decl) = b->type;
if (!C_DECL_IMPLICIT (decl))
{
implicit_decl_warning (functionid, decl);
C_DECL_IMPLICIT (decl) = 1;
}
if (DECL_BUILT_IN (decl) || disable_typechecking_for_spec_flag)
{
newtype = build_type_attribute_variant (newtype,
TYPE_ATTRIBUTES
(TREE_TYPE (decl)));
if (!comptypes (newtype, TREE_TYPE (decl)))
{
warning (0, "incompatible implicit declaration of built-in"
" function %qD", decl);
newtype = TREE_TYPE (decl);
}
}
else
{
if (!comptypes (newtype, TREE_TYPE (decl)))
{
error ("incompatible implicit declaration of function %qD",
decl);
locate_old_decl (decl, error);
}
}
b->type = TREE_TYPE (decl);
TREE_TYPE (decl) = newtype;
bind (functionid, decl, current_scope,
false, true);
return decl;
}
}
decl = build_decl (FUNCTION_DECL, functionid, default_function_type);
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
C_DECL_IMPLICIT (decl) = 1;
implicit_decl_warning (functionid, 0);
asmspec_tree = maybe_apply_renaming_pragma (decl, NULL);
if (asmspec_tree)
set_user_assembler_name (decl, TREE_STRING_POINTER (asmspec_tree));
decl = pushdecl (decl);
rest_of_decl_compilation (decl, 0, 0);
gen_aux_info_record (decl, 0, 1, 0);
decl_attributes (&decl, NULL_TREE, 0);
return decl;
}
void
undeclared_variable (tree id, location_t loc)
{
static bool already = false;
struct c_scope *scope;
if (current_function_decl == 0)
{
error ("%H%qE undeclared here (not in a function)", &loc, id);
scope = current_scope;
}
else
{
if (!objc_diagnose_private_ivar (id))
error ("%H%qE undeclared (first use in this function)", &loc, id);
if (!already)
{
error ("%H(Each undeclared identifier is reported only once", &loc);
error ("%Hfor each function it appears in.)", &loc);
already = true;
}
scope = current_function_scope ? current_function_scope : current_scope;
}
bind (id, error_mark_node, scope, false, false);
}
static tree
make_label (tree name, location_t location)
{
tree label = build_decl (LABEL_DECL, name, void_type_node);
DECL_CONTEXT (label) = current_function_decl;
DECL_MODE (label) = VOIDmode;
DECL_SOURCE_LOCATION (label) = location;
return label;
}
tree
lookup_label (tree name)
{
tree label;
if (current_function_decl == 0)
{
error ("label %qE referenced outside of any function", name);
return 0;
}
label = I_LABEL_DECL (name);
if (label && (DECL_CONTEXT (label) == current_function_decl
|| C_DECLARED_LABEL_FLAG (label)))
{
if (!TREE_USED (label))
DECL_SOURCE_LOCATION (label) = input_location;
return label;
}
label = make_label (name, input_location);
bind (name, label, current_function_scope,
false, false);
return label;
}
tree
declare_label (tree name)
{
struct c_binding *b = I_LABEL_BINDING (name);
tree label;
if (b && B_IN_CURRENT_SCOPE (b))
{
error ("duplicate label declaration %qE", name);
locate_old_decl (b->decl, error);
return b->decl;
}
label = make_label (name, input_location);
C_DECLARED_LABEL_FLAG (label) = 1;
bind (name, label, current_scope,
false, false);
return label;
}
tree
define_label (location_t location, tree name)
{
tree label = I_LABEL_DECL (name);
struct c_label_list *nlist_se, *nlist_vm;
if (label
&& ((DECL_CONTEXT (label) == current_function_decl
&& DECL_INITIAL (label) != 0)
|| (DECL_CONTEXT (label) != current_function_decl
&& C_DECLARED_LABEL_FLAG (label))))
{
error ("%Hduplicate label %qD", &location, label);
locate_old_decl (label, error);
return 0;
}
else if (label && DECL_CONTEXT (label) == current_function_decl)
{
if (C_DECL_UNDEFINABLE_STMT_EXPR (label))
error ("%Jjump into statement expression", label);
if (C_DECL_UNDEFINABLE_VM (label))
error ("%Jjump into scope of identifier with variably modified type",
label);
DECL_SOURCE_LOCATION (label) = location;
}
else
{
label = make_label (name, location);
bind (name, label, current_function_scope,
false, false);
}
if (!in_system_header && lookup_name (name))
warning (OPT_Wtraditional, "%Htraditional C lacks a separate namespace "
"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;
nlist_se->label = label;
label_context_stack_se->labels_def = nlist_se;
nlist_vm = XOBNEW (&parser_obstack, struct c_label_list);
nlist_vm->next = label_context_stack_vm->labels_def;
nlist_vm->label = label;
label_context_stack_vm->labels_def = nlist_vm;
DECL_INITIAL (label) = error_mark_node;
return label;
}
static tree
lookup_tag (enum tree_code code, tree name, int thislevel_only)
{
struct c_binding *b = I_TAG_BINDING (name);
int thislevel = 0;
if (!b || !b->decl)
return 0;
if (thislevel_only || TREE_CODE (b->decl) != code)
{
if (B_IN_CURRENT_SCOPE (b)
|| (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b)))
thislevel = 1;
}
if (thislevel_only && !thislevel)
return 0;
if (TREE_CODE (b->decl) != code)
{
pending_invalid_xref = name;
pending_invalid_xref_location = input_location;
if (thislevel)
pending_xref_error ();
}
return b->decl;
}
void
pending_xref_error (void)
{
if (pending_invalid_xref != 0)
error ("%H%qE defined as wrong kind of tag",
&pending_invalid_xref_location, pending_invalid_xref);
pending_invalid_xref = 0;
}
tree
lookup_name (tree name)
{
struct c_binding *b = I_SYMBOL_BINDING (name);
if (b && !b->invisible)
return b->decl;
return 0;
}
static tree
lookup_name_in_scope (tree name, struct c_scope *scope)
{
struct c_binding *b;
for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed)
if (B_IN_SCOPE (b, scope))
return b->decl;
return 0;
}
void
c_init_decl_processing (void)
{
location_t save_loc = input_location;
c_parse_init ();
current_function_decl = 0;
gcc_obstack_init (&parser_obstack);
push_scope ();
external_scope = current_scope;
#ifdef USE_MAPPED_LOCATION
input_location = BUILTINS_LOCATION;
#else
input_location.file = "<built-in>";
input_location.line = 0;
#endif
build_common_tree_nodes (flag_signed_char, false);
c_common_nodes_and_builtins ();
truthvalue_type_node = integer_type_node;
truthvalue_true_node = integer_one_node;
truthvalue_false_node = integer_zero_node;
pushdecl (build_decl (TYPE_DECL, get_identifier ("_Bool"),
boolean_type_node));
input_location = save_loc;
pedantic_lvalues = true;
make_fname_decl = c_make_fname_decl;
start_fname_decls ();
}
static tree
c_make_fname_decl (tree id, int type_dep)
{
const char *name = fname_as_string (type_dep);
tree decl, type, init;
size_t length = strlen (name);
type = build_array_type (char_type_node,
build_index_type (size_int (length)));
type = c_build_qualified_type (type, TYPE_QUAL_CONST);
decl = build_decl (VAR_DECL, id, type);
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
init = build_string (length + 1, name);
free ((char *) name);
TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
TREE_USED (decl) = 1;
if (current_function_decl
&& (!errorcount || current_function_scope))
{
DECL_CONTEXT (decl) = current_function_decl;
bind (id, decl, current_function_scope,
false, false);
}
finish_decl (decl, init, NULL_TREE);
return decl;
}
tree
builtin_function (const char *name, tree type, int function_code,
enum built_in_class cl, const char *library_name,
tree attrs)
{
tree id = get_identifier (name);
tree decl = build_decl (FUNCTION_DECL, id, type);
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = 1;
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));
gcc_assert (!I_SYMBOL_BINDING (id));
bind (id, decl, external_scope, true, false);
if ((name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
#ifdef TARGET_POWERPC
|| (cl == BUILT_IN_MD
&& function_code >= ALTIVEC_PIM__FIRST
&& function_code <= ALTIVEC_PIM__LAST)
#endif
)
{
TREE_CHAIN (decl) = visible_builtins;
visible_builtins = decl;
}
if (attrs)
decl_attributes (&decl, attrs, ATTR_FLAG_BUILT_IN);
else
decl_attributes (&decl, NULL_TREE, 0);
return decl;
}
void
shadow_tag (const struct c_declspecs *declspecs)
{
shadow_tag_warned (declspecs, 0);
}
void
shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
{
bool found_tag = false;
if (declspecs->type && !declspecs->default_int_p && !declspecs->typedef_p)
{
tree value = declspecs->type;
enum tree_code code = TREE_CODE (value);
if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
{
tree name = TYPE_NAME (value);
tree t;
found_tag = true;
if (name == 0)
{
if (warned != 1 && code != ENUMERAL_TYPE)
{
pedwarn ("unnamed struct/union that defines no instances");
warned = 1;
}
}
else if (!declspecs->tag_defined_p
&& declspecs->storage_class != csc_none)
{
if (warned != 1)
pedwarn ("empty declaration with storage class specifier "
"does not redeclare tag");
warned = 1;
pending_xref_error ();
}
else if (!declspecs->tag_defined_p
&& (declspecs->const_p
|| declspecs->volatile_p
|| declspecs->restrict_p))
{
if (warned != 1)
pedwarn ("empty declaration with type qualifier "
"does not redeclare tag");
warned = 1;
pending_xref_error ();
}
else
{
pending_invalid_xref = 0;
t = lookup_tag (code, name, 1);
if (t == 0)
{
t = make_node (code);
pushtag (name, t);
}
}
}
else
{
if (warned != 1 && !in_system_header)
{
pedwarn ("useless type name in empty declaration");
warned = 1;
}
}
}
else if (warned != 1 && !in_system_header && declspecs->typedef_p)
{
pedwarn ("useless type name in empty declaration");
warned = 1;
}
pending_invalid_xref = 0;
if (declspecs->inline_p)
{
error ("%<inline%> in empty declaration");
warned = 1;
}
if (current_scope == file_scope && declspecs->storage_class == csc_auto)
{
error ("%<auto%> in file-scope empty declaration");
warned = 1;
}
if (current_scope == file_scope && declspecs->storage_class == csc_register)
{
error ("%<register%> in file-scope empty declaration");
warned = 1;
}
if (!warned && !in_system_header && declspecs->storage_class != csc_none)
{
warning (0, "useless storage class specifier in empty declaration");
warned = 2;
}
if (!warned && !in_system_header && declspecs->thread_p)
{
warning (0, "useless %<__thread%> in empty declaration");
warned = 2;
}
if (!warned && !in_system_header && (declspecs->const_p
|| declspecs->volatile_p
|| declspecs->restrict_p))
{
warning (0, "useless type qualifier in empty declaration");
warned = 2;
}
if (warned != 1)
{
if (!found_tag)
pedwarn ("empty declaration");
}
}
int
quals_from_declspecs (const struct c_declspecs *specs)
{
int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0)
| (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
| (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0));
gcc_assert (!specs->type
&& !specs->decl_attr
&& specs->typespec_word == cts_none
&& specs->storage_class == csc_none
&& !specs->typedef_p
&& !specs->explicit_signed_p
&& !specs->deprecated_p
&& !specs->long_p
&& !specs->long_long_p
&& !specs->short_p
&& !specs->signed_p
&& !specs->unsigned_p
&& !specs->complex_p
&& !specs->inline_p
&& !specs->thread_p);
return quals;
}
struct c_declarator *
build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p,
bool vla_unspec_p)
{
struct c_declarator *declarator = XOBNEW (&parser_obstack,
struct c_declarator);
declarator->kind = cdk_array;
declarator->declarator = 0;
declarator->u.array.dimen = expr;
if (quals)
{
declarator->u.array.attrs = quals->attrs;
declarator->u.array.quals = quals_from_declspecs (quals);
}
else
{
declarator->u.array.attrs = NULL_TREE;
declarator->u.array.quals = 0;
}
declarator->u.array.static_p = static_p;
declarator->u.array.vla_unspec_p = vla_unspec_p;
if (pedantic && !flag_isoc99)
{
if (static_p || quals != NULL)
pedwarn ("ISO C90 does not support %<static%> or type "
"qualifiers in parameter array declarators");
if (vla_unspec_p)
pedwarn ("ISO C90 does not support %<[*]%> array declarators");
}
if (vla_unspec_p)
{
if (!current_scope->parm_flag)
{
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;
}
struct c_declarator *
set_array_declarator_inner (struct c_declarator *decl,
struct c_declarator *inner, bool abstract_p)
{
#if 0
if (decl == 0)
return decl;
#endif
decl->declarator = inner;
if (abstract_p && (decl->u.array.quals != TYPE_UNQUALIFIED
|| decl->u.array.attrs != NULL_TREE
|| decl->u.array.static_p))
error ("static or type qualifiers in abstract declarator");
return decl;
}
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));
}
}
tree
grokblockdecl (struct c_declspecs *specs, struct c_declarator *declarator)
{
tree decl;
tree attrs = specs->attrs;
specs->attrs = NULL_TREE;
decl = grokdeclarator (declarator, specs, BLOCKDEF,
false, NULL);
decl_attributes (&decl, attrs, 0);
return decl;
}
tree
groktypename (struct c_type_name *type_name)
{
tree type;
tree attrs = type_name->specs->attrs;
type_name->specs->attrs = NULL_TREE;
type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME,
false, NULL);
decl_attributes (&type, attrs, 0);
return type;
}
tree
start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
bool initialized, tree attributes)
{
tree decl;
tree tem;
#ifdef A_LESS_INEFFICENT_WAY
if (lookup_attribute ("deprecated", attributes))
deprecated_state = DEPRECATED_SUPPRESS;
else if (lookup_attribute ("unavailable", attributes))
deprecated_state = DEPRECATED_UNAVAILABLE_SUPPRESS;
#else
tree a;
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a);
if (TREE_CODE (name) == IDENTIFIER_NODE)
if (is_attribute_p ("deprecated", name))
{
deprecated_state = DEPRECATED_SUPPRESS;
break;
}
if (is_attribute_p ("unavailable", name))
{
deprecated_state = DEPRECATED_UNAVAILABLE_SUPPRESS;
break;
}
}
#endif
decl = grokdeclarator (declarator, declspecs,
NORMAL, initialized, NULL);
if (!decl)
return 0;
deprecated_state = DEPRECATED_NORMAL;
if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL
&& MAIN_NAME_P (DECL_NAME (decl)))
warning (OPT_Wmain, "%q+D is usually a function", decl);
if (initialized)
switch (TREE_CODE (decl))
{
case TYPE_DECL:
error ("typedef %qD is initialized (use __typeof__ instead)", decl);
initialized = 0;
break;
case FUNCTION_DECL:
error ("function %qD is initialized like a variable", decl);
initialized = 0;
break;
case PARM_DECL:
error ("parameter %qD is initialized", decl);
initialized = 0;
break;
default:
if (TREE_TYPE (decl) == error_mark_node)
initialized = 0;
else if (COMPLETE_TYPE_P (TREE_TYPE (decl)))
{
if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
|| C_DECL_VARIABLE_SIZE (decl))
{
error ("variable-sized object may not be initialized");
initialized = 0;
}
}
else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
{
error ("variable %qD has initializer but incomplete type", decl);
initialized = 0;
}
else if (C_DECL_VARIABLE_SIZE (decl))
{
error ("variable-sized object may not be initialized");
initialized = 0;
}
}
if (initialized)
{
if (current_scope == file_scope)
TREE_STATIC (decl) = 1;
DECL_INITIAL (decl) = error_mark_node;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0);
if (TREE_CODE (decl) == VAR_DECL
&& !initialized
&& TREE_PUBLIC (decl)
&& !DECL_THREAD_LOCAL_P (decl)
&& !flag_no_common)
DECL_COMMON (decl) = 1;
decl_attributes (&decl, attributes, 0);
if (c_dialect_objc ())
objc_checkon_weak_attribute (decl);
if (declspecs->inline_p
&& !flag_gnu89_inline
&& 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);
}
if (TREE_CODE (decl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (decl)))
{
struct c_declarator *ce = declarator;
if (ce->kind == cdk_pointer)
ce = declarator->declarator;
if (ce->kind == cdk_function)
{
tree args = ce->u.arg_info->parms;
for (; args; args = TREE_CHAIN (args))
{
tree type = TREE_TYPE (args);
if (type && INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
DECL_ARG_TYPE (args) = integer_type_node;
}
}
}
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)
&& DECL_UNINLINABLE (decl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (decl)))
warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
decl);
if (c_dialect_objc ()
&& (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL))
objc_check_global_decl (decl);
if (TREE_CODE (decl) == VAR_DECL
&& current_scope != file_scope
&& TREE_STATIC (decl)
&& !TREE_READONLY (decl)
&& DECL_DECLARED_INLINE_P (current_function_decl)
&& DECL_EXTERNAL (current_function_decl))
pedwarn ("%J%qD is static but declared in inline function %qD "
"which is not static", decl, decl, current_function_decl);
tem = pushdecl (decl);
if (initialized && DECL_EXTERNAL (tem))
{
DECL_EXTERNAL (tem) = 0;
TREE_STATIC (tem) = 1;
}
return tem;
}
void
c_maybe_initialize_eh (void)
{
if (!flag_exceptions || c_eh_initialized_p)
return;
c_eh_initialized_p = true;
#ifdef ENABLE_LLVM
llvm_eh_personality_libfunc
= llvm_init_one_libfunc (USING_SJLJ_EXCEPTIONS
? "__gcc_personality_sj0"
: "__gcc_personality_v0");
#else
eh_personality_libfunc
= init_one_libfunc (USING_SJLJ_EXCEPTIONS
? "__gcc_personality_sj0"
: "__gcc_personality_v0");
#endif
default_init_unwind_resume_libfunc ();
using_eh_for_cleanups ();
}
#define BLOCK_ALIGN_MAX 18
static tree block_byref_id_object_copy[BLOCK_BYREF_CURRENT_MAX*(BLOCK_ALIGN_MAX+1)];
static tree block_byref_id_object_dispose[BLOCK_BYREF_CURRENT_MAX*(BLOCK_ALIGN_MAX+1)];
static void
synth_block_byref_id_object_copy_func (int flag, int kind)
{
tree stmt, fnbody;
tree dst_arg, src_arg;
tree dst_obj, src_obj;
struct c_arg_info * arg_info;
tree call_exp;
gcc_assert (block_byref_id_object_copy[kind]);
dst_arg = build_decl (PARM_DECL, get_identifier ("_dst"),
ptr_type_node);
TREE_USED (dst_arg) = 1;
DECL_ARG_TYPE (dst_arg) = ptr_type_node;
src_arg = build_decl (PARM_DECL, get_identifier ("_src"),
ptr_type_node);
TREE_USED (src_arg) = 1;
DECL_ARG_TYPE (src_arg) = ptr_type_node;
arg_info = xcalloc (1, sizeof (struct c_arg_info));
TREE_CHAIN (dst_arg) = src_arg;
arg_info->parms = dst_arg;
arg_info->types = tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE,
ptr_type_node,
NULL_TREE));
push_function_context ();
start_block_helper_function (block_byref_id_object_copy[kind]);
store_parm_decls_from (arg_info);
stmt = c_begin_compound_stmt (true);
dst_obj = build_indirect_object_id_exp (dst_arg);
src_obj = build_indirect_object_id_exp (src_arg);
flag |= BLOCK_BYREF_CALLER;
call_exp = build_block_object_assign_call_exp (build_fold_addr_expr (dst_obj), src_obj, flag);
add_stmt (call_exp);
fnbody = c_end_compound_stmt (stmt, true);
add_stmt (fnbody);
finish_function ();
pop_function_context ();
free (arg_info);
}
static void
synth_block_byref_id_object_dispose_func (int flag, int kind)
{
tree stmt, fnbody;
tree src_arg, src_obj, rel_exp;
struct c_arg_info * arg_info;
gcc_assert (block_byref_id_object_dispose[kind]);
src_arg = build_decl (PARM_DECL, get_identifier ("_src"),
ptr_type_node);
TREE_USED (src_arg) = 1;
DECL_ARG_TYPE (src_arg) = ptr_type_node;
arg_info = xcalloc (1, sizeof (struct c_arg_info));
arg_info->parms = src_arg;
arg_info->types = tree_cons (NULL_TREE, ptr_type_node,
NULL_TREE);
push_function_context ();
start_block_helper_function (block_byref_id_object_dispose[kind]);
store_parm_decls_from (arg_info);
stmt = c_begin_compound_stmt (true);
src_obj = build_indirect_object_id_exp (src_arg);
flag |= BLOCK_BYREF_CALLER;
rel_exp = build_block_object_dispose_call_exp (src_obj, flag);
add_stmt (rel_exp);
fnbody = c_end_compound_stmt (stmt, true);
add_stmt (fnbody);
finish_function ();
pop_function_context ();
free (arg_info);
}
static tree
new_block_byref_decl (tree decl)
{
static int unique_count;
int save_flag_objc_gc;
tree Block_byref_type;
tree field_decl_chain, field_decl;
const char *prefix = "__Block_byref_";
char *string = alloca (strlen (IDENTIFIER_POINTER (DECL_NAME (decl))) +
strlen (prefix) + 8 );
sprintf (string, "%s%d_%s", prefix, ++unique_count,
IDENTIFIER_POINTER (DECL_NAME (decl)));
push_to_top_level ();
Block_byref_type = start_struct (RECORD_TYPE, get_identifier (string));
field_decl = build_decl (FIELD_DECL, get_identifier ("__isa"), ptr_type_node);
field_decl_chain = field_decl;
field_decl = build_decl (FIELD_DECL, get_identifier ("__forwarding"),
build_pointer_type (Block_byref_type));
chainon (field_decl_chain, field_decl);
field_decl = build_decl (FIELD_DECL, get_identifier ("__flags"),
unsigned_type_node);
chainon (field_decl_chain, field_decl);
field_decl = build_decl (FIELD_DECL, get_identifier ("__size"),
unsigned_type_node);
chainon (field_decl_chain, field_decl);
if (COPYABLE_BYREF_LOCAL_NONPOD (decl))
{
field_decl = build_decl (FIELD_DECL, get_identifier ("__ByrefKeepFuncPtr"),
ptr_type_node);
chainon (field_decl_chain, field_decl);
field_decl = build_decl (FIELD_DECL, get_identifier ("__ByrefDestroyFuncPtr"),
ptr_type_node);
chainon (field_decl_chain, field_decl);
}
field_decl = build_decl (FIELD_DECL, DECL_NAME (decl), TREE_TYPE (decl));
chainon (field_decl_chain, field_decl);
pop_from_top_level ();
save_flag_objc_gc = flag_objc_gc;
flag_objc_gc = 0;
finish_struct (Block_byref_type, field_decl_chain, NULL_TREE);
flag_objc_gc = save_flag_objc_gc;
TREE_TYPE (decl) = Block_byref_type;
DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
layout_decl (decl, 0);
return decl;
}
static tree
init_byref_decl (tree decl, tree init, int flag)
{
tree initlist;
tree block_byref_type = TREE_TYPE (decl);
int size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (block_byref_type));
unsigned flags = 0;
tree fields;
if (COPYABLE_BYREF_LOCAL_NONPOD (decl))
flags = BLOCK_HAS_COPY_DISPOSE;
fields = TYPE_FIELDS (block_byref_type);
initlist = tree_cons (fields, fold_convert (ptr_type_node, ((flag & BLOCK_FIELD_IS_WEAK) != 0) ? integer_one_node
: integer_zero_node), 0);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields,
build_unary_op (ADDR_EXPR, decl, 0), initlist);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields, build_int_cst (TREE_TYPE (fields), flags),
initlist);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields, build_int_cst (TREE_TYPE (fields), size),
initlist);
fields = TREE_CHAIN (fields);
if (COPYABLE_BYREF_LOCAL_NONPOD (decl))
{
char name[64];
int align = exact_log2 ((DECL_ALIGN (decl)+TYPE_ALIGN (ptr_type_node)-1) / TYPE_ALIGN (ptr_type_node));
int kind;
if (align == -1 || align > BLOCK_ALIGN_MAX) {
error ("invalid alignment for __block variable");
kind = 0;
} else
kind = align*BLOCK_BYREF_CURRENT_MAX + flag;
if (!block_byref_id_object_copy[kind])
{
tree func_type =
build_function_type (void_type_node,
tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node,
void_list_node)));
sprintf (name, "__Block_byref_id_object_copy%d", kind);
block_byref_id_object_copy[kind] = build_helper_func_decl (get_identifier (name),
func_type);
synth_block_byref_id_object_copy_func (flag, kind);
}
initlist = tree_cons (fields,
build_fold_addr_expr (block_byref_id_object_copy[kind]),
initlist);
fields = TREE_CHAIN (fields);
if (!block_byref_id_object_dispose[kind])
{
tree func_type =
build_function_type (void_type_node,
tree_cons (NULL_TREE, ptr_type_node, void_list_node));
sprintf (name, "__Block_byref_id_object_dispose%d", kind);
block_byref_id_object_dispose[kind] = build_helper_func_decl (get_identifier (name),
func_type);
synth_block_byref_id_object_dispose_func (flag, kind);
}
initlist = tree_cons (fields,
build_fold_addr_expr (block_byref_id_object_dispose[kind]),
initlist);
fields = TREE_CHAIN (fields);
}
if (init)
{
init = do_digest_init (TREE_TYPE (fields), init);
initlist = tree_cons (fields, init, initlist);
}
init = build_constructor_from_list (block_byref_type, nreverse (initlist));
return init;
}
void
finish_decl (tree decl, tree init, tree asmspec_tree)
{
tree type;
int was_incomplete = (DECL_SIZE (decl) == 0);
const char *asmspec = 0;
if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
&& DECL_FILE_SCOPE_P (decl))
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
if (asmspec_tree)
asmspec = TREE_STRING_POINTER (asmspec_tree);
if (init != 0 && DECL_INITIAL (decl) == 0)
init = 0;
if (TREE_CODE (decl) == PARM_DECL)
init = 0;
else if (TREE_CODE (decl) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (decl))
{
if (DECL_EXTERNAL (decl) || TREE_STATIC (decl))
{
error ("__block attribute on %q+D not allowed, only allowed on local variables", decl);
COPYABLE_BYREF_LOCAL_VAR (decl) = 0;
COPYABLE_BYREF_LOCAL_NONPOD (decl) = 0;
}
else
{
int flag = 0;
if (objc_is_gcable_type (TREE_TYPE (decl)) == -1)
flag = BLOCK_FIELD_IS_WEAK;
if (block_requires_copying (decl))
{
if (TREE_CODE (TREE_TYPE (decl)) == BLOCK_POINTER_TYPE)
flag |= BLOCK_FIELD_IS_BLOCK;
else
flag |= BLOCK_FIELD_IS_OBJECT;
}
decl = new_block_byref_decl (decl);
if (! flag_objc_gc_only)
{
push_cleanup (decl, build_block_byref_release_exp (decl), false);
}
COPYABLE_WEAK_BLOCK (decl) = ((flag & BLOCK_FIELD_IS_WEAK) != 0);
init = init_byref_decl (decl, init, flag);
}
}
if (init)
store_init_value (decl, init);
if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == FIELD_DECL))
objc_check_decl (decl);
type = TREE_TYPE (decl);
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) == 0
&& TREE_CODE (decl) != TYPE_DECL)
{
bool do_default
= (TREE_STATIC (decl)
? pedantic && !TREE_PUBLIC (decl)
: !DECL_EXTERNAL (decl));
int failure
= complete_array_type (&TREE_TYPE (decl), DECL_INITIAL (decl),
do_default);
type = TREE_TYPE (decl);
switch (failure)
{
case 1:
error ("initializer fails to determine size of %q+D", decl);
break;
case 2:
if (do_default)
error ("array size missing in %q+D", decl);
else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
DECL_EXTERNAL (decl) = 1;
break;
case 3:
error ("zero or negative size array %q+D", decl);
break;
case 0:
if (TREE_PUBLIC (decl))
{
struct c_binding *b_ext = I_SYMBOL_BINDING (DECL_NAME (decl));
while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext))
b_ext = b_ext->shadowed;
if (b_ext)
{
if (b_ext->type)
b_ext->type = composite_type (b_ext->type, type);
else
b_ext->type = type;
}
}
break;
default:
gcc_unreachable ();
}
if (DECL_INITIAL (decl))
TREE_TYPE (DECL_INITIAL (decl)) = type;
layout_decl (decl, 0);
}
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 (DECL_SIZE (decl) == 0
&& TREE_TYPE (decl) != error_mark_node
&& (TREE_STATIC (decl)
? (DECL_INITIAL (decl) != 0
|| !DECL_FILE_SCOPE_P (decl))
: !DECL_EXTERNAL (decl)))
{
error ("storage size of %q+D isn%'t known", decl);
TREE_TYPE (decl) = error_mark_node;
}
if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
&& DECL_SIZE (decl) != 0)
{
if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
constant_expression_warning (DECL_SIZE (decl));
else
error ("storage size of %q+D isn%'t constant", decl);
}
if (TREE_USED (type))
TREE_USED (decl) = 1;
}
if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
{
if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
set_builtin_user_assembler_name (decl, asmspec);
set_user_assembler_name (decl, asmspec);
}
maybe_apply_pragma_weak (decl);
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
{
if (TREE_PUBLIC (decl))
c_determine_visibility (decl);
if (c_dialect_objc ())
objc_check_decl (decl);
if (asmspec)
{
if (!DECL_FILE_SCOPE_P (decl)
&& TREE_CODE (decl) == VAR_DECL
&& !C_DECL_REGISTER (decl)
&& !TREE_STATIC (decl))
warning (0, "ignoring asm-specifier for non-static local "
"variable %q+D", decl);
else
set_user_assembler_name (decl, asmspec);
}
if (DECL_FILE_SCOPE_P (decl))
{
if (DECL_INITIAL (decl) == NULL_TREE
|| DECL_INITIAL (decl) == error_mark_node)
DECL_DEFER_OUTPUT (decl) = 1;
rest_of_decl_compilation (decl, true, 0);
}
else
{
if (asmspec && C_DECL_REGISTER (decl))
{
DECL_HARD_REGISTER (decl) = 1;
if (!DECL_REGISTER (decl))
error ("cannot put object with volatile field into register");
}
if (TREE_CODE (decl) != FUNCTION_DECL)
{
if (DECL_SIZE (decl)
&& !TREE_CONSTANT (DECL_SIZE (decl))
&& STATEMENT_LIST_HAS_LABEL (cur_stmt_list))
{
tree bind;
bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
add_stmt (bind);
BIND_EXPR_BODY (bind) = push_stmt_list ();
}
add_stmt (build_stmt (DECL_EXPR, decl));
}
}
if (!DECL_FILE_SCOPE_P (decl))
{
if (was_incomplete
&& !TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
{
TREE_ADDRESSABLE (decl) = TREE_USED (decl);
if (DECL_SIZE (decl) == 0)
DECL_INITIAL (decl) = 0;
}
}
}
if (!flag_unit_at_a_time && lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
mark_decl_referenced (decl);
if (TREE_CODE (decl) == TYPE_DECL)
{
if (!DECL_FILE_SCOPE_P (decl)
&& variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
add_stmt (build_stmt (DECL_EXPR, decl));
rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
}
if (current_scope == file_scope)
get_pending_sizes ();
if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
{
tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl));
if (attr)
{
tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
tree cleanup_decl = lookup_name (cleanup_id);
tree cleanup;
cleanup = build_unary_op (ADDR_EXPR, decl, 0);
cleanup = build_tree_list (NULL_TREE, cleanup);
cleanup = build_function_call (cleanup_decl, cleanup);
TREE_USED (decl) = 1;
TREE_USED (cleanup_decl) = 1;
c_maybe_initialize_eh ();
push_cleanup (decl, cleanup, false);
}
}
}
tree
grokparm (const struct c_parm *parm)
{
tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
NULL);
decl_attributes (&decl, parm->attrs, 0);
return decl;
}
void
push_parm_decl (const struct c_parm *parm)
{
tree decl;
decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL);
decl_attributes (&decl, parm->attrs, 0);
decl = pushdecl (decl);
finish_decl (decl, NULL_TREE, NULL_TREE);
}
void
mark_forward_parm_decls (void)
{
struct c_binding *b;
if (pedantic && !current_scope->warned_forward_parm_decls)
{
pedwarn ("ISO C forbids forward parameter declarations");
current_scope->warned_forward_parm_decls = true;
}
for (b = current_scope->bindings; b; b = b->prev)
if (TREE_CODE (b->decl) == PARM_DECL)
TREE_ASM_WRITTEN (b->decl) = 1;
}
tree
build_compound_literal (tree type, tree init)
{
tree decl;
tree complit;
tree stmt;
if (type == error_mark_node)
return error_mark_node;
decl = build_decl (VAR_DECL, NULL_TREE, type);
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = 0;
TREE_STATIC (decl) = (current_scope == file_scope);
DECL_CONTEXT (decl) = current_function_decl;
TREE_USED (decl) = 1;
TREE_TYPE (decl) = type;
TREE_READONLY (decl) = TYPE_READONLY (type);
store_init_value (decl, init);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
{
int failure = complete_array_type (&TREE_TYPE (decl),
DECL_INITIAL (decl), true);
gcc_assert (!failure);
type = TREE_TYPE (decl);
TREE_TYPE (DECL_INITIAL (decl)) = type;
}
if (type == error_mark_node || !COMPLETE_TYPE_P (type))
return error_mark_node;
stmt = build_stmt (DECL_EXPR, decl);
complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt);
TREE_SIDE_EFFECTS (complit) = 1;
layout_decl (decl, 0);
if (TREE_STATIC (decl))
{
set_compound_literal_name (decl);
#ifndef ENABLE_LLVM
DECL_DEFER_OUTPUT (decl) = 1;
#endif
DECL_COMDAT (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
pushdecl (decl);
rest_of_decl_compilation (decl, 1, 0);
}
return complit;
}
static bool
flexible_array_type_p (tree type)
{
tree x;
switch (TREE_CODE (type))
{
case RECORD_TYPE:
x = TYPE_FIELDS (type);
if (x == NULL_TREE)
return false;
while (TREE_CHAIN (x) != NULL_TREE)
x = TREE_CHAIN (x);
if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
&& TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
&& TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
&& TYPE_MAX_VALUE (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))
{
if (flexible_array_type_p (TREE_TYPE (x)))
return true;
}
return false;
default:
return false;
}
}
static void
check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
{
tree type_mv;
unsigned int max_width;
unsigned HOST_WIDE_INT w;
const char *name = orig_name ? orig_name: _("<anonymous>");
if (!INTEGRAL_TYPE_P (TREE_TYPE (*width))
|| TREE_CODE (*width) != INTEGER_CST)
{
error ("bit-field %qs width not an integer constant", name);
*width = integer_one_node;
}
else
{
constant_expression_warning (*width);
if (tree_int_cst_sgn (*width) < 0)
{
error ("negative width in bit-field %qs", name);
*width = integer_one_node;
}
else if (integer_zerop (*width) && orig_name)
{
error ("zero width for bit-field %qs", name);
*width = integer_one_node;
}
}
if (TREE_CODE (*type) != INTEGER_TYPE
&& TREE_CODE (*type) != BOOLEAN_TYPE
&& TREE_CODE (*type) != ENUMERAL_TYPE)
{
error ("bit-field %qs has invalid type", name);
*type = unsigned_type_node;
}
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)
pedwarn ("type of bit-field %qs is a GCC extension", name);
if (type_mv == boolean_type_node)
max_width = CHAR_TYPE_SIZE;
else
max_width = TYPE_PRECISION (*type);
if (0 < compare_tree_int (*width, max_width))
{
error ("width of %qs exceeds its type", name);
w = max_width;
*width = build_int_cst (NULL_TREE, w);
}
else
w = tree_low_cst (*width, 1);
if (TREE_CODE (*type) == ENUMERAL_TYPE)
{
struct lang_type *lt = TYPE_LANG_SPECIFIC (*type);
if (!lt
|| 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);
}
}
static tree
grokdeclarator (const struct c_declarator *declarator,
struct c_declspecs *declspecs,
enum decl_context decl_context, bool initialized, tree *width)
{
tree type = declspecs->type;
bool threadp = declspecs->thread_p;
enum c_storage_class storage_class = declspecs->storage_class;
int constp;
int restrictp;
int volatilep;
int type_quals = TYPE_UNQUALIFIED;
const char *name, *orig_name;
tree typedef_type = 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 = true, decl_context = NORMAL;
{
const struct c_declarator *decl = declarator;
name = 0;
while (decl)
switch (decl->kind)
{
case cdk_function:
case cdk_array:
case cdk_pointer:
case cdk_block_pointer:
funcdef_syntax = (decl->kind == cdk_function);
decl = decl->declarator;
break;
case cdk_attrs:
decl = decl->declarator;
break;
case cdk_id:
if (decl->u.id)
name = IDENTIFIER_POINTER (decl->u.id);
decl = 0;
break;
default:
gcc_unreachable ();
}
orig_name = name;
if (name == 0)
name = "type name";
}
if (funcdef_flag && !funcdef_syntax)
return 0;
#if 0
if (! declarator)
return 0;
#endif
if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag)
decl_context = PARM;
if (declspecs->unavailable_p)
error_unavailable_use (declspecs->type);
else
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);
if (declspecs->default_int_p && !in_system_header)
{
if ((warn_implicit_int || warn_return_type || flag_isoc99)
&& funcdef_flag)
warn_about_return_type = 1;
else if (warn_implicit_int || flag_isoc99)
pedwarn_c99 ("type defaults to %<int%> in declaration of %qs", name);
}
if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p
&& TREE_CODE (type) == INTEGER_TYPE)
type = c_common_unsigned_type (type);
element_type = strip_array_types (type);
constp = declspecs->const_p + TYPE_READONLY (element_type);
restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type);
volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type);
if (pedantic && !flag_isoc99)
{
if (constp > 1)
pedwarn ("duplicate %<const%>");
if (restrictp > 1)
pedwarn ("duplicate %<restrict%>");
if (volatilep > 1)
pedwarn ("duplicate %<volatile%>");
}
if (!flag_gen_aux_info && (TYPE_QUALS (element_type)))
type = TYPE_MAIN_VARIANT (type);
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 0));
if (funcdef_flag
&& (threadp
|| storage_class == csc_auto
|| storage_class == csc_register
|| storage_class == csc_typedef))
{
if (storage_class == csc_auto
&& (pedantic || current_scope == file_scope))
pedwarn ("function definition declared %<auto%>");
if (storage_class == csc_register)
error ("function definition declared %<register%>");
if (storage_class == csc_typedef)
error ("function definition declared %<typedef%>");
if (threadp)
error ("function definition declared %<__thread%>");
threadp = false;
if (storage_class == csc_auto
|| storage_class == csc_register
|| storage_class == csc_typedef)
storage_class = csc_none;
}
else if (decl_context != NORMAL && (storage_class != csc_none || threadp))
{
if (decl_context == PARM && storage_class == csc_register)
;
else
{
switch (decl_context)
{
case FIELD:
error ("storage class specified for structure field %qs",
name);
break;
case PARM:
error ("storage class specified for parameter %qs", name);
break;
default:
error ("storage class specified for typename");
break;
}
storage_class = csc_none;
threadp = false;
}
}
else if (storage_class == csc_extern
&& initialized
&& !declspecs->private_extern_p
&& !funcdef_flag)
{
if (current_scope == file_scope)
{
if (!(warn_cxx_compat && constp))
warning (0, "%qs initialized and declared %<extern%>", name);
}
else
error ("%qs has both %<extern%> and initializer", name);
}
else if (current_scope == file_scope)
{
if (storage_class == csc_auto)
error ("file-scope declaration of %qs specifies %<auto%>", name);
if (pedantic && storage_class == csc_register)
pedwarn ("file-scope declaration of %qs specifies %<register%>", name);
}
else
{
if (storage_class == csc_extern && funcdef_flag)
error ("nested function %qs declared %<extern%>", name);
else if (threadp && storage_class == csc_none)
{
error ("function-scope %qs implicitly auto and declared "
"%<__thread%>",
name);
threadp = false;
}
}
while (declarator && declarator->kind != cdk_id)
{
if (type == error_mark_node)
{
declarator = declarator->declarator;
continue;
}
if (array_ptr_quals != TYPE_UNQUALIFIED
|| array_ptr_attrs != NULL_TREE
|| array_parm_static)
{
error ("static or type qualifiers in non-parameter array declarator");
array_ptr_quals = TYPE_UNQUALIFIED;
array_ptr_attrs = NULL_TREE;
array_parm_static = 0;
}
switch (declarator->kind)
{
case cdk_attrs:
{
tree attrs = declarator->u.attrs;
const struct c_declarator *inner_decl;
int attr_flags = 0;
declarator = declarator->declarator;
inner_decl = declarator;
while (inner_decl->kind == cdk_attrs)
inner_decl = inner_decl->declarator;
if (inner_decl->kind == cdk_id)
attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
else if (inner_decl->kind == cdk_function)
attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
else if (inner_decl->kind == cdk_array)
attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
returned_attrs = decl_attributes (&type,
chainon (returned_attrs, attrs),
attr_flags);
break;
}
case cdk_array:
{
tree itype = NULL_TREE;
tree size = declarator->u.array.dimen;
tree index_type = c_common_signed_type (sizetype);
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;
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;
if (size)
{
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);
if (tree_int_cst_sgn (size) < 0)
{
error ("size of array %qs is negative", name);
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
{
size_varies = 1;
if (!flag_isoc99 && pedantic)
{
if (TREE_CONSTANT (size))
pedwarn ("ISO C90 forbids array %qs whose size "
"can%'t be evaluated",
name);
else
pedwarn ("ISO C90 forbids variable-size array %qs",
name);
}
}
if (integer_zerop (size))
{
itype = build_range_type (sizetype, size, NULL_TREE);
}
else
{
if (size_varies)
size = variable_size (size);
itype = fold_build2 (MINUS_EXPR, index_type,
convert (index_type, size),
convert (index_type,
size_one_node));
if (TREE_CODE (itype) == INTEGER_CST
&& TREE_OVERFLOW (itype))
{
error ("size of array %qs is too large", name);
type = error_mark_node;
continue;
}
itype = build_index_type (itype);
}
}
else if (decl_context == FIELD)
{
if (pedantic && !flag_isoc99 && !in_system_header)
pedwarn ("ISO C90 does not support flexible array members");
itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
}
else if (decl_context == PARM)
{
if (array_parm_vla_unspec_p)
{
if (! orig_name)
{
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)
{
itype = build_range_type (sizetype, size_zero_node,
NULL_TREE);
}
}
if (!COMPLETE_TYPE_P (type))
{
error ("array type has incomplete element type");
type = error_mark_node;
}
else
type = build_array_type (type, itype);
if (type != error_mark_node)
{
if (size_varies)
{
if (size && TREE_CODE (size) == INTEGER_CST)
type
= build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
C_TYPE_VARIABLE_SIZE (type) = 1;
}
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);
TYPE_SIZE (type) = bitsize_zero_node;
TYPE_SIZE_UNIT (type) = size_zero_node;
}
}
if (decl_context != PARM
&& (array_ptr_quals != TYPE_UNQUALIFIED
|| array_ptr_attrs != NULL_TREE
|| array_parm_static))
{
error ("static or type qualifiers in non-parameter array declarator");
array_ptr_quals = TYPE_UNQUALIFIED;
array_ptr_attrs = NULL_TREE;
array_parm_static = 0;
}
break;
}
case cdk_function:
{
bool really_funcdef = false;
tree arg_types;
if (funcdef_flag)
{
const struct c_declarator *t = declarator->declarator;
while (t->kind == cdk_attrs)
t = t->declarator;
really_funcdef = (t->kind == cdk_id);
}
if (type == error_mark_node)
continue;
size_varies = 0;
if (TREE_CODE (type) == FUNCTION_TYPE)
{
error ("%qs declared as function returning a function", name);
type = integer_type_node;
}
if (TREE_CODE (type) == ARRAY_TYPE)
{
error ("%qs declared as function returning an array", name);
type = integer_type_node;
}
arg_info = declarator->u.arg_info;
arg_types = grokparms (arg_info, really_funcdef);
if (really_funcdef)
put_pending_sizes (arg_info->pending_sizes);
if (type_quals)
{
if (VOID_TYPE_P (type) && really_funcdef)
pedwarn ("function definition has qualified void return type");
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;
{
tree link;
for (link = arg_info->tags;
link;
link = TREE_CHAIN (link))
TYPE_CONTEXT (TREE_VALUE (link)) = type;
}
break;
}
case cdk_pointer:
{
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
pedwarn ("ISO C forbids qualified function types");
if (type_quals)
type = c_build_qualified_type (type, type_quals);
size_varies = 0;
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);
type_quals = declarator->u.pointer_quals;
declarator = declarator->declarator;
break;
}
case cdk_block_pointer:
{
if (TREE_CODE (type) != FUNCTION_TYPE)
{
error ("block pointer to non-function type is invalid");
type = error_mark_node;
}
else
{
type = build_block_pointer_type (type);
type_quals = declarator->u.pointer_quals;
declarator = declarator->declarator;
}
break;
}
default:
gcc_unreachable ();
}
}
if (bitfield)
check_bitfield_type_and_width (&type, width, orig_name);
if (TREE_CODE (type) == ARRAY_TYPE
&& COMPLETE_TYPE_P (type)
&& TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
&& TREE_OVERFLOW (TYPE_SIZE_UNIT (type)))
{
error ("size of array %qs is too large", name);
type = error_mark_node;
}
if (decl_context == BLOCKDEF)
{
tree decl;
if (type == error_mark_node)
return error_mark_node;
if (TREE_CODE (type) != FUNCTION_TYPE)
{
tree arg_types;
if (TREE_CODE (type) == ARRAY_TYPE)
{
error ("block declared as returning an array");
return error_mark_node;
}
arg_info = XOBNEW (&parser_obstack, struct c_arg_info);
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 = 0;
arg_types = grokparms (arg_info, false);
type_quals = TYPE_UNQUALIFIED;
type = build_function_type (type, arg_types);
}
decl = build_decl (FUNCTION_DECL, NULL_TREE, type);
DECL_ARGUMENTS (decl) = arg_info ? arg_info->parms : NULL_TREE;
return decl;
}
if (storage_class == csc_typedef)
{
tree decl;
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
pedwarn ("ISO C forbids qualified function types");
if (type_quals)
type = c_build_qualified_type (type, type_quals);
decl = build_decl (TYPE_DECL, declarator->u.id, type);
if (declspecs->explicit_signed_p)
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
decl_attributes (&decl, returned_attrs, 0);
if (declspecs->inline_p)
pedwarn ("typedef %q+D declared %<inline%>", decl);
return decl;
}
if (decl_context == TYPENAME)
{
gcc_assert (storage_class == csc_none && !threadp
&& !declspecs->inline_p);
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
pedwarn ("ISO C forbids const or volatile function types");
if (type_quals)
type = c_build_qualified_type (type, type_quals);
decl_attributes (&type, returned_attrs, 0);
return type;
}
if (pedantic && decl_context == FIELD
&& variably_modified_type_p (type, NULL_TREE))
{
pedwarn ("a member of a structure or union cannot have a variably modified type");
}
if (VOID_TYPE_P (type) && decl_context != PARM
&& !((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE)
&& (storage_class == csc_extern
|| (current_scope == file_scope
&& !(storage_class == csc_static
|| storage_class == csc_register)))))
{
error ("variable or field %qs declared void", name);
type = integer_type_node;
}
{
tree decl;
if (decl_context == PARM)
{
tree type_as_written;
tree promoted_type;
if (TREE_CODE (type) == ARRAY_TYPE)
{
type = TREE_TYPE (type);
if (type_quals)
type = c_build_qualified_type (type, type_quals);
type = build_pointer_type (type);
type_quals = array_ptr_quals;
if (array_ptr_attrs != NULL_TREE)
warning (OPT_Wattributes,
"attributes in parameter array declarator ignored");
size_varies = 0;
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
if (pedantic && type_quals)
pedwarn ("ISO C forbids qualified function types");
if (type_quals)
type = c_build_qualified_type (type, type_quals);
type = build_pointer_type (type);
type_quals = TYPE_UNQUALIFIED;
}
else if (type_quals)
type = c_build_qualified_type (type, type_quals);
type_as_written = type;
decl = build_decl (PARM_DECL, declarator->u.id, type);
if (size_varies)
C_DECL_VARIABLE_SIZE (decl) = 1;
if (type == error_mark_node)
promoted_type = type;
else
promoted_type = c_type_promotes_to (type);
DECL_ARG_TYPE (decl) = promoted_type;
if (declspecs->inline_p)
pedwarn ("parameter %q+D declared %<inline%>", decl);
}
else if (decl_context == FIELD)
{
gcc_assert (storage_class == csc_none && !threadp
&& !declspecs->inline_p);
if (TREE_CODE (type) == FUNCTION_TYPE)
{
error ("field %qs declared as a function", name);
type = build_pointer_type (type);
}
else if (TREE_CODE (type) != ERROR_MARK
&& !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
{
error ("field %qs has incomplete type", name);
type = error_mark_node;
}
type = c_build_qualified_type (type, type_quals);
decl = build_decl (FIELD_DECL, declarator->u.id, type);
DECL_NONADDRESSABLE_P (decl) = bitfield;
if (size_varies)
C_DECL_VARIABLE_SIZE (decl) = 1;
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
if (storage_class == csc_register || threadp)
{
error ("invalid storage class for function %qs", name);
}
else if (current_scope != file_scope)
{
if (storage_class == csc_auto)
{
if (pedantic)
pedwarn ("invalid storage class for function %qs", name);
}
else if (storage_class == csc_static)
{
error ("invalid storage class for function %qs", name);
if (funcdef_flag)
storage_class = declspecs->storage_class = csc_none;
else
return 0;
}
}
decl = build_decl (FUNCTION_DECL, declarator->u.id, type);
decl = build_decl_attribute_variant (decl, decl_attr);
DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
pedwarn ("ISO C forbids qualified function types");
if ((type_quals & TYPE_QUAL_VOLATILE)
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
warning (0, "%<noreturn%> function returns non-void value");
if (storage_class == csc_auto && current_scope != file_scope)
DECL_EXTERNAL (decl) = 0;
else if (declspecs->inline_p && storage_class != csc_static)
DECL_EXTERNAL (decl) = ((storage_class == csc_extern)
== flag_gnu89_inline);
else
DECL_EXTERNAL (decl) = !initialized;
TREE_PUBLIC (decl)
= !(storage_class == csc_static || storage_class == csc_auto);
if (funcdef_flag)
current_function_arg_info = arg_info;
if (declspecs->default_int_p)
C_FUNCTION_IMPLICIT_INT (decl) = 1;
if (declspecs->private_extern_p)
{
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
DECL_VISIBILITY_SPECIFIED (decl) = 1;
}
if (flag_hosted && MAIN_NAME_P (declarator->u.id))
{
if (declspecs->inline_p)
pedwarn ("cannot inline function %<main%>");
}
else if (declspecs->inline_p)
{
DECL_DECLARED_INLINE_P (decl) = 1;
DECL_EXPLICIT_INLINE_P (decl) = 1;
if (initialized)
DECL_INLINE (decl) = 1;
}
else if (flag_inline_trees == 2 && initialized)
DECL_INLINE (decl) = 1;
}
else
{
int extern_ref = !initialized && storage_class == csc_extern;
type = c_build_qualified_type (type, type_quals);
if (extern_ref && current_scope != file_scope)
{
tree global_decl = identifier_global_value (declarator->u.id);
tree visible_decl = lookup_name (declarator->u.id);
if (global_decl
&& global_decl != visible_decl
&& TREE_CODE (global_decl) == VAR_DECL
&& !TREE_PUBLIC (global_decl))
error ("variable previously declared %<static%> redeclared "
"%<extern%>");
}
decl = build_decl (VAR_DECL, declarator->u.id, type);
DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
if (size_varies)
C_DECL_VARIABLE_SIZE (decl) = 1;
if (declspecs->inline_p)
pedwarn ("variable %q+D declared %<inline%>", decl);
DECL_EXTERNAL (decl) = (storage_class == csc_extern);
if (declspecs->private_extern_p)
{
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
DECL_VISIBILITY_SPECIFIED (decl) = 1;
}
if (current_scope == file_scope)
{
TREE_PUBLIC (decl) = storage_class != csc_static;
TREE_STATIC (decl) = !extern_ref;
}
else
{
TREE_STATIC (decl) = (storage_class == csc_static);
TREE_PUBLIC (decl) = extern_ref;
}
if (threadp)
{
if (targetm.have_tls)
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
else
error ("thread-local storage not supported for this target");
}
}
if (storage_class == csc_extern
&& variably_modified_type_p (type, NULL_TREE))
{
error ("object with variably modified type must have no linkage");
}
if (storage_class == csc_register)
{
C_DECL_REGISTER (decl) = 1;
DECL_REGISTER (decl) = 1;
}
if (declspecs->iasm_asm_specbit)
{
if (flag_iasm_blocks)
{
DECL_IASM_ASM_FUNCTION (decl) = 1;
DECL_IASM_NORETURN (decl) = 0;
DECL_IASM_FRAME_SIZE (decl) = -2;
}
else
error ("asm functions not enabled, use `-fasm-blocks'");
}
c_apply_type_quals_to_decl (type_quals, decl);
if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl))
&& (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL))
{
int was_reg = C_DECL_REGISTER (decl);
C_DECL_REGISTER (decl) = 0;
DECL_REGISTER (decl) = 0;
c_mark_addressable (decl);
C_DECL_REGISTER (decl) = was_reg;
}
gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
decl_attributes (&decl, returned_attrs, 0);
return decl;
}
}
static tree
grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
{
tree arg_types = arg_info->types;
if (funcdef_flag && arg_info->had_vla_unspec)
{
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");
if (arg_types == error_mark_node)
return 0;
else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE)
{
if (!funcdef_flag)
pedwarn ("parameter names (without types) in function declaration");
arg_info->parms = arg_info->types;
arg_info->types = 0;
return 0;
}
else
{
tree parm, type, typelt;
unsigned int parmno;
for (parm = arg_info->parms, typelt = arg_types, parmno = 1;
parm;
parm = TREE_CHAIN (parm), typelt = TREE_CHAIN (typelt), parmno++)
{
type = TREE_VALUE (typelt);
if (type == error_mark_node)
continue;
if (!COMPLETE_TYPE_P (type))
{
if (funcdef_flag)
{
if (DECL_NAME (parm))
error ("parameter %u (%q+D) has incomplete type",
parmno, parm);
else
error ("%Jparameter %u has incomplete type",
parm, parmno);
TREE_VALUE (typelt) = error_mark_node;
TREE_TYPE (parm) = error_mark_node;
}
else if (VOID_TYPE_P (type))
{
if (DECL_NAME (parm))
warning (0, "parameter %u (%q+D) has void type",
parmno, parm);
else
warning (0, "%Jparameter %u has void type",
parm, parmno);
}
}
if (DECL_NAME (parm) && TREE_USED (parm))
warn_if_shadowing (parm);
}
return arg_types;
}
}
struct c_arg_info *
get_parm_info (bool ellipsis)
{
struct c_binding *b = current_scope->bindings;
struct c_arg_info *arg_info = XOBNEW (&parser_obstack,
struct c_arg_info);
tree parms = 0;
tree tags = 0;
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;
current_scope->bindings = 0;
gcc_assert (b);
if (b->prev == 0
&& TREE_CODE (b->decl) == PARM_DECL
&& !DECL_NAME (b->decl)
&& VOID_TYPE_P (TREE_TYPE (b->decl)))
{
if (TREE_THIS_VOLATILE (b->decl)
|| TREE_READONLY (b->decl)
|| C_DECL_REGISTER (b->decl))
error ("%<void%> as only parameter may not be qualified");
if (ellipsis)
error ("%<void%> must be the only parameter");
arg_info->types = void_list_node;
return arg_info;
}
if (!ellipsis)
types = void_list_node;
while (b)
{
tree decl = b->decl;
tree type = TREE_TYPE (decl);
const char *keyword;
switch (TREE_CODE (decl))
{
case PARM_DECL:
if (b->id)
{
gcc_assert (I_SYMBOL_BINDING (b->id) == b);
I_SYMBOL_BINDING (b->id) = b->shadowed;
}
if (TREE_ASM_WRITTEN (decl))
error ("parameter %q+D has just a forward declaration", decl);
else if (VOID_TYPE_P (type) && !DECL_NAME (decl))
{
if (!gave_void_only_once_err)
{
error ("%<void%> must be the only parameter");
gave_void_only_once_err = true;
}
}
else
{
TREE_CHAIN (decl) = parms;
parms = decl;
DECL_ARG_TYPE (decl) = type;
types = tree_cons (0, type, types);
}
break;
case ENUMERAL_TYPE: keyword = "enum"; goto tag;
case UNION_TYPE: keyword = "union"; goto tag;
case RECORD_TYPE: keyword = "struct"; goto tag;
tag:
if (b->id)
{
gcc_assert (I_TAG_BINDING (b->id) == b);
I_TAG_BINDING (b->id) = b->shadowed;
}
if (TREE_CODE (decl) != UNION_TYPE || b->id != 0)
{
if (b->id)
warning (0, "%<%s %E%> declared inside parameter list",
keyword, b->id);
else
warning (0, "anonymous %s declared inside parameter list",
keyword);
if (!explained_incomplete_types)
{
warning (0, "its scope is only this definition or declaration,"
" which is probably not what you want");
explained_incomplete_types = true;
}
}
tags = tree_cons (b->id, decl, tags);
break;
case CONST_DECL:
case TYPE_DECL:
case FUNCTION_DECL:
TREE_CHAIN (decl) = others;
others = decl;
case ERROR_MARK:
if (b->id)
{
gcc_assert (I_SYMBOL_BINDING (b->id) == b);
I_SYMBOL_BINDING (b->id) = b->shadowed;
}
break;
case LABEL_DECL:
case VAR_DECL:
default:
gcc_unreachable ();
}
b = free_binding_and_advance (b);
}
arg_info->parms = parms;
arg_info->tags = tags;
arg_info->types = types;
arg_info->others = others;
arg_info->pending_sizes = get_pending_sizes ();
return arg_info;
}
struct c_typespec
parser_xref_tag (enum tree_code code, tree name)
{
struct c_typespec ret;
tree ref = lookup_tag (code, name, 0);
ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref);
if (ref && TREE_CODE (ref) == code)
{
ret.spec = ref;
return ret;
}
ref = make_node (code);
if (code == ENUMERAL_TYPE)
{
TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
TYPE_USER_ALIGN (ref) = 0;
TYPE_UNSIGNED (ref) = 1;
TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node);
TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node);
TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
}
pushtag (name, ref);
ret.spec = ref;
return ret;
}
tree
xref_tag (enum tree_code code, tree name)
{
return parser_xref_tag (code, name).spec;
}
tree
start_struct (enum tree_code code, tree name)
{
tree ref = 0;
if (name != 0)
ref = lookup_tag (code, name, 1);
if (ref && TREE_CODE (ref) == code)
{
if (TYPE_SIZE (ref))
{
if (code == UNION_TYPE)
error ("redefinition of %<union %E%>", name);
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
error ("nested redefinition of %<struct %E%>", name);
ref = NULL_TREE;
}
}
if (ref == NULL_TREE || TREE_CODE (ref) != code)
{
ref = make_node (code);
pushtag (name, ref);
}
C_TYPE_BEING_DEFINED (ref) = 1;
TYPE_PACKED (ref) = flag_pack_struct;
return ref;
}
tree
grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
tree width)
{
tree value;
if (declarator->kind == cdk_id && declarator->u.id == NULL_TREE
&& width == NULL_TREE)
{
tree type = declspecs->type;
bool type_ok = (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE);
bool ok = false;
if (type_ok
&& (flag_ms_extensions || !declspecs->typedef_p))
{
if (flag_ms_extensions)
ok = true;
else if (flag_iso)
ok = false;
else if (TYPE_NAME (type) == NULL)
ok = true;
else
ok = false;
}
if (!ok)
{
pedwarn ("declaration does not declare anything");
return NULL_TREE;
}
if (pedantic)
pedwarn ("ISO C doesn%'t support unnamed structs/unions");
}
value = grokdeclarator (declarator, declspecs, FIELD, false,
width ? &width : NULL);
finish_decl (value, NULL_TREE, NULL_TREE);
DECL_INITIAL (value) = width;
return value;
}
static void
detect_field_duplicates (tree fieldlist)
{
tree x, y;
int timeout = 10;
if (!fieldlist)
return;
x = TREE_CHAIN (fieldlist);
if (!x)
return;
do {
timeout--;
x = TREE_CHAIN (x);
} while (timeout > 0 && x);
if (timeout > 0)
{
for (x = TREE_CHAIN (fieldlist); x ; x = TREE_CHAIN (x))
if (DECL_NAME (x))
{
for (y = fieldlist; y != x; y = TREE_CHAIN (y))
if (DECL_NAME (y) == DECL_NAME (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;
}
htab_delete (htab);
}
}
tree
finish_struct (tree t, tree fieldlist, tree attributes)
{
tree x;
bool toplevel = file_scope == current_scope;
int saw_named_field;
TYPE_SIZE (t) = 0;
decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
if (pedantic)
{
for (x = fieldlist; x; x = TREE_CHAIN (x))
if (DECL_NAME (x) != 0)
break;
if (x == 0)
{
if (TREE_CODE (t) == UNION_TYPE)
{
if (fieldlist)
pedwarn ("union has no named members");
else
pedwarn ("union has no members");
}
else
{
if (fieldlist)
pedwarn ("struct has no named members");
else
pedwarn ("struct has no members");
}
}
}
saw_named_field = 0;
for (x = fieldlist; x; x = TREE_CHAIN (x))
{
if (TREE_TYPE (x) == error_mark_node)
continue;
DECL_CONTEXT (x) = t;
if (TYPE_PACKED (t) && TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)
DECL_PACKED (x) = 1;
if (TREE_READONLY (x))
C_TYPE_FIELDS_READONLY (t) = 1;
else
{
tree t1 = TREE_TYPE (x);
while (TREE_CODE (t1) == ARRAY_TYPE)
t1 = TREE_TYPE (t1);
if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (t1))
C_TYPE_FIELDS_READONLY (t) = 1;
}
if (TREE_THIS_VOLATILE (x))
C_TYPE_FIELDS_VOLATILE (t) = 1;
if (C_DECL_VARIABLE_SIZE (x))
C_TYPE_VARIABLE_SIZE (t) = 1;
if (DECL_INITIAL (x))
{
unsigned HOST_WIDE_INT width = tree_low_cst (DECL_INITIAL (x), 1);
DECL_SIZE (x) = bitsize_int (width);
DECL_BIT_FIELD (x) = 1;
SET_DECL_C_BIT_FIELD (x);
}
if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
&& TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
&& TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
{
if (TREE_CODE (t) == UNION_TYPE)
{
error ("%Jflexible array member in union", x);
TREE_TYPE (x) = error_mark_node;
}
else if (TREE_CHAIN (x) != NULL_TREE)
{
error ("%Jflexible array member not at end of struct", x);
TREE_TYPE (x) = error_mark_node;
}
else if (!saw_named_field)
{
error ("%Jflexible array member in otherwise empty struct", x);
TREE_TYPE (x) = error_mark_node;
}
}
if (pedantic && !in_system_header && TREE_CODE (t) == RECORD_TYPE
&& flexible_array_type_p (TREE_TYPE (x)))
pedwarn ("%Jinvalid use of structure with flexible array member", x);
if (DECL_NAME (x))
saw_named_field = 1;
if (c_dialect_objc ())
objc_checkon_weak_attribute (x);
}
if (c_dialect_objc ())
objc_detect_field_duplicates (objc_get_interface_ivars (fieldlist));
else
detect_field_duplicates (fieldlist);
TYPE_FIELDS (t) = fieldlist;
layout_type (t);
{
tree *fieldlistp = &fieldlist;
while (*fieldlistp)
if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp)
&& TREE_TYPE (*fieldlistp) != error_mark_node)
{
unsigned HOST_WIDE_INT width
= tree_low_cst (DECL_INITIAL (*fieldlistp), 1);
tree type = TREE_TYPE (*fieldlistp);
if (width != TYPE_PRECISION (type))
{
TREE_TYPE (*fieldlistp)
= c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type));
DECL_MODE (*fieldlistp) = TYPE_MODE (TREE_TYPE (*fieldlistp));
}
DECL_INITIAL (*fieldlistp) = 0;
}
else
fieldlistp = &TREE_CHAIN (*fieldlistp);
}
TYPE_FIELDS (t) = fieldlist;
{
int len = 0;
for (x = fieldlist; x; x = TREE_CHAIN (x))
{
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;
len += list_length (x);
space = GGC_CNEW (struct lang_type);
space2 = GGC_NEWVAR (struct 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))
{
field_array[len++] = x;
if (DECL_NAME (x) == NULL)
break;
}
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 = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
{
TYPE_FIELDS (x) = TYPE_FIELDS (t);
TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (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 (TREE_CODE (t) == UNION_TYPE
&& TYPE_TRANSPARENT_UNION (t)
&& (!TYPE_FIELDS (t) || TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t))))
{
TYPE_TRANSPARENT_UNION (t) = 0;
warning (0, "union cannot be made transparent");
}
for (x = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
x;
x = TREE_CHAIN (x))
{
tree decl = TREE_VALUE (x);
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
layout_array_type (TREE_TYPE (decl));
if (TREE_CODE (decl) != TYPE_DECL)
{
layout_decl (decl, 0);
if (c_dialect_objc ())
objc_check_decl (decl);
rest_of_decl_compilation (decl, toplevel, 0);
if (!toplevel)
expand_decl (decl);
}
}
C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)) = 0;
rest_of_type_compilation (t, toplevel);
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;
}
static void
layout_array_type (tree t)
{
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
layout_array_type (TREE_TYPE (t));
layout_type (t);
}
tree
start_enum (tree name)
{
tree enumtype = 0;
if (name != 0)
enumtype = lookup_tag (ENUMERAL_TYPE, name, 1);
if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
{
enumtype = make_node (ENUMERAL_TYPE);
pushtag (name, enumtype);
}
if (C_TYPE_BEING_DEFINED (enumtype))
error ("nested redefinition of %<enum %E%>", name);
C_TYPE_BEING_DEFINED (enumtype) = 1;
if (TYPE_VALUES (enumtype) != 0)
{
error ("redeclaration of %<enum %E%>", name);
TYPE_VALUES (enumtype) = 0;
}
enum_next_value = integer_zero_node;
enum_overflow = 0;
if (flag_short_enums)
TYPE_PACKED (enumtype) = 1;
return enumtype;
}
tree
finish_enum (tree enumtype, tree values, tree attributes)
{
tree pair, tem;
tree minnode = 0, maxnode = 0;
int precision, unsign;
bool toplevel = (file_scope == current_scope);
struct lang_type *lt;
decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
if (values == error_mark_node)
minnode = maxnode = integer_zero_node;
else
{
minnode = maxnode = TREE_VALUE (values);
for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
{
tree value = TREE_VALUE (pair);
if (tree_int_cst_lt (maxnode, value))
maxnode = value;
if (tree_int_cst_lt (value, minnode))
minnode = value;
}
}
unsign = (tree_int_cst_sgn (minnode) >= 0);
precision = MAX (min_precision (minnode, unsign),
min_precision (maxnode, unsign));
if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
{
tem = c_common_type_for_size (precision, unsign);
if (tem == NULL)
{
warning (0, "enumeration values exceed range of largest integer");
tem = long_long_integer_type_node;
}
}
else
tem = unsign ? unsigned_type_node : integer_type_node;
TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem);
TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem);
TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem);
TYPE_SIZE (enumtype) = 0;
if (TYPE_PRECISION (enumtype))
{
if (precision > TYPE_PRECISION (enumtype))
error ("specified mode too small for enumeral values");
}
else
TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem);
layout_type (enumtype);
if (values != error_mark_node)
{
for (pair = values; pair; pair = TREE_CHAIN (pair))
{
tree enu = TREE_PURPOSE (pair);
tree ini = DECL_INITIAL (enu);
TREE_TYPE (enu) = enumtype;
if (int_fits_type_p (ini, integer_type_node))
tem = integer_type_node;
else
tem = enumtype;
ini = convert (tem, ini);
DECL_INITIAL (enu) = ini;
TREE_PURPOSE (pair) = DECL_NAME (enu);
TREE_VALUE (pair) = ini;
}
TYPE_VALUES (enumtype) = values;
}
lt = GGC_CNEW (struct lang_type);
lt->enum_min = minnode;
lt->enum_max = maxnode;
TYPE_LANG_SPECIFIC (enumtype) = lt;
for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
{
if (tem == enumtype)
continue;
TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype);
TYPE_MODE (tem) = TYPE_MODE (enumtype);
TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype);
TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype);
TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype);
}
rest_of_type_compilation (enumtype, toplevel);
return enumtype;
}
tree
build_enumerator (tree name, tree value)
{
tree decl, type;
if (value != 0)
{
if (value == error_mark_node)
value = 0;
else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
|| TREE_CODE (value) != INTEGER_CST)
{
error ("enumerator value for %qE is not an integer constant", name);
value = 0;
}
else
{
value = default_conversion (value);
constant_expression_warning (value);
}
}
if (value == 0)
{
value = enum_next_value;
if (enum_overflow)
error ("overflow in enumeration values");
}
if (pedantic && !int_fits_type_p (value, integer_type_node))
{
pedwarn ("ISO C restricts enumerator values to range of %<int%>");
value = convert (integer_type_node, value);
}
enum_next_value = build_binary_op (PLUS_EXPR, value, integer_one_node, 0);
enum_overflow = tree_int_cst_lt (enum_next_value, value);
type = TREE_TYPE (value);
type = c_common_type_for_size (MAX (TYPE_PRECISION (type),
TYPE_PRECISION (integer_type_node)),
(TYPE_PRECISION (type)
>= TYPE_PRECISION (integer_type_node)
&& TYPE_UNSIGNED (type)));
decl = build_decl (CONST_DECL, name, type);
DECL_INITIAL (decl) = convert (type, value);
pushdecl (decl);
return tree_cons (decl, value, NULL_TREE);
}
int
start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
tree attributes)
{
tree decl1, old_decl;
tree restype, resdecl;
struct c_label_context_se *nstack_se;
struct c_label_context_vm *nstack_vm;
current_function_returns_value = 0;
current_function_returns_null = 0;
current_function_returns_abnormally = 0;
warn_about_return_type = 0;
c_switch_stack = NULL;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack_se->labels_def = NULL;
nstack_se->labels_used = NULL;
nstack_se->next = label_context_stack_se;
label_context_stack_se = nstack_se;
nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack_vm->labels_def = NULL;
nstack_vm->labels_used = NULL;
nstack_vm->scope = 0;
nstack_vm->next = label_context_stack_vm;
label_context_stack_vm = nstack_vm;
c_break_label = c_cont_label = size_zero_node;
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL);
if (decl1 == 0)
{
label_context_stack_se = label_context_stack_se->next;
label_context_stack_vm = label_context_stack_vm->next;
return 0;
}
decl_attributes (&decl1, attributes, 0);
if (DECL_DECLARED_INLINE_P (decl1)
&& DECL_UNINLINABLE (decl1)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1)))
warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
decl1);
if (declspecs->inline_p
&& !flag_gnu89_inline
&& TREE_CODE (decl1) == FUNCTION_DECL
&& lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)))
{
if (declspecs->storage_class != csc_static)
DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1);
}
announce_function (decl1);
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
{
error ("return type is an incomplete type");
TREE_TYPE (decl1)
= build_function_type (void_type_node,
TYPE_ARG_TYPES (TREE_TYPE (decl1)));
}
if (warn_about_return_type)
pedwarn_c99 ("return type defaults to %<int%>");
DECL_INITIAL (decl1) = error_mark_node;
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;
if (TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
{
if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (decl1)),
TREE_TYPE (TREE_TYPE (old_decl))))
{
TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
TREE_TYPE (decl1));
current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl);
current_function_prototype_built_in
= C_DECL_BUILTIN_PROTOTYPE (old_decl);
current_function_prototype_arg_types
= TYPE_ARG_TYPES (TREE_TYPE (decl1));
}
if (TREE_PUBLIC (decl1))
{
struct c_binding *b;
for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed)
if (B_IN_SCOPE (b, external_scope))
break;
if (b)
{
tree ext_decl, ext_type;
ext_decl = b->decl;
ext_type = b->type ? b->type : TREE_TYPE (ext_decl);
if (TREE_CODE (ext_type) == FUNCTION_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (decl1)),
TREE_TYPE (ext_type)))
{
current_function_prototype_locus
= DECL_SOURCE_LOCATION (ext_decl);
current_function_prototype_built_in
= C_DECL_BUILTIN_PROTOTYPE (ext_decl);
current_function_prototype_arg_types
= TYPE_ARG_TYPES (ext_type);
}
}
}
}
if (warn_strict_prototypes
&& old_decl != error_mark_node
&& TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0
&& C_DECL_ISNT_PROTOTYPE (old_decl))
warning (OPT_Wstrict_prototypes,
"function declaration isn%'t a prototype");
else if (warn_missing_prototypes
&& old_decl != error_mark_node
&& TREE_PUBLIC (decl1)
&& !MAIN_NAME_P (DECL_NAME (decl1))
&& C_DECL_ISNT_PROTOTYPE (old_decl))
warning (OPT_Wmissing_prototypes, "no previous prototype for %q+D", decl1);
else if (warn_missing_prototypes
&& old_decl != 0
&& old_decl != error_mark_node
&& TREE_USED (old_decl)
&& TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0)
warning (OPT_Wmissing_prototypes,
"%q+D was used with no prototype before its definition", decl1);
else if (warn_missing_declarations
&& TREE_PUBLIC (decl1)
&& old_decl == 0
&& !MAIN_NAME_P (DECL_NAME (decl1)))
warning (OPT_Wmissing_declarations, "no previous declaration for %q+D",
decl1);
else if (warn_missing_declarations
&& old_decl != 0
&& old_decl != error_mark_node
&& TREE_USED (old_decl)
&& C_DECL_IMPLICIT (old_decl))
warning (OPT_Wmissing_declarations,
"%q+D was used with no declaration before its definition", decl1);
TREE_STATIC (decl1) = 1;
if (current_function_decl != 0)
TREE_PUBLIC (decl1) = 0;
gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1));
if (current_scope == file_scope)
maybe_apply_pragma_weak (decl1);
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;
}
}
if (argct > 0 && (argct < 2 || argct > 3))
pedwarn ("%q+D takes only zero or two arguments", decl1);
if (!TREE_PUBLIC (decl1))
pedwarn ("%q+D is normally a non-static function", decl1);
}
current_function_decl = pushdecl (decl1);
record_func_cl_pf_opts_mapping (current_function_decl);
push_scope ();
declare_parm_level ();
restype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (c_promoting_integer_type_p (restype))
{
if (TYPE_UNSIGNED (restype)
&& (TYPE_PRECISION (restype)
== TYPE_PRECISION (integer_type_node)))
restype = unsigned_type_node;
else
restype = integer_type_node;
}
resdecl = build_decl (RESULT_DECL, NULL_TREE, restype);
DECL_ARTIFICIAL (resdecl) = 1;
DECL_IGNORED_P (resdecl) = 1;
DECL_RESULT (current_function_decl) = resdecl;
if (DECL_IASM_ASM_FUNCTION (current_function_decl))
{
iasm_state = iasm_decls;
iasm_in_decl = false;
current_function_returns_abnormally = 1;
TREE_NO_WARNING (current_function_decl) = 1;
}
start_fname_decls ();
return 1;
}
static void
store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info)
{
tree decl;
if (current_scope->bindings)
{
error ("%Jold-style parameter declarations in prototyped "
"function definition", fndecl);
pop_scope ();
push_scope ();
}
else if (!in_system_header && !current_function_scope
&& arg_info->types != error_mark_node)
warning (OPT_Wtraditional,
"%Jtraditional C rejects ISO C style function definitions",
fndecl);
for (decl = arg_info->parms; decl; decl = TREE_CHAIN (decl))
{
DECL_CONTEXT (decl) = current_function_decl;
if (DECL_NAME (decl))
{
bind (DECL_NAME (decl), decl, current_scope,
false, false);
if (!TREE_USED (decl))
warn_if_shadowing (decl);
}
else
error ("%Jparameter name omitted", decl);
}
DECL_ARGUMENTS (fndecl) = arg_info->parms;
for (decl = arg_info->others; decl; decl = TREE_CHAIN (decl))
{
DECL_CONTEXT (decl) = current_function_decl;
if (DECL_NAME (decl))
bind (DECL_NAME (decl), decl, current_scope,
false, false);
}
for (decl = arg_info->tags; decl; decl = TREE_CHAIN (decl))
if (TREE_PURPOSE (decl))
bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope,
false, false);
}
static void
store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
{
struct c_binding *b;
tree parm, decl, last;
tree parmids = arg_info->parms;
struct pointer_set_t *seen_args = pointer_set_create ();
if (!in_system_header)
warning (OPT_Wold_style_definition, "%Jold-style function definition",
fndecl);
for (parm = parmids; parm; parm = TREE_CHAIN (parm))
{
if (TREE_VALUE (parm) == 0)
{
error ("%Jparameter name missing from parameter list", fndecl);
TREE_PURPOSE (parm) = 0;
continue;
}
b = I_SYMBOL_BINDING (TREE_VALUE (parm));
if (b && B_IN_CURRENT_SCOPE (b))
{
decl = b->decl;
if (TREE_CODE (decl) != PARM_DECL)
error ("%q+D declared as a non-parameter", decl);
else if (pointer_set_contains (seen_args, decl))
{
error ("multiple parameters named %q+D", decl);
TREE_PURPOSE (parm) = 0;
continue;
}
else if (VOID_TYPE_P (TREE_TYPE (decl)))
{
error ("parameter %q+D declared with void type", decl);
TREE_TYPE (decl) = integer_type_node;
DECL_ARG_TYPE (decl) = integer_type_node;
layout_decl (decl, 0);
}
warn_if_shadowing (decl);
}
else
{
decl = build_decl (PARM_DECL, TREE_VALUE (parm), integer_type_node);
DECL_ARG_TYPE (decl) = TREE_TYPE (decl);
DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (fndecl);
pushdecl (decl);
warn_if_shadowing (decl);
if (flag_isoc99)
pedwarn ("type of %q+D defaults to %<int%>", decl);
else if (extra_warnings)
warning (OPT_Wextra, "type of %q+D defaults to %<int%>", decl);
}
TREE_PURPOSE (parm) = decl;
pointer_set_insert (seen_args, decl);
}
for (b = current_scope->bindings; b; b = b->prev)
{
parm = b->decl;
if (TREE_CODE (parm) != PARM_DECL)
continue;
if (TREE_TYPE (parm) != error_mark_node
&& !COMPLETE_TYPE_P (TREE_TYPE (parm)))
{
error ("parameter %q+D has incomplete type", parm);
TREE_TYPE (parm) = error_mark_node;
}
if (!pointer_set_contains (seen_args, parm))
{
error ("declaration for parameter %q+D but no such parameter", parm);
parmids = chainon (parmids, tree_cons (parm, 0, 0));
}
}
DECL_ARGUMENTS (fndecl) = 0;
for (parm = parmids; parm; parm = TREE_CHAIN (parm))
if (TREE_PURPOSE (parm))
break;
if (parm && TREE_PURPOSE (parm))
{
last = TREE_PURPOSE (parm);
DECL_ARGUMENTS (fndecl) = last;
for (parm = TREE_CHAIN (parm); parm; parm = TREE_CHAIN (parm))
if (TREE_PURPOSE (parm))
{
TREE_CHAIN (last) = TREE_PURPOSE (parm);
last = TREE_PURPOSE (parm);
}
TREE_CHAIN (last) = 0;
}
pointer_set_destroy (seen_args);
if (current_function_prototype_arg_types)
{
tree type;
for (parm = DECL_ARGUMENTS (fndecl),
type = current_function_prototype_arg_types;
parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type))
!= void_type_node));
parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
{
if (parm == 0 || type == 0
|| TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
{
if (current_function_prototype_built_in)
warning (0, "number of arguments doesn%'t match "
"built-in prototype");
else
{
error ("number of arguments doesn%'t match prototype");
error ("%Hprototype declaration",
¤t_function_prototype_locus);
}
break;
}
if (!comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
TYPE_MAIN_VARIANT (TREE_VALUE (type))))
{
if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
== TYPE_MAIN_VARIANT (TREE_VALUE (type)))
{
DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
if (targetm.calls.promote_prototypes (TREE_TYPE (current_function_decl))
&& INTEGRAL_TYPE_P (TREE_TYPE (parm))
&& TYPE_PRECISION (TREE_TYPE (parm))
< TYPE_PRECISION (integer_type_node))
DECL_ARG_TYPE (parm) = integer_type_node;
if (pedantic)
{
if (current_function_prototype_built_in)
warning (0, "promoted argument %qD "
"doesn%'t match built-in prototype", parm);
else
{
pedwarn ("promoted argument %qD "
"doesn%'t match prototype", parm);
pedwarn ("%Hprototype declaration",
¤t_function_prototype_locus);
}
}
}
else
{
if (current_function_prototype_built_in)
warning (0, "argument %qD doesn%'t match "
"built-in prototype", parm);
else
{
error ("argument %qD doesn%'t match prototype", parm);
error ("%Hprototype declaration",
¤t_function_prototype_locus);
}
}
}
}
TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = 0;
}
else
{
tree actual = 0, last = 0, type;
for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm))
{
type = tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), NULL_TREE);
if (last)
TREE_CHAIN (last) = type;
else
actual = type;
last = type;
}
type = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
if (last)
TREE_CHAIN (last) = type;
else
actual = type;
TREE_TYPE (fndecl) = build_variant_type_copy (TREE_TYPE (fndecl));
TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual;
}
}
void
store_parm_decls_from (struct c_arg_info *arg_info)
{
current_function_arg_info = arg_info;
store_parm_decls ();
}
void
store_parm_decls (void)
{
tree fndecl = current_function_decl;
bool proto;
struct c_arg_info *arg_info = current_function_arg_info;
current_function_arg_info = 0;
proto = arg_info->types != 0;
if (proto)
store_parm_decls_newstyle (fndecl, arg_info);
else
store_parm_decls_oldstyle (fndecl, arg_info);
next_is_function_body = true;
gen_aux_info_record (fndecl, 1, 0, proto);
allocate_struct_function (fndecl);
DECL_SAVED_TREE (fndecl) = push_stmt_list ();
{
tree t;
for (t = nreverse (get_pending_sizes ()); t ; t = TREE_CHAIN (t))
add_stmt (TREE_VALUE (t));
}
cfun->x_dont_save_pending_sizes_p = 1;
}
static void
c_gimple_diagnostics_recursively (tree fndecl)
{
struct cgraph_node *cgn;
c_warn_unused_result (&DECL_SAVED_TREE (fndecl));
if (flag_openmp)
diagnose_omp_structured_block_errors (fndecl);
cgn = cgraph_node (fndecl);
for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
c_gimple_diagnostics_recursively (cgn->decl);
}
void
finish_function (void)
{
tree fndecl = current_function_decl;
label_context_stack_se = label_context_stack_se->next;
label_context_stack_vm = label_context_stack_vm->next;
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
{
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;
}
}
if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node)
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node)
DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted)
{
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
!= integer_type_node)
{
if (!warn_main)
pedwarn ("return type of %q+D is not %<int%>", fndecl);
}
else
{
if (flag_isoc99)
{
tree stmt = c_finish_return (integer_zero_node);
#ifdef USE_MAPPED_LOCATION
SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION);
#else
annotate_with_file_line (stmt, input_filename, 0);
#endif
}
}
}
DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
finish_fname_decls ();
if (warn_return_type
&& TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE
&& !current_function_returns_value && !current_function_returns_null
&& !current_function_returns_abnormally
&& !MAIN_NAME_P (DECL_NAME (fndecl))
&& !C_FUNCTION_IMPLICIT_INT (fndecl)
&& DECL_INLINE (fndecl))
{
warning (OPT_Wreturn_type,
"no return statement in function returning non-void");
TREE_NO_WARNING (fndecl) = 1;
}
if (extra_warnings
&& current_function_returns_value
&& current_function_returns_null)
warning (OPT_Wextra, "this function may return with or without a value");
cfun->function_end_locus = input_location;
if (DECL_STATIC_CONSTRUCTOR (fndecl)
&& !targetm.have_ctors_dtors)
static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
if (DECL_STATIC_DESTRUCTOR (fndecl)
&& !targetm.have_ctors_dtors)
static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
c_determine_visibility (fndecl);
if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node
&& !undef_nested_function)
{
if (!decl_function_context (fndecl))
{
c_genericize (fndecl);
c_gimple_diagnostics_recursively (fndecl);
if (cgraph_global_info_ready)
{
c_expand_body (fndecl);
return;
}
cgraph_finalize_function (fndecl, false);
}
else
{
(void) cgraph_node (fndecl);
}
}
if (!decl_function_context (fndecl))
undef_nested_function = false;
cfun = NULL;
current_function_decl = NULL;
}
void
c_expand_body (tree fndecl)
{
if (!DECL_INITIAL (fndecl)
|| DECL_INITIAL (fndecl) == error_mark_node)
return;
tree_rest_of_compilation (fndecl);
#ifdef ENABLE_LLVM
if (DECL_STATIC_CONSTRUCTOR (fndecl))
llvm_emit_ctor_dtor (fndecl, DEFAULT_INIT_PRIORITY, 1);
if (DECL_STATIC_DESTRUCTOR (fndecl))
llvm_emit_ctor_dtor (fndecl, DEFAULT_INIT_PRIORITY, 0);
return;
#endif
if (DECL_STATIC_CONSTRUCTOR (fndecl)
&& targetm.have_ctors_dtors)
targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
DEFAULT_INIT_PRIORITY);
if (DECL_STATIC_DESTRUCTOR (fndecl)
&& targetm.have_ctors_dtors)
targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
DEFAULT_INIT_PRIORITY);
}
tree
check_for_loop_decls (void)
{
struct c_binding *b;
tree one_decl = NULL_TREE;
int n_decls = 0;
if (!flag_isoc99)
{
error ("%<for%> loop initial declaration used outside C99 mode");
return NULL_TREE;
}
for (b = current_scope->bindings; b; b = b->prev)
{
tree id = b->id;
tree decl = b->decl;
if (!id)
continue;
switch (TREE_CODE (decl))
{
case VAR_DECL:
if (TREE_STATIC (decl))
error ("declaration of static variable %q+D in %<for%> loop "
"initial declaration", decl);
else if (DECL_EXTERNAL (decl))
error ("declaration of %<extern%> variable %q+D in %<for%> loop "
"initial declaration", decl);
break;
case RECORD_TYPE:
error ("%<struct %E%> declared in %<for%> loop initial declaration",
id);
break;
case UNION_TYPE:
error ("%<union %E%> declared in %<for%> loop initial declaration",
id);
break;
case ENUMERAL_TYPE:
error ("%<enum %E%> declared in %<for%> loop initial declaration",
id);
break;
case FUNCTION_DECL:
if (BLOCK_SYNTHESIZED_FUNC (decl))
break;
default:
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;
}
void
c_push_function_context (struct function *f)
{
struct language_function *p;
p = GGC_NEW (struct language_function);
f->language = p;
p->base.x_stmt_tree = c_stmt_tree;
p->x_break_label = c_break_label;
p->x_cont_label = c_cont_label;
p->x_switch_stack = c_switch_stack;
p->arg_info = current_function_arg_info;
p->returns_value = current_function_returns_value;
p->returns_null = current_function_returns_null;
p->returns_abnormally = current_function_returns_abnormally;
p->warn_about_return_type = warn_about_return_type;
}
void
c_pop_function_context (struct function *f)
{
struct language_function *p = f->language;
if (current_function_decl
&& DECL_STRUCT_FUNCTION (current_function_decl) == 0
&& DECL_SAVED_TREE (current_function_decl) == NULL_TREE)
{
DECL_INITIAL (current_function_decl) = error_mark_node;
DECL_ARGUMENTS (current_function_decl) = 0;
}
c_stmt_tree = p->base.x_stmt_tree;
c_break_label = p->x_break_label;
c_cont_label = p->x_cont_label;
c_switch_stack = p->x_switch_stack;
current_function_arg_info = p->arg_info;
current_function_returns_value = p->returns_value;
current_function_returns_null = p->returns_null;
current_function_returns_abnormally = p->returns_abnormally;
warn_about_return_type = p->warn_about_return_type;
f->language = NULL;
}
void
c_dup_lang_specific_decl (tree decl)
{
struct lang_decl *ld;
if (!DECL_LANG_SPECIFIC (decl))
return;
ld = GGC_NEW (struct lang_decl);
memcpy (ld, DECL_LANG_SPECIFIC (decl), sizeof (struct lang_decl));
DECL_LANG_SPECIFIC (decl) = ld;
}
stmt_tree
current_stmt_tree (void)
{
return &c_stmt_tree;
}
int
anon_aggr_type_p (tree ARG_UNUSED (node))
{
return 0;
}
tree
identifier_global_value (tree t)
{
struct c_binding *b;
for (b = I_SYMBOL_BINDING (t); b; b = b->shadowed)
if (B_IN_FILE_SCOPE (b) || B_IN_EXTERNAL_SCOPE (b))
return b->decl;
return 0;
}
void
record_builtin_type (enum rid rid_index, const char *name, tree type)
{
tree id, decl;
if (name == 0)
id = ridpointers[(int) rid_index];
else
id = get_identifier (name);
decl = build_decl (TYPE_DECL, id, type);
pushdecl (decl);
if (debug_hooks->type_decl)
debug_hooks->type_decl (decl, false);
}
tree
build_void_list_node (void)
{
tree t = build_tree_list (NULL_TREE, void_type_node);
return t;
}
struct c_parm *
build_c_parm (struct c_declspecs *specs, tree attrs,
struct c_declarator *declarator)
{
struct c_parm *ret = XOBNEW (&parser_obstack, struct c_parm);
ret->specs = specs;
ret->attrs = attrs;
ret->declarator = declarator;
return ret;
}
struct c_declarator *
build_attrs_declarator (tree attrs, struct c_declarator *target)
{
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
ret->kind = cdk_attrs;
ret->declarator = target;
ret->u.attrs = attrs;
return ret;
}
struct c_declarator *
build_function_declarator (struct c_arg_info *args,
struct c_declarator *target)
{
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
ret->kind = cdk_function;
ret->declarator = target;
ret->u.arg_info = args;
return ret;
}
struct c_declarator *
build_id_declarator (tree ident)
{
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
ret->kind = cdk_id;
ret->declarator = 0;
ret->u.id = ident;
ret->id_loc = input_location;
return ret;
}
struct c_declarator *
make_pointer_declarator (struct c_declspecs *type_quals_attrs,
struct c_declarator *target)
{
tree attrs;
int quals = 0;
struct c_declarator *itarget = target;
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
if (type_quals_attrs)
{
attrs = type_quals_attrs->attrs;
quals = quals_from_declspecs (type_quals_attrs);
if (attrs != NULL_TREE)
itarget = build_attrs_declarator (attrs, target);
}
ret->kind = cdk_pointer;
ret->declarator = itarget;
ret->u.pointer_quals = quals;
return ret;
}
tree
build_byref_local_var_access (tree expr, tree decl_name)
{
tree exp = build_component_ref (expr, get_identifier ("__forwarding"));
exp = build_indirect_ref (exp, "unary *");
exp = build_component_ref (exp, decl_name);
return exp;
}
tree
build_block_byref_decl (tree name, tree decl, tree exp)
{
struct c_scope *scope = current_scope;
tree ptr_type, byref_decl;
if (cur_block->prev_block_info) {
struct block_sema_info *cb = cur_block->prev_block_info;
while (cb) {
struct c_binding *b = I_SYMBOL_BINDING (name);
while (b && b->decl
&& (TREE_CODE (b->decl) == VAR_DECL
|| TREE_CODE (b->decl) == PARM_DECL)
&& b->depth >= cur_block->the_scope->depth)
b = b->shadowed;
if (b && b->decl
&& (TREE_CODE (b->decl) == VAR_DECL
|| TREE_CODE (b->decl) == PARM_DECL)
&& b->depth < cb->the_scope->depth) {
struct c_scope *save_scope = current_scope;
struct block_sema_info *save_current_block = cur_block;
current_scope = cb->the_scope;
cur_block = cb;
decl = build_block_byref_decl (name, decl, exp);
cur_block = save_current_block;
current_scope = save_scope;
}
cb = cb->prev_block_info;
}
}
ptr_type = (TREE_CODE (decl) == VAR_DECL && BLOCK_DECL_BYREF (decl))
? TREE_TYPE (decl) : build_pointer_type (TREE_TYPE (decl));
byref_decl = build_decl (VAR_DECL, name, ptr_type);
DECL_SOURCE_LOCATION (byref_decl) = DECL_SOURCE_LOCATION
(cur_block->helper_func_decl);
BLOCK_DECL_BYREF (byref_decl) = 1;
if (TREE_CODE (decl) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (decl))
{
COPYABLE_BYREF_LOCAL_VAR (byref_decl) = 1;
COPYABLE_BYREF_LOCAL_NONPOD (byref_decl) = COPYABLE_BYREF_LOCAL_NONPOD (decl);
COPYABLE_WEAK_BLOCK (byref_decl) = COPYABLE_WEAK_BLOCK (decl);
}
while (scope && !scope->function_body)
scope = scope->outer;
gcc_assert (scope && scope->function_body);
bind (name, byref_decl,
scope, false, false);
cur_block->block_byref_decl_list =
tree_cons (NULL_TREE, byref_decl, cur_block->block_byref_decl_list);
if (! flag_objc_gc_only)
push_cleanup (byref_decl, build_block_byref_release_exp (byref_decl), false);
return byref_decl;
}
tree
build_block_ref_decl (tree name, tree decl)
{
struct c_scope *scope = current_scope;
tree ref_decl;
tree type, exp;
if (TREE_CODE (decl) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (decl))
decl = build_byref_local_var_access (decl, DECL_NAME (decl));
else {
if (cur_block->prev_block_info) {
struct block_sema_info *cb = cur_block->prev_block_info;
while (cb) {
struct c_binding *b = I_SYMBOL_BINDING (name);
while (b && b->decl
&& (TREE_CODE (b->decl) == VAR_DECL
|| TREE_CODE (b->decl) == PARM_DECL)
&& b->depth >= cur_block->the_scope->depth)
b = b->shadowed;
if (b && b->decl
&& (TREE_CODE (b->decl) == VAR_DECL
|| TREE_CODE (b->decl) == PARM_DECL)
&& b->depth < cb->the_scope->depth) {
struct c_scope *save_scope = current_scope;
struct block_sema_info *save_current_block = cur_block;
current_scope = cb->the_scope;
cur_block = cb;
decl = build_block_ref_decl (name, decl);
cur_block = save_current_block;
current_scope = save_scope;
}
cb = cb->prev_block_info;
}
}
}
exp = decl;
type = TREE_TYPE (exp);
if (TREE_CODE (type) == ARRAY_TYPE) {
exp = array_to_pointer_conversion (decl);
type = TREE_TYPE (exp);
}
else if (TREE_CODE (type) == FUNCTION_TYPE) {
exp = function_to_pointer_conversion (exp);
type = TREE_TYPE (exp);
}
ref_decl = build_decl (VAR_DECL, name,
build_qualified_type (type, TYPE_QUAL_CONST));
DECL_SOURCE_LOCATION (ref_decl) = DECL_SOURCE_LOCATION
(cur_block->helper_func_decl);
DECL_INITIAL (ref_decl) = error_mark_node;
c_apply_type_quals_to_decl (TYPE_QUAL_CONST, ref_decl);
BLOCK_DECL_COPIED (ref_decl) = 1;
while (scope && !scope->function_body)
scope = scope->outer;
gcc_assert (scope);
bind (name, ref_decl,
scope, false, false);
cur_block->block_ref_decl_list =
tree_cons (NULL_TREE, ref_decl, cur_block->block_ref_decl_list);
cur_block->block_original_ref_decl_list =
tree_cons (NULL_TREE, exp, cur_block->block_original_ref_decl_list);
return ref_decl;
}
static GTY (()) tree descriptor_ptr_type;
static GTY (()) tree descriptor_ptr_type_with_copydispose;
tree
build_block_descriptor_type (bool withCopyDispose)
{
tree field_decl_chain, field_decl;
tree main_type;
if (withCopyDispose && descriptor_ptr_type_with_copydispose)
return descriptor_ptr_type_with_copydispose;
if (!withCopyDispose && descriptor_ptr_type)
return descriptor_ptr_type;
main_type =
withCopyDispose ?
start_struct (RECORD_TYPE, get_identifier ("__block_descriptor_withcopydispose"))
: start_struct (RECORD_TYPE, get_identifier ("__block_descriptor"));
field_decl = build_decl (FIELD_DECL, get_identifier ("reserved"), long_unsigned_type_node);
field_decl_chain = field_decl;
field_decl = build_decl (FIELD_DECL, get_identifier ("Size"), long_unsigned_type_node);
chainon (field_decl_chain, field_decl);
if (withCopyDispose)
{
field_decl = build_decl (FIELD_DECL, get_identifier ("CopyFuncPtr"), ptr_type_node);
chainon (field_decl_chain, field_decl);
field_decl = build_decl (FIELD_DECL, get_identifier ("DestroyFuncPtr"), ptr_type_node);
chainon (field_decl_chain, field_decl);
}
field_decl = build_decl (FIELD_DECL, get_identifier ("signature"), build_pointer_type (char_type_node));
chainon (field_decl_chain, field_decl);
field_decl = build_decl (FIELD_DECL, get_identifier ("layout"), build_pointer_type (char_type_node));
chainon (field_decl_chain, field_decl);
TYPE_BLOCK_IMPL_STRUCT (main_type) = 1;
finish_struct (main_type, field_decl_chain, NULL_TREE);
main_type = build_pointer_type (main_type);
if (withCopyDispose)
descriptor_ptr_type_with_copydispose = main_type;
else
descriptor_ptr_type = main_type;
return main_type;
}
struct c_declarator *
make_block_pointer_declarator (struct c_declspecs *type_quals_attrs,
struct c_declarator *target)
{
int quals = 0;
struct c_declarator *itarget = target;
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
if (type_quals_attrs)
{
tree attrs = type_quals_attrs->attrs;
quals = quals_from_declspecs (type_quals_attrs);
if (attrs != NULL_TREE)
itarget = build_attrs_declarator (attrs, target);
}
ret->kind = cdk_block_pointer;
ret->declarator = itarget;
ret->u.pointer_quals = quals;
return ret;
}
tree
begin_block (void)
{
struct block_sema_info *csi;
#if 0
push_scope ();
#endif
csi = (struct block_sema_info*)xcalloc (1, sizeof (struct block_sema_info));
csi->prev_block_info = cur_block;
cur_block = csi;
return NULL_TREE;
}
struct block_sema_info *
finish_block (tree block __attribute__ ((__unused__)))
{
struct block_sema_info *csi = cur_block;
cur_block = cur_block->prev_block_info;
#if 0
pop_scope ();
#endif
return csi;
}
bool
in_imm_block (void)
{
return (cur_block && cur_block->the_scope == current_scope);
}
bool
lookup_name_in_block (tree name, tree *decl)
{
if (cur_block)
{
struct c_binding *b = I_SYMBOL_BINDING (name);
if (b->depth >= cur_block->the_scope->depth)
return true;
if (!cur_block->prev_block_info)
return false;
while (b && b->decl
&& (TREE_CODE (b->decl) == VAR_DECL)
&& BLOCK_DECL_BYREF (b->decl))
b = b->shadowed;
if (b && b->decl)
*decl = b->decl;
}
return false;
}
static struct c_scope *save_current_scope;
static tree save_current_function_decl;
void
push_to_top_level (void)
{
save_current_scope = current_scope;
save_current_function_decl = current_function_decl;
current_scope = file_scope;
current_function_decl = NULL_TREE;
}
void
pop_from_top_level (void)
{
current_scope = save_current_scope;
current_function_decl = save_current_function_decl;
}
tree
build_helper_func_decl (tree ident, tree type)
{
tree func_decl = build_decl (FUNCTION_DECL, ident, type);
DECL_EXTERNAL (func_decl) = 0;
TREE_PUBLIC (func_decl) = 0;
TREE_USED (func_decl) = 1;
TREE_NOTHROW (func_decl) = 0;
BLOCK_SYNTHESIZED_FUNC (func_decl) = 1;
return func_decl;
}
void
start_block_helper_function (tree decl1)
{
struct c_label_context_se *nstack_se;
struct c_label_context_vm *nstack_vm;
tree restype, resdecl;
current_function_returns_value = 0;
current_function_returns_null = 0;
current_function_returns_abnormally = 0;
warn_about_return_type = 0;
c_switch_stack = NULL;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack_se->labels_def = NULL;
nstack_se->labels_used = NULL;
nstack_se->next = label_context_stack_se;
label_context_stack_se = nstack_se;
nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack_vm->labels_def = NULL;
nstack_vm->labels_used = NULL;
nstack_vm->scope = 0;
nstack_vm->next = label_context_stack_vm;
label_context_stack_vm = nstack_vm;
c_break_label = c_cont_label = size_zero_node;
announce_function (decl1);
DECL_INITIAL (decl1) = error_mark_node;
current_function_prototype_locus = UNKNOWN_LOCATION;
current_function_prototype_built_in = false;
current_function_prototype_arg_types = NULL_TREE;
TREE_STATIC (decl1) = 1;
TREE_PUBLIC (decl1) = 0;
gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1));
current_function_decl = pushdecl (decl1);
record_func_cl_pf_opts_mapping (current_function_decl);
push_scope ();
declare_parm_level ();
restype = TREE_TYPE (TREE_TYPE (current_function_decl));
resdecl = build_decl (RESULT_DECL, NULL_TREE, restype);
DECL_ARTIFICIAL (resdecl) = 1;
DECL_IGNORED_P (resdecl) = 1;
DECL_RESULT (current_function_decl) = resdecl;
start_fname_decls ();
}
static void
declare_block_prologue_local_vars (tree self_parm, tree component,
tree stmt)
{
tree decl, block_component;
tree_stmt_iterator i;
tree decl_stmt;
decl = component;
block_component = build_component_ref (build_indirect_ref (self_parm, "->"),
DECL_NAME (component));
gcc_assert (block_component);
DECL_EXTERNAL (decl) = 0;
TREE_STATIC (decl) = 0;
TREE_USED (decl) = 1;
DECL_CONTEXT (decl) = current_function_decl;
DECL_ARTIFICIAL (decl) = 1;
DECL_INITIAL (decl) = block_component;
i = tsi_start (stmt);
decl_stmt = build_stmt (DECL_EXPR, decl);
SET_EXPR_LOCATION (decl_stmt, DECL_SOURCE_LOCATION (decl));
EXPR_LINENO (decl_stmt) = DECL_SOURCE_LINE (decl) - 1;
tsi_link_before (&i, decl_stmt, TSI_SAME_STMT);
}
void
block_build_prologue (struct block_sema_info *block_impl)
{
tree chain;
tree self_parm = lookup_name (get_identifier (".block_descriptor"));
gcc_assert (self_parm);
for (chain = block_impl->block_ref_decl_list; chain;
chain = TREE_CHAIN (chain))
declare_block_prologue_local_vars (self_parm, TREE_VALUE (chain),
block_impl->block_body);
for (chain = block_impl->block_byref_decl_list; chain;
chain = TREE_CHAIN (chain))
declare_block_prologue_local_vars (self_parm, TREE_VALUE (chain),
block_impl->block_body);
}
struct c_declspecs *
build_null_declspecs (void)
{
struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs);
ret->type = 0;
ret->decl_attr = 0;
ret->attrs = 0;
ret->typespec_word = cts_none;
ret->storage_class = csc_none;
ret->declspecs_seen_p = false;
ret->type_seen_p = false;
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->unavailable_p = false;
ret->default_int_p = false;
ret->long_p = false;
ret->long_long_p = false;
ret->short_p = false;
ret->signed_p = false;
ret->unsigned_p = false;
ret->complex_p = false;
ret->inline_p = false;
ret->thread_p = false;
ret->const_p = false;
ret->volatile_p = false;
ret->restrict_p = false;
ret->iasm_asm_specbit = false;
ret->private_extern_p = false;
return ret;
}
struct c_declspecs *
declspecs_add_qual (struct c_declspecs *specs, tree qual)
{
enum rid i;
bool dupe = false;
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE
&& C_IS_RESERVED_WORD (qual));
i = C_RID_CODE (qual);
switch (i)
{
case RID_CONST:
dupe = specs->const_p;
specs->const_p = true;
break;
case RID_VOLATILE:
dupe = specs->volatile_p;
specs->volatile_p = true;
break;
case RID_RESTRICT:
dupe = specs->restrict_p;
specs->restrict_p = true;
break;
default:
gcc_unreachable ();
}
if (dupe && pedantic && !flag_isoc99)
pedwarn ("duplicate %qE", qual);
return specs;
}
struct c_declspecs *
declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
{
tree type = spec.spec;
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
specs->type_seen_p = true;
if (TREE_DEPRECATED (type))
specs->deprecated_p = true;
if (TREE_UNAVAILABLE (type))
specs->unavailable_p = true;
if (TREE_CODE (type) == IDENTIFIER_NODE && C_IS_RESERVED_WORD (type))
{
enum rid i = C_RID_CODE (type);
if (specs->type)
{
error ("two or more data types in declaration specifiers");
return specs;
}
if ((int) i <= (int) RID_LAST_MODIFIER)
{
bool dupe = false;
switch (i)
{
case RID_LONG:
if (specs->long_long_p)
{
error ("%<long long long%> is too long for GCC");
break;
}
if (specs->long_p)
{
if (specs->typespec_word == cts_double)
{
error ("both %<long long%> and %<double%> in "
"declaration specifiers");
break;
}
if (pedantic && !flag_isoc99 && !in_system_header
&& warn_long_long)
pedwarn ("ISO C90 does not support %<long long%>");
specs->long_long_p = 1;
break;
}
if (specs->short_p)
error ("both %<long%> and %<short%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_void)
error ("both %<long%> and %<void%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_bool)
error ("both %<long%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_char)
error ("both %<long%> and %<char%> in "
"declaration specifiers");
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;
case RID_SHORT:
dupe = specs->short_p;
if (specs->long_p)
error ("both %<long%> and %<short%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_void)
error ("both %<short%> and %<void%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_bool)
error ("both %<short%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_char)
error ("both %<short%> and %<char%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_float)
error ("both %<short%> and %<float%> in "
"declaration specifiers");
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;
case RID_SIGNED:
dupe = specs->signed_p;
if (specs->unsigned_p)
error ("both %<signed%> and %<unsigned%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_void)
error ("both %<signed%> and %<void%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_bool)
error ("both %<signed%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_float)
error ("both %<signed%> and %<float%> in "
"declaration specifiers");
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;
case RID_UNSIGNED:
dupe = specs->unsigned_p;
if (specs->signed_p)
error ("both %<signed%> and %<unsigned%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_void)
error ("both %<unsigned%> and %<void%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_bool)
error ("both %<unsigned%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->typespec_word == cts_float)
error ("both %<unsigned%> and %<float%> in "
"declaration specifiers");
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;
case RID_COMPLEX:
dupe = specs->complex_p;
if (pedantic && !flag_isoc99 && !in_system_header)
pedwarn ("ISO C90 does not support complex types");
if (specs->typespec_word == cts_void)
error ("both %<complex%> and %<void%> in "
"declaration specifiers");
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;
default:
gcc_unreachable ();
}
if (dupe)
error ("duplicate %qE", type);
return specs;
}
else
{
if (specs->typespec_word != cts_none)
{
error ("two or more data types in declaration specifiers");
return specs;
}
switch (i)
{
case RID_VOID:
if (specs->long_p)
error ("both %<long%> and %<void%> in "
"declaration specifiers");
else if (specs->short_p)
error ("both %<short%> and %<void%> in "
"declaration specifiers");
else if (specs->signed_p)
error ("both %<signed%> and %<void%> in "
"declaration specifiers");
else if (specs->unsigned_p)
error ("both %<unsigned%> and %<void%> in "
"declaration specifiers");
else if (specs->complex_p)
error ("both %<complex%> and %<void%> in "
"declaration specifiers");
else
specs->typespec_word = cts_void;
return specs;
case RID_BOOL:
if (specs->long_p)
error ("both %<long%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->short_p)
error ("both %<short%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->signed_p)
error ("both %<signed%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->unsigned_p)
error ("both %<unsigned%> and %<_Bool%> in "
"declaration specifiers");
else if (specs->complex_p)
error ("both %<complex%> and %<_Bool%> in "
"declaration specifiers");
else
specs->typespec_word = cts_bool;
return specs;
case RID_CHAR:
if (specs->long_p)
error ("both %<long%> and %<char%> in "
"declaration specifiers");
else if (specs->short_p)
error ("both %<short%> and %<char%> in "
"declaration specifiers");
else
specs->typespec_word = cts_char;
return specs;
case RID_INT:
specs->typespec_word = cts_int;
return specs;
case RID_FLOAT:
if (specs->long_p)
error ("both %<long%> and %<float%> in "
"declaration specifiers");
else if (specs->short_p)
error ("both %<short%> and %<float%> in "
"declaration specifiers");
else if (specs->signed_p)
error ("both %<signed%> and %<float%> in "
"declaration specifiers");
else if (specs->unsigned_p)
error ("both %<unsigned%> and %<float%> in "
"declaration specifiers");
else
specs->typespec_word = cts_float;
return specs;
case RID_DOUBLE:
if (specs->long_long_p)
error ("both %<long long%> and %<double%> in "
"declaration specifiers");
else if (specs->short_p)
error ("both %<short%> and %<double%> in "
"declaration specifiers");
else if (specs->signed_p)
error ("both %<signed%> and %<double%> in "
"declaration specifiers");
else if (specs->unsigned_p)
error ("both %<unsigned%> and %<double%> in "
"declaration specifiers");
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:
break;
}
}
}
if (specs->type || specs->typespec_word != cts_none
|| specs->long_p || specs->short_p || specs->signed_p
|| specs->unsigned_p || specs->complex_p)
error ("two or more data types in declaration specifiers");
else if (TREE_CODE (type) == TYPE_DECL)
{
if (TREE_TYPE (type) == error_mark_node)
;
else
{
specs->type = TREE_TYPE (type);
specs->decl_attr = DECL_ATTRIBUTES (type);
specs->typedef_p = true;
specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type);
}
}
else if (TREE_CODE (type) == IDENTIFIER_NODE)
{
tree t = lookup_name (type);
if (!t || TREE_CODE (t) != TYPE_DECL)
error ("%qE fails to be a typedef or built in type", type);
else if (TREE_TYPE (t) == error_mark_node)
;
else
specs->type = TREE_TYPE (t);
}
else if (TREE_CODE (type) != ERROR_MARK)
{
if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
specs->tag_defined_p = true;
if (spec.kind == ctsk_typeof)
specs->typedef_p = true;
specs->type = type;
}
return specs;
}
struct c_declspecs *
declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
{
enum rid i;
enum c_storage_class n = csc_none;
bool dupe = false;
specs->declspecs_seen_p = true;
gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
&& C_IS_RESERVED_WORD (scspec));
i = C_RID_CODE (scspec);
if (extra_warnings && specs->non_sc_seen_p)
warning (OPT_Wextra, "%qE is not at beginning of declaration", scspec);
switch (i)
{
case RID_ASM:
dupe = specs->iasm_asm_specbit;
specs->iasm_asm_specbit = true;
break;
case RID_INLINE:
dupe = false;
specs->inline_p = true;
break;
case RID_THREAD:
dupe = specs->thread_p;
if (specs->storage_class == csc_auto)
error ("%<__thread%> used with %<auto%>");
else if (specs->storage_class == csc_register)
error ("%<__thread%> used with %<register%>");
else if (specs->storage_class == csc_typedef)
error ("%<__thread%> used with %<typedef%>");
else
specs->thread_p = true;
break;
case RID_AUTO:
n = csc_auto;
break;
case RID_EXTERN:
n = csc_extern;
if (specs->thread_p)
error ("%<__thread%> before %<extern%>");
break;
case RID_PRIVATE_EXTERN:
specs->private_extern_p = true;
n = csc_extern;
if (specs->thread_p)
error ("%<__thread%> before %<private_extern%>");
break;
case RID_REGISTER:
n = csc_register;
break;
case RID_STATIC:
n = csc_static;
if (specs->thread_p)
error ("%<__thread%> before %<static%>");
break;
case RID_TYPEDEF:
n = csc_typedef;
break;
default:
gcc_unreachable ();
}
if (n != csc_none && n == specs->storage_class)
dupe = true;
if (dupe)
error ("duplicate %qE", scspec);
if (n != csc_none)
{
if (specs->storage_class != csc_none && n != specs->storage_class)
{
error ("multiple storage classes in declaration specifiers");
}
else
{
specs->storage_class = n;
if (n != csc_extern && n != csc_static && specs->thread_p)
{
error ("%<__thread%> used with %qE", scspec);
specs->thread_p = false;
}
}
}
return specs;
}
struct c_declspecs *
declspecs_add_attrs (struct c_declspecs *specs, tree attrs)
{
specs->attrs = chainon (attrs, specs->attrs);
specs->declspecs_seen_p = true;
return specs;
}
struct c_declspecs *
finish_declspecs (struct c_declspecs *specs)
{
if (specs->type != NULL_TREE)
{
gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p
&& !specs->signed_p && !specs->unsigned_p
&& !specs->complex_p);
return specs;
}
if (specs->typespec_word == cts_none)
{
if (specs->long_p || specs->short_p
|| specs->signed_p || specs->unsigned_p)
{
specs->typespec_word = cts_int;
}
else if (specs->complex_p)
{
specs->typespec_word = cts_double;
if (pedantic)
pedwarn ("ISO C does not support plain %<complex%> meaning "
"%<double complex%>");
}
else
{
specs->typespec_word = cts_int;
specs->default_int_p = true;
}
}
specs->explicit_signed_p = specs->signed_p;
switch (specs->typespec_word)
{
case cts_void:
gcc_assert (!specs->long_p && !specs->short_p
&& !specs->signed_p && !specs->unsigned_p
&& !specs->complex_p);
specs->type = void_type_node;
break;
case cts_bool:
gcc_assert (!specs->long_p && !specs->short_p
&& !specs->signed_p && !specs->unsigned_p
&& !specs->complex_p);
specs->type = boolean_type_node;
break;
case cts_char:
gcc_assert (!specs->long_p && !specs->short_p);
gcc_assert (!(specs->signed_p && specs->unsigned_p));
if (specs->signed_p)
specs->type = signed_char_type_node;
else if (specs->unsigned_p)
specs->type = unsigned_char_type_node;
else
specs->type = char_type_node;
if (specs->complex_p)
{
if (pedantic)
pedwarn ("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));
if (specs->long_long_p)
specs->type = (specs->unsigned_p
? long_long_unsigned_type_node
: long_long_integer_type_node);
else if (specs->long_p)
specs->type = (specs->unsigned_p
? long_unsigned_type_node
: long_integer_type_node);
else if (specs->short_p)
specs->type = (specs->unsigned_p
? short_unsigned_type_node
: short_integer_type_node);
else
specs->type = (specs->unsigned_p
? unsigned_type_node
: integer_type_node);
if (specs->complex_p)
{
if (pedantic)
pedwarn ("ISO C does not support complex integer types");
specs->type = build_complex_type (specs->type);
}
break;
case cts_float:
gcc_assert (!specs->long_p && !specs->short_p
&& !specs->signed_p && !specs->unsigned_p);
specs->type = (specs->complex_p
? complex_float_type_node
: float_type_node);
break;
case cts_double:
gcc_assert (!specs->long_long_p && !specs->short_p
&& !specs->signed_p && !specs->unsigned_p);
if (specs->long_p)
{
specs->type = (specs->complex_p
? complex_long_double_type_node
: long_double_type_node);
}
else
{
specs->type = (specs->complex_p
? complex_double_type_node
: 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 ();
}
return specs;
}
static void
build_cdtor (int method_type, tree cdtors)
{
tree body = 0;
if (!cdtors)
return;
for (; cdtors; cdtors = TREE_CHAIN (cdtors))
append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0),
&body);
cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
}
static void
c_write_global_declarations_1 (tree globals)
{
tree decl;
bool reconsider;
for (decl = globals; decl; decl = TREE_CHAIN (decl))
{
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INITIAL (decl) == 0
&& DECL_EXTERNAL (decl)
&& !TREE_PUBLIC (decl)
&& C_DECL_USED (decl))
{
pedwarn ("%q+F used but never defined", decl);
TREE_NO_WARNING (decl) = 1;
}
wrapup_global_declaration_1 (decl);
}
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);
}
static void
c_write_global_declarations_2 (tree globals)
{
tree decl;
for (decl = globals; decl ; decl = TREE_CHAIN (decl))
debug_hooks->global_decl (decl);
}
static GTY(()) tree ext_block;
void
c_write_global_declarations (void)
{
tree t;
if (pch_file)
return;
if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in))
return;
ext_block = pop_scope ();
external_scope = 0;
gcc_assert (!current_scope);
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);
}
}
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));
build_cdtor ('I', static_ctors); static_ctors = 0;
build_cdtor ('D', static_dtors); static_dtors = 0;
cgraph_optimize ();
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;
}
tree
lookup_struct_or_union_tag (tree typename)
{
tree rslt = lookup_tag (RECORD_TYPE, typename, 0);
pending_invalid_xref = 0;
if (!rslt)
rslt = lookup_tag (UNION_TYPE, typename, 0);
pending_invalid_xref = 0;
return rslt;
}
tree
c_return_interface_record_type (tree typename)
{
enum tree_code_class class;
enum tree_code code;
tree retval = NULL;
if (typename == NULL)
return retval;
code = TREE_CODE (typename);
class = TREE_CODE_CLASS (code);
if (code != IDENTIFIER_NODE
|| class != tcc_exceptional)
return retval;
retval = I_TAG_DECL (typename);
if (TREE_CODE (retval) != RECORD_TYPE)
retval = NULL;
return retval;
}
#include "gt-c-decl.h"