/* Process declarations and variables for C compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
#include "langhooks-def.h"
#include "pointer-set.h"
#include "gimple.h"
+#include "plugin.h"
/* In grokdeclarator, distinguish syntactic contexts of declarators. */
enum decl_context
tree c_break_label;
tree c_cont_label;
+/* True if we are currently parsing the fields of a struct or
+ union. */
+
+static bool in_struct;
+
+/* A list of types defined in the current struct or union. */
+
+static VEC(tree,heap) *struct_types;
+
/* Linked list of TRANSLATION_UNIT_DECLS for the translation units
included in this invocation. Note that the current translation
unit is not included in this list. */
in all such cases, the binding in the outer scope will have its
invisible bit true. */
-struct c_binding GTY((chain_next ("%h.prev")))
-{
+struct GTY((chain_next ("%h.prev"))) c_binding {
tree decl; /* the decl bound */
tree type; /* the type in this scope */
tree id; /* the identifier it's bound to */
BOOL_BITFIELD nested : 1; /* do not set DECL_CONTEXT when popping */
BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */
/* one free bit */
+ location_t locus; /* location for nested bindings */
};
#define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth)
#define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth)
These describe the values of the identifier in the three different
namespaces defined by the language. */
-struct lang_identifier GTY(())
-{
+struct GTY(()) lang_identifier {
struct c_common_identifier common_id;
struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */
struct c_binding *tag_binding; /* struct/union/enum tags */
/* The resulting tree type. */
-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 GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+ chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *) TYPE_NEXT_VARIANT (&%h.generic) : ((union lang_tree_node *) TREE_CHAIN (&%h.generic))"))) lang_tree_node
+ {
union tree_node GTY ((tag ("0"),
desc ("tree_node_structure (&%h)")))
generic;
pop_scope relies on this. */
-struct c_scope GTY((chain_next ("%h.outer")))
-{
+struct GTY((chain_next ("%h.outer"))) c_scope {
/* The scope containing this one. */
struct c_scope *outer;
/* True means make a BLOCK for this scope no matter what. */
BOOL_BITFIELD keep : 1;
+
+ /* True means that an unsuffixed float constant is _Decimal64. */
+ BOOL_BITFIELD float_const_decimal64 : 1;
};
/* The scope currently in effect. */
t_->to##_last = f_->from##_last; \
} while (0)
+/* A c_inline_static structure stores details of a static identifier
+ referenced in a definition of a function that may be an inline
+ definition if no subsequent declaration of that function uses
+ "extern" or does not use "inline". */
+
+struct GTY((chain_next ("%h.next"))) c_inline_static {
+ /* The location for a diagnostic. */
+ location_t location;
+
+ /* The function that may be an inline definition. */
+ tree function;
+
+ /* The object or function referenced. */
+ tree static_decl;
+
+ /* What sort of reference this is. */
+ enum c_inline_static_type type;
+
+ /* The next such structure or NULL. */
+ struct c_inline_static *next;
+};
+
+/* List of static identifiers used or referenced in functions that may
+ be inline definitions. */
+static GTY(()) struct c_inline_static *c_inline_statics;
+
/* True means unconditionally make a BLOCK for the next scope pushed. */
static bool keep_next_level_flag;
static tree c_make_fname_decl (tree, int);
static tree grokdeclarator (const struct c_declarator *,
struct c_declspecs *,
- enum decl_context, bool, tree *, tree *,
- enum deprecated_states);
+ enum decl_context, bool, tree *, tree *, tree *,
+ bool *, enum deprecated_states);
static tree grokparms (struct c_arg_info *, bool);
static void layout_array_type (tree);
\f
which may be any of several kinds of DECL or TYPE or error_mark_node,
in the scope SCOPE. */
static void
-bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested)
+bind (tree name, tree decl, struct c_scope *scope, bool invisible,
+ bool nested, location_t locus)
{
struct c_binding *b, **here;
b->invisible = invisible;
b->nested = nested;
b->inner_comp = 0;
+ b->locus = locus;
b->type = 0;
}
}
\f
+/* Record that inline function FUNC contains a reference (location
+ LOC) to static DECL (file-scope or function-local according to
+ TYPE). */
+
+void
+record_inline_static (location_t loc, tree func, tree decl,
+ enum c_inline_static_type type)
+{
+ struct c_inline_static *csi = GGC_NEW (struct c_inline_static);
+ csi->location = loc;
+ csi->function = func;
+ csi->static_decl = decl;
+ csi->type = type;
+ csi->next = c_inline_statics;
+ c_inline_statics = csi;
+}
+
+/* Check for references to static declarations in inline functions at
+ the end of the translation unit and diagnose them if the functions
+ are still inline definitions. */
+
+static void
+check_inline_statics (void)
+{
+ struct c_inline_static *csi;
+ for (csi = c_inline_statics; csi; csi = csi->next)
+ {
+ if (DECL_EXTERNAL (csi->function))
+ switch (csi->type)
+ {
+ case csi_internal:
+ pedwarn (csi->location, 0,
+ "%qD is static but used in inline function %qD "
+ "which is not static", csi->static_decl, csi->function);
+ break;
+ case csi_modifiable:
+ pedwarn (csi->location, 0,
+ "%q+D is static but declared in inline function %qD "
+ "which is not static", csi->static_decl, csi->function);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ c_inline_statics = NULL;
+}
+\f
/* The Objective-C front-end often needs to determine the current scope. */
void *
int
global_bindings_p (void)
{
- return current_scope == file_scope && !c_override_global_bindings_to_false;
+ return (current_scope == file_scope && !c_override_global_bindings_to_false
+ ? -1
+ : 0);
}
void
keep_next_level_flag = true;
}
+/* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON. */
+
+void
+set_float_const_decimal64 (void)
+{
+ current_scope->float_const_decimal64 = true;
+}
+
+/* Clear the flag for the FLOAT_CONST_DECIMAL64 pragma. */
+
+void
+clear_float_const_decimal64 (void)
+{
+ current_scope->float_const_decimal64 = false;
+}
+
+/* Return nonzero if an unsuffixed float constant is _Decimal64. */
+
+bool
+float_const_decimal64_p (void)
+{
+ return current_scope->float_const_decimal64;
+}
+
/* Identify this scope as currently being filled with parameters. */
void
keep_next_level_flag = false;
next_is_function_body = false;
+
+ /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */
+ if (current_scope->outer)
+ current_scope->float_const_decimal64
+ = current_scope->outer->float_const_decimal64;
+ else
+ current_scope->float_const_decimal64 = false;
}
else
{
else
scope = GGC_CNEW (struct c_scope);
+ /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes. */
+ if (current_scope)
+ scope->float_const_decimal64 = current_scope->float_const_decimal64;
+ else
+ scope->float_const_decimal64 = false;
+
scope->keep = keep_next_level_flag;
scope->outer = current_scope;
scope->depth = current_scope ? (current_scope->depth + 1) : 0;
error ("nested function %q+D declared but never defined", p);
undef_nested_function = true;
}
- /* C99 6.7.4p6: "a function with external linkage... declared
- with an inline function specifier ... shall also be defined in the
- same translation unit." */
else if (DECL_DECLARED_INLINE_P (p)
&& TREE_PUBLIC (p)
- && !DECL_INITIAL (p)
- && !flag_gnu89_inline)
- pedwarn (input_location, 0, "inline function %q+D declared but never defined", p);
+ && !DECL_INITIAL (p))
+ {
+ /* C99 6.7.4p6: "a function with external linkage... declared
+ with an inline function specifier ... shall also be defined
+ in the same translation unit." */
+ if (!flag_gnu89_inline)
+ pedwarn (input_location, 0,
+ "inline function %q+D declared but never defined", p);
+ DECL_EXTERNAL (p) = 1;
+ }
goto common_symbol;
TREE_CHAIN (p) = BLOCK_VARS (block);
BLOCK_VARS (block) = p;
}
+ else if (VAR_OR_FUNCTION_DECL_P (p))
+ {
+ /* For block local externs add a special
+ DECL_EXTERNAL decl for debug info generation. */
+ tree extp = copy_node (p);
+
+ DECL_EXTERNAL (extp) = 1;
+ TREE_STATIC (extp) = 0;
+ TREE_PUBLIC (extp) = 1;
+ DECL_INITIAL (extp) = NULL_TREE;
+ DECL_LANG_SPECIFIC (extp) = NULL;
+ DECL_CONTEXT (extp) = current_function_decl;
+ if (TREE_CODE (p) == FUNCTION_DECL)
+ {
+ DECL_RESULT (extp) = NULL_TREE;
+ DECL_SAVED_TREE (extp) = NULL_TREE;
+ DECL_STRUCT_FUNCTION (extp) = NULL;
+ }
+ if (b->locus != UNKNOWN_LOCATION)
+ DECL_SOURCE_LOCATION (extp) = b->locus;
+ TREE_CHAIN (extp) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = extp;
+ }
/* If this is the file scope, and we are processing more
than one translation unit in this compilation, set
DECL_CONTEXT of each decl to the TRANSLATION_UNIT_DECL.
for (decl = visible_builtins; decl; decl = TREE_CHAIN (decl))
bind (DECL_NAME (decl), decl, file_scope,
- /*invisible=*/false, /*nested=*/true);
+ /*invisible=*/false, /*nested=*/true, DECL_SOURCE_LOCATION (decl));
}
void
still works without it. */
finish_fname_decls ();
+ check_inline_statics ();
+
/* This is the point to write out a PCH if we're doing that.
In that case we do not want to do anything else. */
if (pch_file)
In that case, the TYPE_SIZE will be zero. */
static void
-pushtag (tree name, tree type)
+pushtag (tree name, tree type, location_t loc)
{
/* Record the identifier as the type's name if it has none. */
if (name && !TYPE_NAME (type))
TYPE_NAME (type) = name;
- bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false);
+ bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false, loc);
/* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the
tagged type we just added to the current scope. This fake
throw it away, in case it was inlined into a function that
hasn't been written out yet. */
if (new_is_definition && DECL_INITIAL (olddecl))
- {
- if (TREE_USED (olddecl)
- /* We never inline re-defined extern inline functions.
- FIXME: This would be better handled by keeping both functions
- as separate declarations. */
- && cgraph_function_possibly_inlined_p (olddecl))
- (*debug_hooks->outlining_inline_function) (olddecl);
-
- /* The new defn must not be inline. */
- DECL_UNINLINABLE (newdecl) = 1;
- }
+ /* The new defn must not be inline. */
+ DECL_UNINLINABLE (newdecl) = 1;
else
{
/* If either decl says `inline', this fn is inline, unless
/* Also preserve various other info from the definition. */
if (!new_is_definition)
{
+ tree t;
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);
gimple_set_body (newdecl, gimple_body (olddecl));
- DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+ DECL_ARGUMENTS (newdecl) = copy_list (DECL_ARGUMENTS (olddecl));
+ for (t = DECL_ARGUMENTS (newdecl); t ; t = TREE_CHAIN (t))
+ DECL_CONTEXT (t) = newdecl;
/* See if we've got a function to instantiate from. */
if (DECL_SAVED_TREE (olddecl))
{
unsigned olddecl_uid = DECL_UID (olddecl);
tree olddecl_context = DECL_CONTEXT (olddecl);
+ tree olddecl_arguments = NULL;
+ if (TREE_CODE (olddecl) == FUNCTION_DECL)
+ olddecl_arguments = DECL_ARGUMENTS (olddecl);
memcpy ((char *) olddecl + sizeof (struct tree_common),
(char *) newdecl + sizeof (struct tree_common),
}
DECL_UID (olddecl) = olddecl_uid;
DECL_CONTEXT (olddecl) = olddecl_context;
+ if (TREE_CODE (olddecl) == FUNCTION_DECL)
+ DECL_ARGUMENTS (olddecl) = olddecl_arguments;
}
/* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl
}
}
-
-/* Subroutine of pushdecl.
-
- X is a TYPE_DECL for a typedef statement. Create a brand new
- ..._TYPE node (which will be just a variant of the existing
- ..._TYPE node with identical properties) and then install X
- as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
- The whole point here is to end up with a situation where each
- and every ..._TYPE node the compiler creates will be uniquely
- associated with AT MOST one node representing a typedef name.
- This way, even though the compiler substitutes corresponding
- ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
- early on, later parts of the compiler can always do the reverse
- translation and get back the corresponding typedef name. For
- example, given:
-
- typedef struct S MY_TYPE;
- MY_TYPE object;
-
- Later parts of the compiler might only know that `object' was of
- type `struct S' if it were not for code just below. With this
- code however, later parts of the compiler see something like:
-
- struct S' == struct S
- typedef struct S' MY_TYPE;
- struct S' object;
-
- And they can then deduce (from the node for type struct S') that
- the original object declaration was:
-
- MY_TYPE object;
-
- Being able to do this is important for proper support of protoize,
- and also for generating precise symbolic debugging information
- which takes full account of the programmer's (typedef) vocabulary.
-
- Obviously, we don't want to generate a duplicate ..._TYPE node if
- the TYPE_DECL node that we are now processing really represents a
- standard built-in type. */
-
-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;
- }
-}
-
/* Record a decl-node X as belonging to the current lexical scope.
Check for errors (such as an incompatible declaration for the same
name already seen in the same scope).
struct c_scope *scope = current_scope;
struct c_binding *b;
bool nested = false;
+ location_t locus = DECL_SOURCE_LOCATION (x);
/* Must set DECL_CONTEXT for everything not at file scope or
DECL_FILE_SCOPE_P won't work. Local externs don't count
/* Anonymous decls are just inserted in the scope. */
if (!name)
{
- bind (name, x, scope, /*invisible=*/false, /*nested=*/false);
+ bind (name, x, scope, /*invisible=*/false, /*nested=*/false,
+ locus);
return x;
}
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES (b->type));
TREE_TYPE (b->decl) = thistype;
- bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true);
+ bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true,
+ locus);
return b->decl;
}
else if (TREE_PUBLIC (x))
else
{
bind (name, x, external_scope, /*invisible=*/true,
- /*nested=*/false);
+ /*nested=*/false, locus);
nested = true;
}
}
skip_external_and_shadow_checks:
if (TREE_CODE (x) == TYPE_DECL)
- clone_underlying_type (x);
+ set_underlying_type (x);
- bind (name, x, scope, /*invisible=*/false, nested);
+ bind (name, x, scope, /*invisible=*/false, nested, locus);
/* If x's type is incomplete because it's based on a
structure or union which has not yet been fully declared,
if (TREE_PUBLIC (x))
{
- bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false);
+ bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false,
+ UNKNOWN_LOCATION);
nested = true;
}
if (file_scope)
- bind (name, x, file_scope, /*invisible=*/false, nested);
+ bind (name, x, file_scope, /*invisible=*/false, nested, UNKNOWN_LOCATION);
return x;
}
if (!DECL_BUILT_IN (decl) && DECL_IS_BUILTIN (decl))
{
bind (functionid, decl, file_scope,
- /*invisible=*/false, /*nested=*/true);
+ /*invisible=*/false, /*nested=*/true,
+ DECL_SOURCE_LOCATION (decl));
return decl;
}
else
b->type = TREE_TYPE (decl);
TREE_TYPE (decl) = newtype;
bind (functionid, decl, current_scope,
- /*invisible=*/false, /*nested=*/true);
+ /*invisible=*/false, /*nested=*/true,
+ DECL_SOURCE_LOCATION (decl));
return decl;
}
}
will be nonnull but current_function_scope will be null. */
scope = current_function_scope ? current_function_scope : current_scope;
}
- bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false);
+ bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false,
+ UNKNOWN_LOCATION);
}
\f
/* Subroutine of lookup_label, declare_label, define_label: construct a
/* Ordinary labels go in the current function scope. */
bind (name, label, current_function_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
return label;
}
/* Declared labels go in the current scope. */
bind (name, label, current_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
return label;
}
/* Ordinary labels go in the current function scope. */
bind (name, label, current_function_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
}
if (!in_system_header && lookup_name (name))
If THISLEVEL_ONLY is nonzero, searches only the current_scope.
CODE says which kind of type the caller wants;
it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE.
+ If PLOC is not NULL and this returns non-null, it sets *PLOC to the
+ location where the tag was defined.
If the wrong kind of type is found, an error is reported. */
static tree
-lookup_tag (enum tree_code code, tree name, int thislevel_only)
+lookup_tag (enum tree_code code, tree name, int thislevel_only,
+ location_t *ploc)
{
struct c_binding *b = I_TAG_BINDING (name);
int thislevel = 0;
if (thislevel)
pending_xref_error ();
}
+
+ if (ploc != NULL)
+ *ploc = b->locus;
+
return b->decl;
}
{
DECL_CONTEXT (decl) = current_function_decl;
bind (id, decl, current_function_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
}
- finish_decl (decl, init, NULL_TREE);
+ finish_decl (decl, init, NULL_TREE, NULL_TREE);
return decl;
}
/* Should never be called on a symbol with a preexisting meaning. */
gcc_assert (!I_SYMBOL_BINDING (id));
- bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false);
+ bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false,
+ UNKNOWN_LOCATION);
/* Builtins in the implementation namespace are made visible without
needing to be explicitly declared. See push_file_scope. */
/* Should never be called on a symbol with a preexisting meaning. */
gcc_assert (!I_SYMBOL_BINDING (id));
- bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false);
+ bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false,
+ UNKNOWN_LOCATION);
/* Builtins in the implementation namespace are made visible without
needing to be explicitly declared. See push_file_scope. */
found_tag = true;
+ if (declspecs->restrict_p)
+ {
+ error ("invalid use of %<restrict%>");
+ warned = 1;
+ }
+
if (name == 0)
{
if (warned != 1 && code != ENUMERAL_TYPE)
else
{
pending_invalid_xref = 0;
- t = lookup_tag (code, name, 1);
+ t = lookup_tag (code, name, 1, NULL);
if (t == 0)
{
t = make_node (code);
- pushtag (name, t);
+ pushtag (name, t, input_location);
}
}
}
}
}
\f
-/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
+/* Decode a "typename", such as "int **", returning a ..._TYPE node.
+ Set *EXPR, if EXPR not NULL, to any expression to be evaluated
+ before the type name, and set *EXPR_CONST_OPERANDS, if
+ EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may
+ appear in a constant expression. */
tree
-groktypename (struct c_type_name *type_name)
+groktypename (struct c_type_name *type_name, tree *expr,
+ bool *expr_const_operands)
{
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, &attrs, DEPRECATED_NORMAL);
+ false, NULL, &attrs, expr, expr_const_operands,
+ DEPRECATED_NORMAL);
/* Apply attributes. */
decl_attributes (&type, attrs, 0);
{
tree decl;
tree tem;
+ tree expr = NULL_TREE;
enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
/* An object declared as __attribute__((deprecated)) suppresses
deprecated_state = DEPRECATED_SUPPRESS;
decl = grokdeclarator (declarator, declspecs,
- NORMAL, initialized, NULL, &attributes,
+ NORMAL, initialized, NULL, &attributes, &expr, NULL,
deprecated_state);
if (!decl)
return 0;
+ if (expr)
+ add_stmt (expr);
+
if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
warning (OPT_Wmain, "%q+D is usually a function", decl);
&& !TREE_READONLY (decl)
&& DECL_DECLARED_INLINE_P (current_function_decl)
&& DECL_EXTERNAL (current_function_decl))
- pedwarn (input_location, 0,
- "%q+D is static but declared in inline function %qD "
- "which is not static", decl, current_function_decl);
+ record_inline_static (input_location, current_function_decl,
+ decl, csi_modifiable);
/* Add this decl to the current scope.
TEM may equal DECL or it may be a previous decl of the same name. */
/* Finish processing of a declaration;
install its initial value.
+ If ORIGTYPE is not NULL_TREE, it is the original type of INIT.
If the length of an array type is not known before,
it must be determined now, from the initial value, or it is an error. */
void
-finish_decl (tree decl, tree init, tree asmspec_tree)
+finish_decl (tree decl, tree init, tree origtype, tree asmspec_tree)
{
tree type;
int was_incomplete = (DECL_SIZE (decl) == 0);
init = 0;
if (init)
- store_init_value (decl, init);
+ store_init_value (decl, init, origtype);
if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL
tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
tree cleanup_decl = lookup_name (cleanup_id);
tree cleanup;
+ VEC(tree,gc) *vec;
/* Build "cleanup(&decl)" for the destructor. */
cleanup = build_unary_op (input_location, ADDR_EXPR, decl, 0);
- cleanup = build_tree_list (NULL_TREE, cleanup);
- cleanup = build_function_call (cleanup_decl, cleanup);
+ vec = VEC_alloc (tree, gc, 1);
+ VEC_quick_push (tree, vec, cleanup);
+ cleanup = build_function_call_vec (cleanup_decl, vec, NULL);
+ VEC_free (tree, gc, vec);
/* Don't warn about decl unused; the cleanup uses it. */
TREE_USED (decl) = 1;
{
tree attrs = parm->attrs;
tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
- NULL, &attrs, DEPRECATED_NORMAL);
+ NULL, &attrs, NULL, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
tree decl;
decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
- &attrs, DEPRECATED_NORMAL);
+ &attrs, NULL, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
decl = pushdecl (decl);
- finish_decl (decl, NULL_TREE, NULL_TREE);
+ finish_decl (decl, NULL_TREE, NULL_TREE, NULL_TREE);
}
/* Mark all the parameter declarations to date as forward decls.
/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
literal, which may be an incomplete array type completed by the
initializer; INIT is a CONSTRUCTOR that initializes the compound
- literal. */
+ literal. NON_CONST is true if the initializers contain something
+ that cannot occur in a constant expression. */
tree
-build_compound_literal (tree type, tree init)
+build_compound_literal (tree type, tree init, bool non_const)
{
/* We do not use start_decl here because we have a type, not a declarator;
and do not use finish_decl because the decl should be stored inside
TREE_USED (decl) = 1;
TREE_TYPE (decl) = type;
TREE_READONLY (decl) = TYPE_READONLY (type);
- store_init_value (decl, init);
+ store_init_value (decl, init, NULL_TREE);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
{
rest_of_decl_compilation (decl, 1, 0);
}
+ if (non_const)
+ {
+ complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit);
+ C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1;
+ }
+
return complit;
}
+
+/* Check the type of a compound literal. Here we just check that it
+ is valid for C++. */
+
+void
+check_compound_literal_type (struct c_type_name *type_name, location_t loc)
+{
+ if (warn_cxx_compat && type_name->specs->tag_defined_p)
+ warning_at (loc, OPT_Wc___compat,
+ "defining a type in a compound literal is invalid in C++");
+}
\f
/* Determine whether TYPE is a structure with a flexible array member,
or a union containing such a structure (possibly recursively). */
/* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME,
replacing with appropriate values if they are invalid. */
static void
-check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
+check_bitfield_type_and_width (tree *type, tree *width, tree orig_name)
{
tree type_mv;
unsigned int max_width;
unsigned HOST_WIDE_INT w;
- const char *name = orig_name ? orig_name: _("<anonymous>");
+ const char *name = (orig_name
+ ? identifier_to_locale (IDENTIFIER_POINTER (orig_name))
+ : _("<anonymous>"));
/* Detect and ignore out of range field width and process valid
field widths. */
{
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)))
+ || w < tree_int_cst_min_precision (lt->enum_min, TYPE_UNSIGNED (*type))
+ || w < tree_int_cst_min_precision (lt->enum_max, TYPE_UNSIGNED (*type)))
warning (0, "%qs is narrower than values of its type", name);
}
}
/* Print warning about variable length array if necessary. */
static void
-warn_variable_length_array (const char *name, tree size)
+warn_variable_length_array (tree name, tree size)
{
int const_size = TREE_CONSTANT (size);
if (const_size)
{
if (name)
- pedwarn (input_location, OPT_Wvla, "ISO C90 forbids array %qs whose size "
+ pedwarn (input_location, OPT_Wvla,
+ "ISO C90 forbids array %qE whose size "
"can%'t be evaluated",
name);
else
else
{
if (name)
- pedwarn (input_location, OPT_Wvla, "ISO C90 forbids variable length array %qs",
+ pedwarn (input_location, OPT_Wvla,
+ "ISO C90 forbids variable length array %qE",
name);
else
pedwarn (input_location, OPT_Wvla, "ISO C90 forbids variable length array");
{
if (name)
warning (OPT_Wvla,
- "the size of array %qs can"
+ "the size of array %qE can"
"%'t be evaluated", name);
else
warning (OPT_Wvla,
{
if (name)
warning (OPT_Wvla,
- "variable length array %qs is used",
+ "variable length array %qE is used",
name);
else
warning (OPT_Wvla,
}
}
+/* Given a size SIZE that may not be a constant, return a SAVE_EXPR to
+ serve as the actual size-expression for a type or decl. This is
+ like variable_size in stor-layout.c, but we make global_bindings_p
+ return negative to avoid calls to that function from outside the
+ front end resulting in errors at file scope, then call this version
+ instead from front-end code. */
+
+static tree
+c_variable_size (tree size)
+{
+ tree save;
+
+ if (TREE_CONSTANT (size))
+ return size;
+
+ size = save_expr (size);
+
+ save = skip_simple_arithmetic (size);
+
+ if (cfun && cfun->dont_save_pending_sizes_p)
+ return size;
+
+ if (!global_bindings_p ())
+ put_pending_size (save);
+
+ return size;
+}
+
/* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
DECL_ATTRS points to the list of attributes that should be added to this
decl. Any nested attributes that belong on the decl itself will be
added to this list.
+ If EXPR is not NULL, any expressions that need to be evaluated as
+ part of evaluating variably modified types will be stored in *EXPR.
+ If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be
+ set to indicate whether operands in *EXPR can be used in constant
+ expressions.
DEPRECATED_STATE is a deprecated_states value indicating whether
deprecation warnings should be suppressed.
grokdeclarator (const struct c_declarator *declarator,
struct c_declspecs *declspecs,
enum decl_context decl_context, bool initialized, tree *width,
- tree *decl_attrs, enum deprecated_states deprecated_state)
+ tree *decl_attrs, tree *expr, bool *expr_const_operands,
+ enum deprecated_states deprecated_state)
{
tree type = declspecs->type;
bool threadp = declspecs->thread_p;
int restrictp;
int volatilep;
int type_quals = TYPE_UNQUALIFIED;
- const char *name, *orig_name;
+ tree name = NULL_TREE;
bool funcdef_flag = false;
bool funcdef_syntax = false;
int size_varies = 0;
bool bitfield = width != NULL;
tree element_type;
struct c_arg_info *arg_info = 0;
+ tree expr_dummy;
+ bool expr_const_operands_dummy;
+
+ if (expr == NULL)
+ expr = &expr_dummy;
+ if (expr_const_operands == NULL)
+ expr_const_operands = &expr_const_operands_dummy;
+
+ *expr = declspecs->expr;
+ *expr_const_operands = declspecs->expr_const_operands;
if (decl_context == FUNCDEF)
funcdef_flag = true, decl_context = NORMAL;
/* Look inside a declarator for the name being declared
- and get it as a string, for an error message. */
+ and get it as an IDENTIFIER_NODE, for an error message. */
{
const struct c_declarator *decl = declarator;
- name = 0;
while (decl)
switch (decl->kind)
case cdk_id:
if (decl->u.id)
- name = IDENTIFIER_POINTER (decl->u.id);
+ name = decl->u.id;
decl = 0;
break;
default:
gcc_unreachable ();
}
- orig_name = name;
if (name == 0)
- name = "type name";
+ {
+ gcc_assert (decl_context == PARM
+ || decl_context == TYPENAME
+ || (decl_context == FIELD
+ && declarator->kind == cdk_id));
+ gcc_assert (!initialized);
+ }
}
/* A function definition's declarator must have the form of
decl_context = PARM;
if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS)
- warn_deprecated_use (declspecs->type);
+ warn_deprecated_use (declspecs->type, declspecs->decl_attr);
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);
+ if (name)
+ error ("variably modified %qE at file scope", name);
+ else
+ error ("variably modified field at file scope");
type = integer_type_node;
}
if ((warn_implicit_int || warn_return_type || flag_isoc99)
&& funcdef_flag)
warn_about_return_type = 1;
- else
- pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wimplicit_int,
- "type defaults to %<int%> in declaration of %qs", name);
+ else
+ {
+ if (name)
+ pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wimplicit_int,
+ "type defaults to %<int%> in declaration of %qE",
+ name);
+ else
+ pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wimplicit_int,
+ "type defaults to %<int%> in type name");
+ }
}
/* Adjust the type if a bit-field is being declared,
switch (decl_context)
{
case FIELD:
- error ("storage class specified for structure field %qs",
- name);
+ if (name)
+ error ("storage class specified for structure field %qE",
+ name);
+ else
+ error ("storage class specified for structure field");
break;
case PARM:
- error ("storage class specified for parameter %qs", name);
+ if (name)
+ error ("storage class specified for parameter %qE", name);
+ else
+ error ("storage class specified for unnamed parameter");
break;
default:
error ("storage class specified for typename");
/* It is fine to have 'extern const' when compiling at C
and C++ intersection. */
if (!(warn_cxx_compat && constp))
- warning (0, "%qs initialized and declared %<extern%>", name);
+ warning (0, "%qE initialized and declared %<extern%>", name);
}
else
- error ("%qs has both %<extern%> and initializer", name);
+ error ("%qE 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);
+ error ("file-scope declaration of %qE specifies %<auto%>", name);
if (pedantic && storage_class == csc_register)
pedwarn (input_location, OPT_pedantic,
- "file-scope declaration of %qs specifies %<register%>", name);
+ "file-scope declaration of %qE specifies %<register%>", name);
}
else
{
if (storage_class == csc_extern && funcdef_flag)
- error ("nested function %qs declared %<extern%>", name);
+ error ("nested function %qE declared %<extern%>", name);
else if (threadp && storage_class == csc_none)
{
- error ("function-scope %qs implicitly auto and declared "
+ error ("function-scope %qE implicitly auto and declared "
"%<__thread%>",
name);
threadp = false;
if (VOID_TYPE_P (type))
{
- error ("declaration of %qs as array of voids", name);
+ if (name)
+ error ("declaration of %qE as array of voids", name);
+ else
+ error ("declaration of type name as array of voids");
type = error_mark_node;
}
if (TREE_CODE (type) == FUNCTION_TYPE)
{
- error ("declaration of %qs as array of functions", name);
+ if (name)
+ error ("declaration of %qE as array of functions", name);
+ else
+ error ("declaration of type name as array of functions");
type = error_mark_node;
}
if (size)
{
+ bool size_maybe_const = true;
+ bool size_int_const = (TREE_CODE (size) == INTEGER_CST
+ && !TREE_OVERFLOW (size));
+ bool this_size_varies = false;
+
/* Strip NON_LVALUE_EXPRs since we aren't using as an
lvalue. */
STRIP_TYPE_NOPS (size);
if (!INTEGRAL_TYPE_P (TREE_TYPE (size)))
{
- error ("size of array %qs has non-integer type", name);
+ if (name)
+ error ("size of array %qE has non-integer type", name);
+ else
+ error ("size of unnamed array has non-integer type");
size = integer_one_node;
}
- if (pedantic && integer_zerop (size))
- pedwarn (input_location, OPT_pedantic,
- "ISO C forbids zero-size array %qs", name);
+ size = c_fully_fold (size, false, &size_maybe_const);
+
+ if (pedantic && size_maybe_const && integer_zerop (size))
+ {
+ if (name)
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids zero-size array %qE", name);
+ else
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids zero-size array");
+ }
- if (TREE_CODE (size) == INTEGER_CST)
+ if (TREE_CODE (size) == INTEGER_CST && size_maybe_const)
{
constant_expression_warning (size);
if (tree_int_cst_sgn (size) < 0)
{
- error ("size of array %qs is negative", name);
+ if (name)
+ error ("size of array %qE is negative", name);
+ else
+ error ("size of unnamed array is negative");
size = integer_one_node;
}
+ /* Handle a size folded to an integer constant but
+ not an integer constant expression. */
+ if (!size_int_const)
+ {
+ /* If this is a file scope declaration of an
+ ordinary identifier, this is invalid code;
+ diagnosing it here and not subsequently
+ treating the type as variable-length avoids
+ more confusing diagnostics later. */
+ if ((decl_context == NORMAL || decl_context == FIELD)
+ && current_scope == file_scope)
+ pedwarn (input_location, 0,
+ "variably modified %qE at file scope",
+ name);
+ else
+ this_size_varies = size_varies = 1;
+ warn_variable_length_array (name, size);
+ }
}
else if ((decl_context == NORMAL || decl_context == FIELD)
&& current_scope == file_scope)
{
- error ("variably modified %qs at file scope", name);
+ error ("variably modified %qE at file scope", name);
size = integer_one_node;
}
else
/* Make sure the array size remains visibly
nonconstant even if it is (eg) a const variable
with known value. */
- size_varies = 1;
- warn_variable_length_array (orig_name, size);
+ this_size_varies = size_varies = 1;
+ warn_variable_length_array (name, size);
}
- if (integer_zerop (size))
+ if (integer_zerop (size) && !this_size_varies)
{
/* A zero-length array cannot be represented with
an unsigned index type, which is what we'll
MINUS_EXPR, which allows the -1 to get folded
with the +1 that happens when building TYPE_SIZE. */
if (size_varies)
- size = variable_size (size);
+ size = c_variable_size (size);
+ if (this_size_varies && TREE_CODE (size) == INTEGER_CST)
+ size = build2 (COMPOUND_EXPR, TREE_TYPE (size),
+ integer_zero_node, size);
/* Compute the maximum valid index, that is, size
- 1. Do the calculation in index_type, so that
if (TREE_CODE (itype) == INTEGER_CST
&& TREE_OVERFLOW (itype))
{
- error ("size of array %qs is too large", name);
+ if (name)
+ error ("size of array %qE is too large", name);
+ else
+ error ("size of unnamed array is too large");
type = error_mark_node;
continue;
}
itype = build_index_type (itype);
}
+ if (this_size_varies)
+ {
+ if (*expr)
+ *expr = build2 (COMPOUND_EXPR, TREE_TYPE (size),
+ *expr, size);
+ else
+ *expr = size;
+ *expr_const_operands &= size_maybe_const;
+ }
}
else if (decl_context == FIELD)
{
- if (pedantic && !flag_isoc99 && !in_system_header)
+ bool flexible_array_member = false;
+ if (array_parm_vla_unspec_p)
+ /* Field names can in fact have function prototype
+ scope so [*] is disallowed here through making
+ the field variably modified, not through being
+ something other than a declaration with function
+ prototype scope. */
+ size_varies = 1;
+ else
+ {
+ const struct c_declarator *t = declarator;
+ while (t->kind == cdk_attrs)
+ t = t->declarator;
+ flexible_array_member = (t->kind == cdk_id);
+ }
+ if (flexible_array_member
+ && pedantic && !flag_isoc99 && !in_system_header)
pedwarn (input_location, OPT_pedantic,
"ISO C90 does not support flexible array members");
/* ISO C99 Flexible array members are effectively
identical to GCC's zero-length array extension. */
- itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+ if (flexible_array_member || array_parm_vla_unspec_p)
+ itype = build_range_type (sizetype, size_zero_node,
+ NULL_TREE);
}
else if (decl_context == PARM)
{
if (array_parm_vla_unspec_p)
{
- if (! orig_name)
- {
- /* C99 6.7.5.2p4 */
- error ("%<[*]%> not allowed in other than a declaration");
- }
-
itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
size_varies = 1;
}
{
if (array_parm_vla_unspec_p)
{
- /* The error is printed elsewhere. We use this to
- avoid messing up with incomplete array types of
- the same type, that would otherwise be modified
- below. */
+ /* C99 6.7.5.2p4 */
+ warning (0, "%<[*]%> not in a declaration");
+ /* We use this to avoid messing up with incomplete
+ array types of the same type, that would
+ otherwise be modified below. */
itype = build_range_type (sizetype, size_zero_node,
NULL_TREE);
+ size_varies = 1;
}
}
/* Warn about some types functions can't return. */
if (TREE_CODE (type) == FUNCTION_TYPE)
{
- error ("%qs declared as function returning a function", name);
+ if (name)
+ error ("%qE declared as function returning a function",
+ name);
+ else
+ error ("type name declared as function "
+ "returning a function");
type = integer_type_node;
}
if (TREE_CODE (type) == ARRAY_TYPE)
{
- error ("%qs declared as function returning an array", name);
+ if (name)
+ error ("%qE declared as function returning an array", name);
+ else
+ error ("type name declared as function returning an array");
type = integer_type_node;
}
tree decl = build_decl (TYPE_DECL, NULL_TREE, type);
DECL_ARTIFICIAL (decl) = 1;
pushdecl (decl);
- finish_decl (decl, NULL_TREE, NULL_TREE);
+ finish_decl (decl, NULL_TREE, NULL_TREE, NULL_TREE);
TYPE_NAME (type) = decl;
}
/* Check the type and width of a bit-field. */
if (bitfield)
- check_bitfield_type_and_width (&type, width, orig_name);
+ check_bitfield_type_and_width (&type, width, name);
/* Did array size calculations overflow? */
&& TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
&& TREE_OVERFLOW (TYPE_SIZE_UNIT (type)))
{
- error ("size of array %qs is too large", name);
+ if (name)
+ error ("size of array %qE is too large", name);
+ else
+ error ("size of unnamed array is too large");
/* If we proceed with the array type as it is, we'll eventually
crash in tree_low_cst(). */
type = error_mark_node;
&& !(storage_class == csc_static
|| storage_class == csc_register)))))
{
- error ("variable or field %qs declared void", name);
+ error ("variable or field %qE declared void", name);
type = integer_type_node;
}
if (TREE_CODE (type) == FUNCTION_TYPE)
{
- error ("field %qs declared as a function", name);
+ error ("field %qE 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);
+ if (name)
+ error ("field %qE has incomplete type", name);
+ else
+ error ("unnamed field has incomplete type");
type = error_mark_node;
}
type = c_build_qualified_type (type, type_quals);
{
if (storage_class == csc_register || threadp)
{
- error ("invalid storage class for function %qs", name);
+ error ("invalid storage class for function %qE", name);
}
else if (current_scope != file_scope)
{
GCC allows 'auto', perhaps with 'inline', to support
nested functions. */
if (storage_class == csc_auto)
- pedwarn (input_location, OPT_pedantic, "invalid storage class for function %qs", name);
+ pedwarn (input_location, OPT_pedantic,
+ "invalid storage class for function %qE", name);
else if (storage_class == csc_static)
{
- error ("invalid storage class for function %qs", name);
+ error ("invalid storage class for function %qE", name);
if (funcdef_flag)
storage_class = declspecs->storage_class = csc_none;
else
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
}
- if (storage_class == csc_extern
+ if ((storage_class == csc_extern
+ || (storage_class == csc_none
+ && TREE_CODE (type) == FUNCTION_TYPE
+ && !funcdef_flag))
&& variably_modified_type_p (type, NULL_TREE))
{
/* C99 6.7.5.2p2 */
- error ("object with variably modified type must have no linkage");
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ error ("non-nested function with variably modified type");
+ else
+ error ("object with variably modified type must have no linkage");
}
/* Record `register' declaration for warnings on &
Return a c_typespec structure for the type specifier. */
struct c_typespec
-parser_xref_tag (enum tree_code code, tree name)
+parser_xref_tag (enum tree_code code, tree name, location_t loc)
{
struct c_typespec ret;
+ tree ref;
+ location_t refloc;
+
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
- tree ref = lookup_tag (code, name, 0);
+ ref = lookup_tag (code, name, 0, &refloc);
/* If this is the right type of tag, return what we found.
(This reference will be shadowed by shadow_tag later if appropriate.)
If this is the wrong type of tag, do not return it. If it was the
ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref);
if (ref && TREE_CODE (ref) == code)
{
+ if (C_TYPE_DEFINED_IN_STRUCT (ref)
+ && loc != UNKNOWN_LOCATION
+ && warn_cxx_compat)
+ {
+ switch (code)
+ {
+ case ENUMERAL_TYPE:
+ warning_at (loc, OPT_Wc___compat,
+ ("enum type defined in struct or union "
+ "is not visible in C++"));
+ inform (refloc, "enum type defined here");
+ break;
+ case RECORD_TYPE:
+ warning_at (loc, OPT_Wc___compat,
+ ("struct defined in struct or union "
+ "is not visible in C++"));
+ inform (refloc, "struct defined here");
+ break;
+ case UNION_TYPE:
+ warning_at (loc, OPT_Wc___compat,
+ ("union defined in struct or union "
+ "is not visible in C++"));
+ inform (refloc, "union defined here");
+ break;
+ default:
+ gcc_unreachable();
+ }
+ }
+
ret.spec = ref;
return ret;
}
{
/* Give the type a default layout like unsigned int
to avoid crashing if it does not get defined. */
- TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
+ SET_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_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
}
- pushtag (name, ref);
+ pushtag (name, ref, loc);
ret.spec = ref;
return ret;
tree
xref_tag (enum tree_code code, tree name)
{
- return parser_xref_tag (code, name).spec;
+ return parser_xref_tag (code, name, UNKNOWN_LOCATION).spec;
}
\f
/* Make sure that the tag NAME is defined *in the current scope*
at least as a forward reference.
- CODE says which kind of tag NAME ought to be. */
+ CODE says which kind of tag NAME ought to be.
+
+ This stores the current value of the file static IN_STRUCT in
+ *ENCLOSING_IN_STRUCT, and sets IN_STRUCT to true. Similarly, this
+ sets STRUCT_TYPES in *ENCLOSING_STRUCT_TYPES, and sets STRUCT_TYPES
+ to an empty vector. The old values are restored in
+ finish_struct. */
tree
-start_struct (enum tree_code code, tree name)
+start_struct (enum tree_code code, tree name, bool *enclosing_in_struct,
+ VEC(tree,heap) **enclosing_struct_types, location_t loc)
{
/* If there is already a tag defined at this scope
(as a forward reference), just return it. */
- tree ref = 0;
+ tree ref = NULL_TREE;
+ location_t refloc = UNKNOWN_LOCATION;
- if (name != 0)
- ref = lookup_tag (code, name, 1);
+ if (name != NULL_TREE)
+ ref = lookup_tag (code, name, 1, &refloc);
if (ref && TREE_CODE (ref) == code)
{
if (TYPE_SIZE (ref))
{
if (code == UNION_TYPE)
- error ("redefinition of %<union %E%>", name);
+ error_at (loc, "redefinition of %<union %E%>", name);
else
- error ("redefinition of %<struct %E%>", name);
+ error_at (loc, "redefinition of %<struct %E%>", name);
+ if (refloc != UNKNOWN_LOCATION)
+ inform (refloc, "originally defined here");
+ /* Don't create structures using a name already in use. */
+ ref = NULL_TREE;
}
else if (C_TYPE_BEING_DEFINED (ref))
{
if (code == UNION_TYPE)
- error ("nested redefinition of %<union %E%>", name);
+ error_at (loc, "nested redefinition of %<union %E%>", name);
else
- error ("nested redefinition of %<struct %E%>", name);
+ error_at (loc, "nested redefinition of %<struct %E%>", name);
+ /* Don't bother to report "originally defined here" for a
+ nested redefinition; the original definition should be
+ obvious. */
/* Don't create structures that contain themselves. */
ref = NULL_TREE;
}
if (ref == NULL_TREE || TREE_CODE (ref) != code)
{
ref = make_node (code);
- pushtag (name, ref);
+ pushtag (name, ref, loc);
}
C_TYPE_BEING_DEFINED (ref) = 1;
TYPE_PACKED (ref) = flag_pack_struct;
+
+ *enclosing_in_struct = in_struct;
+ *enclosing_struct_types = struct_types;
+ in_struct = true;
+ struct_types = VEC_alloc(tree, heap, 0);
+
+ /* FIXME: This will issue a warning for a use of a type defined
+ within a statement expr used within sizeof, et. al. This is not
+ terribly serious as C++ doesn't permit statement exprs within
+ sizeof anyhow. */
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ warning_at (loc, OPT_Wc___compat,
+ "defining type in %qs expression is invalid in C++",
+ (in_sizeof
+ ? "sizeof"
+ : (in_typeof ? "typeof" : "alignof")));
+
return ref;
}
}
value = grokdeclarator (declarator, declspecs, FIELD, false,
- width ? &width : NULL, decl_attrs,
+ width ? &width : NULL, decl_attrs, NULL, NULL,
DEPRECATED_NORMAL);
- finish_decl (value, NULL_TREE, NULL_TREE);
+ finish_decl (value, NULL_TREE, NULL_TREE, NULL_TREE);
DECL_INITIAL (value) = width;
return value;
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
FIELDLIST is a chain of FIELD_DECL nodes for the fields.
- ATTRIBUTES are attributes to be applied to the structure. */
+ ATTRIBUTES are attributes to be applied to the structure.
+
+ ENCLOSING_IN_STRUCT is the value of IN_STRUCT, and
+ ENCLOSING_STRUCT_TYPES is the value of STRUCT_TYPES, when the
+ struct was started. This sets the C_TYPE_DEFINED_IN_STRUCT flag
+ for any type defined in the current struct. */
tree
-finish_struct (tree t, tree fieldlist, tree attributes)
+finish_struct (tree t, tree fieldlist, tree attributes,
+ bool enclosing_in_struct,
+ VEC(tree,heap) *enclosing_struct_types)
{
tree x;
bool toplevel = file_scope == current_scope;
int saw_named_field;
+ unsigned int ix;
/* If this type was previously laid out as a forward reference,
make sure we lay it out again. */
DECL_CONTEXT (x) = t;
- if (TYPE_PACKED (t) && TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)
- DECL_PACKED (x) = 1;
-
/* If any field is const, the structure type is pseudo-const. */
if (TREE_READONLY (x))
C_TYPE_FIELDS_READONLY (t) = 1;
SET_DECL_C_BIT_FIELD (x);
}
+ if (TYPE_PACKED (t)
+ && (DECL_BIT_FIELD (x)
+ || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT))
+ DECL_PACKED (x) = 1;
+
/* Detect flexible array member in an invalid context. */
if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
&& TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE))
add_stmt (build_stmt (DECL_EXPR, build_decl (TYPE_DECL, NULL, t)));
+ /* Set the C_TYPE_DEFINED_IN_STRUCT flag for each type defined in
+ the current struct. We do this now at the end of the struct
+ because the flag is used to issue visibility warnings when using
+ -Wc++-compat, and we only want to issue those warnings if the
+ type is referenced outside of the struct declaration. */
+ for (ix = 0; VEC_iterate (tree, struct_types, ix, x); ++ix)
+ C_TYPE_DEFINED_IN_STRUCT (x) = 1;
+
+ VEC_free (tree, heap, struct_types);
+
+ in_struct = enclosing_in_struct;
+ struct_types = enclosing_struct_types;
+
+ /* If this struct is defined inside a struct, add it to
+ STRUCT_TYPES. */
+ if (in_struct && !in_sizeof && !in_typeof && !in_alignof)
+ VEC_safe_push (tree, heap, struct_types, t);
+
return t;
}
may be used to declare the individual values as they are read. */
tree
-start_enum (struct c_enum_contents *the_enum, tree name)
+start_enum (struct c_enum_contents *the_enum, tree name, location_t loc)
{
- tree enumtype = 0;
+ tree enumtype = NULL_TREE;
+ location_t enumloc = UNKNOWN_LOCATION;
/* If this is the real definition for a previous forward reference,
fill in the contents in the same object that used to be the
forward reference. */
- if (name != 0)
- enumtype = lookup_tag (ENUMERAL_TYPE, name, 1);
+ if (name != NULL_TREE)
+ enumtype = lookup_tag (ENUMERAL_TYPE, name, 1, &enumloc);
if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
{
enumtype = make_node (ENUMERAL_TYPE);
- pushtag (name, enumtype);
+ pushtag (name, enumtype, loc);
}
if (C_TYPE_BEING_DEFINED (enumtype))
- error ("nested redefinition of %<enum %E%>", name);
+ error_at (loc, "nested redefinition of %<enum %E%>", name);
C_TYPE_BEING_DEFINED (enumtype) = 1;
if (TYPE_VALUES (enumtype) != 0)
{
/* This enum is a named one that has been declared already. */
- error ("redeclaration of %<enum %E%>", name);
+ error_at (loc, "redeclaration of %<enum %E%>", name);
+ if (enumloc != UNKNOWN_LOCATION)
+ inform (enumloc, "originally defined here");
/* Completely replace its old definition.
The old enumerators remain defined, however. */
if (flag_short_enums)
TYPE_PACKED (enumtype) = 1;
+ /* FIXME: This will issue a warning for a use of a type defined
+ within sizeof in a statement expr. This is not terribly serious
+ as C++ doesn't permit statement exprs within sizeof anyhow. */
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ warning_at (loc, OPT_Wc___compat,
+ "defining type in %qs expression is invalid in C++",
+ (in_sizeof
+ ? "sizeof"
+ : (in_typeof ? "typeof" : "alignof")));
+
return enumtype;
}
that normally we only go as narrow as int - and signed iff any of
the values are negative. */
unsign = (tree_int_cst_sgn (minnode) >= 0);
- precision = MAX (min_precision (minnode, unsign),
- min_precision (maxnode, unsign));
+ precision = MAX (tree_int_cst_min_precision (minnode, unsign),
+ tree_int_cst_min_precision (maxnode, unsign));
if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
{
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);
+ SET_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);
/* Finish debugging output for this type. */
rest_of_type_compilation (enumtype, toplevel);
+ /* If this enum is defined inside a struct, add it to
+ STRUCT_TYPES. */
+ if (in_struct && !in_sizeof && !in_typeof && !in_alignof)
+ VEC_safe_push (tree, heap, struct_types, enumtype);
+
return enumtype;
}
undeclared identifier) - just ignore the value expression. */
if (value == error_mark_node)
value = 0;
- else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
- || TREE_CODE (value) != INTEGER_CST)
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (value)))
{
error ("enumerator value for %qE is not an integer constant", name);
value = 0;
}
else
{
- value = default_conversion (value);
- constant_expression_warning (value);
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ value = c_fully_fold (value, false, NULL);
+ if (TREE_CODE (value) == INTEGER_CST)
+ pedwarn (value_loc, OPT_pedantic,
+ "enumerator value for %qE is not an integer "
+ "constant expression", name);
+ }
+ if (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);
+ }
}
}
c_break_label = c_cont_label = size_zero_node;
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
- &attributes, DEPRECATED_NORMAL);
+ &attributes, NULL, NULL, DEPRECATED_NORMAL);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (DECL_NAME (decl))
{
bind (DECL_NAME (decl), decl, current_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false,
+ UNKNOWN_LOCATION);
if (!TREE_USED (decl))
warn_if_shadowing (decl);
}
DECL_CONTEXT (decl) = current_function_decl;
if (DECL_NAME (decl))
bind (DECL_NAME (decl), decl, current_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
}
/* And all the tag declarations. */
for (decl = arg_info->tags; decl; decl = TREE_CHAIN (decl))
if (TREE_PURPOSE (decl))
bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope,
- /*invisible=*/false, /*nested=*/false);
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
}
/* Subroutine of store_parm_decls which handles old-style function
&& TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
== integer_type_node && flag_isoc99)
{
- tree stmt = c_finish_return (integer_zero_node);
+ tree stmt = c_finish_return (integer_zero_node, NULL_TREE);
/* Hack. We don't want the middle-end to warn that this return
is unreachable, so we mark its location as special. Using
UNKNOWN_LOCATION has the problem that it gets clobbered in
{
struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs);
ret->type = 0;
+ ret->expr = 0;
ret->decl_attr = 0;
ret->attrs = 0;
ret->typespec_word = cts_none;
ret->storage_class = csc_none;
+ ret->expr_const_operands = true;
ret->declspecs_seen_p = false;
ret->type_seen_p = false;
ret->non_sc_seen_p = false;
"declaration specifiers");
break;
}
- if (pedantic && !flag_isoc99 && !in_system_header)
- pedwarn (input_location, OPT_Wlong_long, "ISO C90 does not support %<long long%>");
+ pedwarn_c90 (input_location, OPT_Wlong_long,
+ "ISO C90 does not support %<long long%>");
specs->long_long_p = 1;
break;
}
if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
specs->tag_defined_p = true;
if (spec.kind == ctsk_typeof)
- specs->typedef_p = true;
+ {
+ specs->typedef_p = true;
+ if (spec.expr)
+ {
+ if (specs->expr)
+ specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr),
+ specs->expr, spec.expr);
+ else
+ specs->expr = spec.expr;
+ specs->expr_const_operands &= spec.expr_const_operands;
+ }
+ }
specs->type = type;
}
if (specs->saturating_p)
{
error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
+ if (!targetm.fixed_point_supported_p ())
+ error ("fixed-point types not supported for this target");
specs->typespec_word = cts_fract;
}
else if (specs->long_p || specs->short_p
specs->type = dfloat128_type_node;
break;
case cts_fract:
- gcc_assert (!specs->complex_p);
- if (specs->saturating_p)
+ gcc_assert (!specs->complex_p);
+ if (!targetm.fixed_point_supported_p ())
+ specs->type = integer_type_node;
+ else if (specs->saturating_p)
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
specs->type = specs->unsigned_p
? sat_unsigned_fract_type_node
: sat_fract_type_node;
- }
+ }
else
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
? unsigned_fract_type_node
: fract_type_node;
- }
+ }
break;
case cts_accum:
- gcc_assert (!specs->complex_p);
- if (specs->saturating_p)
+ gcc_assert (!specs->complex_p);
+ if (!targetm.fixed_point_supported_p ())
+ specs->type = integer_type_node;
+ else if (specs->saturating_p)
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
specs->type = specs->unsigned_p
? sat_unsigned_accum_type_node
: sat_accum_type_node;
- }
+ }
else
{
if (specs->long_long_p)
specs->type = specs->unsigned_p
? unsigned_accum_type_node
: accum_type_node;
- }
+ }
break;
default:
gcc_unreachable ();
/* Don't waste time on further processing if -fsyntax-only or we've
encountered errors. */
- if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in))
+ if (flag_syntax_only || errorcount || sorrycount)
return;
/* Close the external scope. */