Index: gcc/gcc/c-decl.c |
diff --git a/gcc/gcc/c-decl.c b/gcc/gcc/c-decl.c |
index 64f8c939936de525d67de3a1324819166e6f0e05..b6ff3f476e6f57ad9372cd37ef71179e9a4a495c 100644 |
--- a/gcc/gcc/c-decl.c |
+++ b/gcc/gcc/c-decl.c |
@@ -1,6 +1,6 @@ |
/* Process declarations and variables for C compiler. |
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
Free Software Foundation, Inc. |
This file is part of GCC. |
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see |
#include "timevar.h" |
#include "c-common.h" |
#include "c-pragma.h" |
+#include "c-lang.h" |
#include "langhooks.h" |
#include "tree-mudflap.h" |
#include "gimple.h" |
@@ -63,6 +64,7 @@ along with GCC; see the file COPYING3. If not see |
#include "langhooks-def.h" |
#include "pointer-set.h" |
#include "gimple.h" |
+#include "plugin.h" |
/* In grokdeclarator, distinguish syntactic contexts of declarators. */ |
enum decl_context |
@@ -90,9 +92,6 @@ tree pending_invalid_xref; |
/* File and line to appear in the eventual error message. */ |
location_t pending_invalid_xref_location; |
-/* True means we've initialized exception handling. */ |
-bool c_eh_initialized_p; |
- |
/* The file and line that the prototype came from if this is an |
old-style definition; used for diagnostics in |
store_parm_decls_oldstyle. */ |
@@ -178,7 +177,7 @@ bool c_override_global_bindings_to_false; |
suppress further errors about that identifier in the current |
function. |
- The ->type field stores the type of the declaration in this scope; |
+ The ->u.type field stores the type of the declaration in this scope; |
if NULL, the type is the type of the ->decl field. This is only of |
relevance for objects with external or internal linkage which may |
be redeclared in inner scopes, forming composite types that only |
@@ -188,6 +187,9 @@ bool c_override_global_bindings_to_false; |
scope) stores whether an incomplete array type at file scope was |
completed at an inner scope to an array size other than 1. |
+ The ->u.label field is used for labels. It points to a structure |
+ which stores additional information used for warnings. |
+ |
The depth field is copied from the scope structure that holds this |
decl. It is used to preserve the proper ordering of the ->shadowed |
field (see bind()) and also for a handful of special-case checks. |
@@ -197,10 +199,12 @@ bool c_override_global_bindings_to_false; |
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 { |
+ union GTY(()) { /* first so GTY desc can use decl */ |
+ tree GTY((tag ("0"))) type; /* the type in this scope */ |
+ struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */ |
+ } GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u; |
tree decl; /* the decl bound */ |
- tree type; /* the type in this scope */ |
tree id; /* the identifier it's bound to */ |
struct c_binding *prev; /* the previous decl in this scope */ |
struct c_binding *shadowed; /* the innermost decl shadowed by this one */ |
@@ -208,7 +212,8 @@ struct c_binding GTY((chain_next ("%h.prev"))) |
BOOL_BITFIELD invisible : 1; /* normal lookup should ignore this binding */ |
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 */ |
+ BOOL_BITFIELD in_struct : 1; /* currently defined as struct field */ |
+ 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) |
@@ -234,8 +239,7 @@ struct c_binding GTY((chain_next ("%h.prev"))) |
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 */ |
@@ -248,16 +252,76 @@ extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate |
/* 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; |
struct lang_identifier GTY ((tag ("1"))) identifier; |
}; |
+/* Track bindings and other things that matter for goto warnings. For |
+ efficiency, we do not gather all the decls at the point of |
+ definition. Instead, we point into the bindings structure. As |
+ scopes are popped, we update these structures and gather the decls |
+ that matter at that time. */ |
+ |
+struct GTY(()) c_spot_bindings { |
+ /* The currently open scope which holds bindings defined when the |
+ label was defined or the goto statement was found. */ |
+ struct c_scope *scope; |
+ /* The bindings in the scope field which were defined at the point |
+ of the label or goto. This lets us look at older or newer |
+ bindings in the scope, as appropriate. */ |
+ struct c_binding *bindings_in_scope; |
+ /* The number of statement expressions that have started since this |
+ label or goto statement was defined. This is zero if we are at |
+ the same statement expression level. It is positive if we are in |
+ a statement expression started since this spot. It is negative |
+ if this spot was in a statement expression and we have left |
+ it. */ |
+ int stmt_exprs; |
+ /* Whether we started in a statement expression but are no longer in |
+ it. This is set to true if stmt_exprs ever goes negative. */ |
+ bool left_stmt_expr; |
+}; |
+ |
+/* This structure is used to keep track of bindings seen when a goto |
+ statement is defined. This is only used if we see the goto |
+ statement before we see the label. */ |
+ |
+struct GTY(()) c_goto_bindings { |
+ /* The location of the goto statement. */ |
+ location_t loc; |
+ /* The bindings of the goto statement. */ |
+ struct c_spot_bindings goto_bindings; |
+}; |
+ |
+typedef struct c_goto_bindings *c_goto_bindings_p; |
+DEF_VEC_P(c_goto_bindings_p); |
+DEF_VEC_ALLOC_P(c_goto_bindings_p,gc); |
+ |
+/* The additional information we keep track of for a label binding. |
+ These fields are updated as scopes are popped. */ |
+ |
+struct GTY(()) c_label_vars { |
+ /* The shadowed c_label_vars, when one label shadows another (which |
+ can only happen using a __label__ declaration). */ |
+ struct c_label_vars *shadowed; |
+ /* The bindings when the label was defined. */ |
+ struct c_spot_bindings label_bindings; |
+ /* A list of decls that we care about: decls about which we should |
+ warn if a goto branches to this label from later in the function. |
+ Decls are added to this list as scopes are popped. We only add |
+ the decls that matter. */ |
+ VEC(tree,gc) *decls_in_scope; |
+ /* A list of goto statements to this label. This is only used for |
+ goto statements seen before the label was defined, so that we can |
+ issue appropriate warnings for them. */ |
+ VEC(c_goto_bindings_p,gc) *gotos; |
+}; |
+ |
/* Each c_scope structure describes the complete contents of one |
scope. Four scopes are distinguished specially: the innermost or |
current scope, the innermost function scope, the file scope (always |
@@ -303,8 +367,7 @@ union lang_tree_node |
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; |
@@ -344,6 +407,14 @@ struct c_scope GTY((chain_next ("%h.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; |
+ |
+ /* True if this scope has any label bindings. This is used to speed |
+ up searching for labels when popping scopes, particularly since |
+ labels are normally only found at function scope. */ |
+ BOOL_BITFIELD has_label_bindings : 1; |
}; |
/* The scope currently in effect. */ |
@@ -395,6 +466,32 @@ static GTY((deletable)) struct c_binding *binding_freelist; |
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; |
@@ -405,13 +502,41 @@ static bool keep_next_level_flag; |
static bool next_is_function_body; |
+/* A VEC of pointers to c_binding structures. */ |
+ |
+typedef struct c_binding *c_binding_ptr; |
+DEF_VEC_P(c_binding_ptr); |
+DEF_VEC_ALLOC_P(c_binding_ptr,heap); |
+ |
+/* Information that we keep for a struct or union while it is being |
+ parsed. */ |
+ |
+struct c_struct_parse_info |
+{ |
+ /* If warn_cxx_compat, a list of types defined within this |
+ struct. */ |
+ VEC(tree,heap) *struct_types; |
+ /* If warn_cxx_compat, a list of field names which have bindings, |
+ and which are defined in this struct, but which are not defined |
+ in any enclosing struct. This is used to clear the in_struct |
+ field of the c_bindings structure. */ |
+ VEC(c_binding_ptr,heap) *fields; |
+ /* If warn_cxx_compat, a list of typedef names used when defining |
+ fields in this struct. */ |
+ VEC(tree,heap) *typedefs_seen; |
+}; |
+ |
+/* Information for the struct or union currently being parsed, or |
+ NULL if not parsing a struct or union. */ |
+static struct c_struct_parse_info *struct_parse_info; |
+ |
/* Forward declarations. */ |
static tree lookup_name_in_scope (tree, struct c_scope *); |
-static tree c_make_fname_decl (tree, int); |
+static tree c_make_fname_decl (location_t, 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); |
@@ -451,7 +576,7 @@ c_print_identifier (FILE *file, tree node, int indent) |
{ |
tree rid = ridpointers[C_RID_CODE (node)]; |
indent_to (file, indent + 4); |
- fprintf (file, "rid %p \"%s\"", |
+ fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"", |
(void *) rid, IDENTIFIER_POINTER (rid)); |
} |
} |
@@ -460,7 +585,8 @@ c_print_identifier (FILE *file, tree node, int indent) |
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; |
@@ -479,8 +605,10 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested) |
b->invisible = invisible; |
b->nested = nested; |
b->inner_comp = 0; |
+ b->in_struct = 0; |
+ b->locus = locus; |
- b->type = 0; |
+ b->u.type = NULL; |
b->prev = scope->bindings; |
scope->bindings = b; |
@@ -531,6 +659,24 @@ free_binding_and_advance (struct c_binding *b) |
return prev; |
} |
+/* Bind a label. Like bind, but skip fields which aren't used for |
+ labels, and add the LABEL_VARS value. */ |
+static void |
+bind_label (tree name, tree label, struct c_scope *scope, |
+ struct c_label_vars *label_vars) |
+{ |
+ struct c_binding *b; |
+ |
+ bind (name, label, scope, /*invisible=*/false, /*nested=*/false, |
+ UNKNOWN_LOCATION); |
+ |
+ scope->has_label_bindings = true; |
+ |
+ b = scope->bindings; |
+ gcc_assert (b->decl == label); |
+ label_vars->shadowed = b->u.label; |
+ b->u.label = label_vars; |
+} |
/* Hook called at end of compilation to assume 1 elt |
for a file-scope tentative array defn that wasn't complete before. */ |
@@ -546,7 +692,8 @@ c_finish_incomplete_decl (tree decl) |
&& !DECL_EXTERNAL (decl) |
&& TYPE_DOMAIN (type) == 0) |
{ |
- warning (0, "array %q+D assumed to have one element", decl); |
+ warning_at (DECL_SOURCE_LOCATION (decl), |
+ 0, "array %q+D assumed to have one element", decl); |
complete_array_type (&TREE_TYPE (decl), NULL_TREE, true); |
@@ -555,6 +702,120 @@ c_finish_incomplete_decl (tree decl) |
} |
} |
+/* 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; |
+} |
+ |
+/* Fill in a c_spot_bindings structure. If DEFINING is true, set it |
+ for the current state, otherwise set it to uninitialized. */ |
+ |
+static void |
+set_spot_bindings (struct c_spot_bindings *p, bool defining) |
+{ |
+ if (defining) |
+ { |
+ p->scope = current_scope; |
+ p->bindings_in_scope = current_scope->bindings; |
+ } |
+ else |
+ { |
+ p->scope = NULL; |
+ p->bindings_in_scope = NULL; |
+ } |
+ p->stmt_exprs = 0; |
+ p->left_stmt_expr = false; |
+} |
+ |
+/* Return true if we will want to say something if a goto statement |
+ crosses DECL. */ |
+ |
+static bool |
+decl_jump_unsafe (tree decl) |
+{ |
+ if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node) |
+ return false; |
+ |
+ /* Always warn about crossing variably modified types. */ |
+ if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL) |
+ && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) |
+ return true; |
+ |
+ /* Otherwise, only warn if -Wgoto-misses-init and this is an |
+ initialized automatic decl. */ |
+ if (warn_jump_misses_init |
+ && TREE_CODE (decl) == VAR_DECL |
+ && !TREE_STATIC (decl) |
+ && DECL_INITIAL (decl) != NULL_TREE) |
+ return true; |
+ |
+ return false; |
+} |
+ |
+/* Update spot bindings P as we pop out of SCOPE. Return true if we |
+ should push decls for a label. */ |
+ |
+static bool |
+update_spot_bindings (struct c_scope *scope, struct c_spot_bindings *p) |
+{ |
+ if (p->scope != scope) |
+ { |
+ /* This label or goto is defined in some other scope, or it is a |
+ label which is not yet defined. There is nothing to |
+ update. */ |
+ return false; |
+ } |
+ |
+ /* Adjust the spot bindings to refer to the bindings already defined |
+ in the enclosing scope. */ |
+ p->scope = scope->outer; |
+ p->bindings_in_scope = p->scope->bindings; |
+ |
+ return true; |
+} |
+ |
/* The Objective-C front-end often needs to determine the current scope. */ |
void * |
@@ -590,7 +851,9 @@ objc_mark_locals_volatile (void *enclosing_blk) |
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 |
@@ -599,6 +862,30 @@ keep_next_level (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 |
@@ -630,6 +917,13 @@ push_scope (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 |
{ |
@@ -642,6 +936,12 @@ push_scope (void) |
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; |
@@ -659,6 +959,67 @@ push_scope (void) |
} |
} |
+/* This is called when we are leaving SCOPE. For each label defined |
+ in SCOPE, add any appropriate decls to its decls_in_scope fields. |
+ These are the decls whose initialization will be skipped by a goto |
+ later in the function. */ |
+ |
+static void |
+update_label_decls (struct c_scope *scope) |
+{ |
+ struct c_scope *s; |
+ |
+ s = scope; |
+ while (s != NULL) |
+ { |
+ if (s->has_label_bindings) |
+ { |
+ struct c_binding *b; |
+ |
+ for (b = s->bindings; b != NULL; b = b->prev) |
+ { |
+ struct c_label_vars *label_vars; |
+ struct c_binding *b1; |
+ unsigned int ix; |
+ struct c_goto_bindings *g; |
+ |
+ if (TREE_CODE (b->decl) != LABEL_DECL) |
+ continue; |
+ label_vars = b->u.label; |
+ |
+ b1 = label_vars->label_bindings.bindings_in_scope; |
+ if (update_spot_bindings (scope, &label_vars->label_bindings)) |
+ { |
+ /* This label is defined in this scope. */ |
+ for (; b1 != NULL; b1 = b1->prev) |
+ { |
+ /* A goto from later in the function to this |
+ label will never see the initialization of |
+ B1, if any. Save it to issue a warning if |
+ needed. */ |
+ if (decl_jump_unsafe (b1->decl)) |
+ VEC_safe_push (tree, gc, label_vars->decls_in_scope, |
+ b1->decl); |
+ } |
+ } |
+ |
+ /* Update the bindings of any goto statements associated |
+ with this label. */ |
+ for (ix = 0; |
+ VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); |
+ ++ix) |
+ update_spot_bindings (scope, &g->goto_bindings); |
+ } |
+ } |
+ |
+ /* Don't search beyond the current function. */ |
+ if (s == current_function_scope) |
+ break; |
+ |
+ s = s->outer; |
+ } |
+} |
+ |
/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */ |
static void |
@@ -684,7 +1045,7 @@ pop_scope (void) |
bool functionbody = scope->function_body; |
bool keep = functionbody || scope->keep || scope->bindings; |
- c_end_vm_scope (scope->depth); |
+ update_label_decls (scope); |
/* If appropriate, create a BLOCK to record the decls for the life |
of this function. */ |
@@ -719,7 +1080,8 @@ pop_scope (void) |
context = current_function_decl; |
else if (scope == file_scope) |
{ |
- tree file_decl = build_decl (TRANSLATION_UNIT_DECL, 0, 0); |
+ tree file_decl = build_decl (UNKNOWN_LOCATION, |
+ TRANSLATION_UNIT_DECL, 0, 0); |
TREE_CHAIN (file_decl) = all_translation_units; |
all_translation_units = file_decl; |
context = file_decl; |
@@ -740,7 +1102,7 @@ pop_scope (void) |
error ("label %q+D used but not defined", p); |
DECL_INITIAL (p) = error_mark_node; |
} |
- else |
+ else |
warn_for_unused_label (p); |
/* Labels go in BLOCK_VARS. */ |
@@ -748,6 +1110,10 @@ pop_scope (void) |
BLOCK_VARS (block) = p; |
gcc_assert (I_LABEL_BINDING (b->id) == b); |
I_LABEL_BINDING (b->id) = b->shadowed; |
+ |
+ /* Also pop back to the shadowed label_vars. */ |
+ release_tree_vector (b->u.label->decls_in_scope); |
+ b->u.label = b->u.label->shadowed; |
break; |
case ENUMERAL_TYPE: |
@@ -824,6 +1190,29 @@ pop_scope (void) |
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. |
@@ -850,8 +1239,8 @@ pop_scope (void) |
{ |
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; |
+ if (b->shadowed && b->shadowed->u.type) |
+ TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; |
} |
break; |
@@ -905,7 +1294,7 @@ push_file_scope (void) |
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 |
@@ -921,6 +1310,8 @@ pop_file_scope (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) |
@@ -934,24 +1325,108 @@ pop_file_scope (void) |
file_scope = 0; |
maybe_apply_pending_pragma_weaks (); |
- cgraph_finalize_compilation_unit (); |
} |
+ |
+/* Adjust the bindings for the start of a statement expression. */ |
+ |
+void |
+c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings) |
+{ |
+ struct c_scope *scope; |
+ |
+ for (scope = current_scope; scope != NULL; scope = scope->outer) |
+ { |
+ struct c_binding *b; |
+ |
+ if (!scope->has_label_bindings) |
+ continue; |
+ |
+ for (b = scope->bindings; b != NULL; b = b->prev) |
+ { |
+ struct c_label_vars *label_vars; |
+ unsigned int ix; |
+ struct c_goto_bindings *g; |
+ |
+ if (TREE_CODE (b->decl) != LABEL_DECL) |
+ continue; |
+ label_vars = b->u.label; |
+ ++label_vars->label_bindings.stmt_exprs; |
+ for (ix = 0; |
+ VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); |
+ ++ix) |
+ ++g->goto_bindings.stmt_exprs; |
+ } |
+ } |
+ |
+ if (switch_bindings != NULL) |
+ ++switch_bindings->stmt_exprs; |
+} |
+ |
+/* Adjust the bindings for the end of a statement expression. */ |
+ |
+void |
+c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings) |
+{ |
+ struct c_scope *scope; |
+ |
+ for (scope = current_scope; scope != NULL; scope = scope->outer) |
+ { |
+ struct c_binding *b; |
+ |
+ if (!scope->has_label_bindings) |
+ continue; |
+ |
+ for (b = scope->bindings; b != NULL; b = b->prev) |
+ { |
+ struct c_label_vars *label_vars; |
+ unsigned int ix; |
+ struct c_goto_bindings *g; |
+ |
+ if (TREE_CODE (b->decl) != LABEL_DECL) |
+ continue; |
+ label_vars = b->u.label; |
+ --label_vars->label_bindings.stmt_exprs; |
+ if (label_vars->label_bindings.stmt_exprs < 0) |
+ { |
+ label_vars->label_bindings.left_stmt_expr = true; |
+ label_vars->label_bindings.stmt_exprs = 0; |
+ } |
+ for (ix = 0; |
+ VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); |
+ ++ix) |
+ { |
+ --g->goto_bindings.stmt_exprs; |
+ if (g->goto_bindings.stmt_exprs < 0) |
+ { |
+ g->goto_bindings.left_stmt_expr = true; |
+ g->goto_bindings.stmt_exprs = 0; |
+ } |
+ } |
+ } |
+ } |
+ if (switch_bindings != NULL) |
+ { |
+ --switch_bindings->stmt_exprs; |
+ gcc_assert (switch_bindings->stmt_exprs >= 0); |
+ } |
+} |
/* Push a definition or a declaration of struct, union or enum tag "name". |
"type" should be the type node. |
- We assume that the tag "name" is not already defined. |
+ We assume that the tag "name" is not already defined, and has a location |
+ of LOC. |
Note that the definition may really be just a forward reference. |
In that case, the TYPE_SIZE will be zero. */ |
static void |
-pushtag (tree name, tree type) |
+pushtag (location_t loc, tree name, tree type) |
{ |
/* 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 |
@@ -960,11 +1435,33 @@ pushtag (tree name, tree type) |
us a convenient place to record the "scope start" address for the |
tagged type. */ |
- TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type)); |
+ TYPE_STUB_DECL (type) = pushdecl (build_decl (loc, |
+ TYPE_DECL, NULL_TREE, type)); |
/* An approximation for now, so we can tell this is a function-scope tag. |
This will be updated in pop_scope. */ |
TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); |
+ |
+ if (warn_cxx_compat && name != NULL_TREE) |
+ { |
+ struct c_binding *b = I_SYMBOL_BINDING (name); |
+ |
+ if (b != NULL |
+ && b->decl != NULL_TREE |
+ && TREE_CODE (b->decl) == TYPE_DECL |
+ && (B_IN_CURRENT_SCOPE (b) |
+ || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) |
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (b->decl)) |
+ != TYPE_MAIN_VARIANT (type))) |
+ { |
+ warning_at (loc, OPT_Wc___compat, |
+ ("using %qD as both a typedef and a tag is " |
+ "invalid in C++"), |
+ b->decl); |
+ if (b->locus != UNKNOWN_LOCATION) |
+ inform (b->locus, "originally defined here"); |
+ } |
+ } |
} |
/* Subroutine of compare_decls. Allow harmless mismatches in return |
@@ -1249,8 +1746,35 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, |
} |
else |
{ |
- if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype)) |
- error ("conflicting type qualifiers for %q+D", newdecl); |
+ int new_quals = TYPE_QUALS (newtype); |
+ int old_quals = TYPE_QUALS (oldtype); |
+ |
+ if (new_quals != old_quals) |
+ { |
+ addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); |
+ addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); |
+ if (new_addr != old_addr) |
+ { |
+ if (ADDR_SPACE_GENERIC_P (new_addr)) |
+ error ("conflicting named address spaces (generic vs %s) " |
+ "for %q+D", |
+ c_addr_space_name (old_addr), newdecl); |
+ else if (ADDR_SPACE_GENERIC_P (old_addr)) |
+ error ("conflicting named address spaces (%s vs generic) " |
+ "for %q+D", |
+ c_addr_space_name (new_addr), newdecl); |
+ else |
+ error ("conflicting named address spaces (%s vs %s) " |
+ "for %q+D", |
+ c_addr_space_name (new_addr), |
+ c_addr_space_name (old_addr), |
+ newdecl); |
+ } |
+ |
+ if (CLEAR_QUAL_ADDR_SPACE (new_quals) |
+ != CLEAR_QUAL_ADDR_SPACE (old_quals)) |
+ error ("conflicting type qualifiers for %q+D", newdecl); |
+ } |
else |
error ("conflicting types for %q+D", newdecl); |
diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); |
@@ -1373,7 +1897,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, |
} |
else if (warn_traditional) |
{ |
- warned |= warning (OPT_Wtraditional, |
+ warned |= warning (OPT_Wtraditional, |
"non-static declaration of %q+D " |
"follows static declaration", newdecl); |
} |
@@ -1390,9 +1914,10 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, |
DECL_ATTRIBUTES (olddecl)) != NULL; |
if (newa != olda) |
{ |
- error ("%<gnu_inline%> attribute present on %q+D", |
- newa ? newdecl : olddecl); |
- error ("%Jbut not here", newa ? olddecl : newdecl); |
+ error_at (input_location, "%<gnu_inline%> attribute present on %q+D", |
+ newa ? newdecl : olddecl); |
+ error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl), |
+ "but not here"); |
} |
} |
} |
@@ -1450,7 +1975,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, |
} |
else if (warn_traditional) |
{ |
- warned |= warning (OPT_Wtraditional, |
+ warned |= warning (OPT_Wtraditional, |
"non-static declaration of %q+D " |
"follows static declaration", newdecl); |
} |
@@ -1491,6 +2016,18 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, |
return false; |
} |
+ |
+ /* C++ does not permit a decl to appear multiple times at file |
+ scope. */ |
+ if (warn_cxx_compat |
+ && DECL_FILE_SCOPE_P (newdecl) |
+ && !DECL_EXTERNAL (newdecl) |
+ && !DECL_EXTERNAL (olddecl)) |
+ warned |= warning_at (DECL_SOURCE_LOCATION (newdecl), |
+ OPT_Wc___compat, |
+ ("duplicate declaration of %qD is " |
+ "invalid in C++"), |
+ newdecl); |
} |
/* warnings */ |
@@ -1509,14 +2046,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, |
if (DECL_DECLARED_INLINE_P (newdecl) |
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) |
{ |
- warned |= warning (OPT_Wattributes, |
+ warned |= warning (OPT_Wattributes, |
"inline declaration of %qD follows " |
"declaration with attribute noinline", newdecl); |
} |
else if (DECL_DECLARED_INLINE_P (olddecl) |
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) |
{ |
- warned |= warning (OPT_Wattributes, |
+ warned |= warning (OPT_Wattributes, |
"declaration of %q+D with attribute " |
"noinline follows inline declaration ", newdecl); |
} |
@@ -1826,12 +2363,15 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) |
/* 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)) |
@@ -1840,19 +2380,27 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) |
} |
} |
- extern_changed = DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl); |
+ extern_changed = DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl); |
- /* Merge the USED information. */ |
- if (TREE_USED (olddecl)) |
- TREE_USED (newdecl) = 1; |
- else if (TREE_USED (newdecl)) |
- TREE_USED (olddecl) = 1; |
+ /* Merge the USED information. */ |
+ if (TREE_USED (olddecl)) |
+ TREE_USED (newdecl) = 1; |
+ else if (TREE_USED (newdecl)) |
+ TREE_USED (olddecl) = 1; |
+ if (DECL_PRESERVE_P (olddecl)) |
+ DECL_PRESERVE_P (newdecl) = 1; |
+ else if (DECL_PRESERVE_P (newdecl)) |
+ DECL_PRESERVE_P (olddecl) = 1; |
/* Copy most of the decl-specific fields of NEWDECL into OLDDECL. |
- But preserve OLDDECL's DECL_UID and DECL_CONTEXT. */ |
+ But preserve OLDDECL's DECL_UID, DECL_CONTEXT and |
+ DECL_ARGUMENTS (if appropriate). */ |
{ |
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), |
@@ -1883,6 +2431,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) |
} |
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 |
@@ -1969,73 +2519,13 @@ warn_if_shadowing (tree new_decl) |
warning (OPT_Wshadow, "declaration of %q+D shadows a previous local", |
new_decl); |
- warning (OPT_Wshadow, "%Jshadowed declaration is here", old_decl); |
+ warning_at (DECL_SOURCE_LOCATION (old_decl), OPT_Wshadow, |
+ "shadowed declaration is here"); |
break; |
} |
} |
- |
-/* 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). |
@@ -2051,6 +2541,7 @@ pushdecl (tree x) |
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 |
@@ -2060,16 +2551,11 @@ pushdecl (tree x) |
|| DECL_INITIAL (x) || !DECL_EXTERNAL (x))) |
DECL_CONTEXT (x) = current_function_decl; |
- /* If this is of variably modified type, prevent jumping into its |
- scope. */ |
- 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); |
- |
/* 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; |
} |
@@ -2103,8 +2589,8 @@ pushdecl (tree x) |
if (b_ext) |
{ |
b_use = b_ext; |
- if (b_use->type) |
- TREE_TYPE (b_use->decl) = b_use->type; |
+ if (b_use->u.type) |
+ TREE_TYPE (b_use->decl) = b_use->u.type; |
} |
} |
if (duplicate_decls (x, b_use->decl)) |
@@ -2118,13 +2604,13 @@ pushdecl (tree x) |
thistype = composite_type (vistype, type); |
else |
thistype = TREE_TYPE (b_use->decl); |
- b_use->type = TREE_TYPE (b_use->decl); |
+ b_use->u.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)); |
+ (b_use->u.type)); |
TREE_TYPE (b_use->decl) = thistype; |
} |
return b_use->decl; |
@@ -2175,7 +2661,7 @@ pushdecl (tree x) |
their scopes will not have been re-entered. */ |
if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved) |
{ |
- b->type = TREE_TYPE (b->decl); |
+ b->u.type = TREE_TYPE (b->decl); |
type_saved = true; |
} |
if (B_IN_FILE_SCOPE (b) |
@@ -2201,8 +2687,8 @@ pushdecl (tree x) |
After the consistency checks, it will be reset to the |
composite of the visible types only. */ |
if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl)) |
- && b->type) |
- TREE_TYPE (b->decl) = b->type; |
+ && b->u.type) |
+ TREE_TYPE (b->decl) = b->u.type; |
/* The point of the same_translation_unit_p check here is, |
we want to detect a duplicate decl for a construct like |
@@ -2223,13 +2709,14 @@ pushdecl (tree x) |
} |
else |
thistype = type; |
- b->type = TREE_TYPE (b->decl); |
+ b->u.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)); |
+ TYPE_ATTRIBUTES (b->u.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)) |
@@ -2247,7 +2734,7 @@ pushdecl (tree x) |
else |
{ |
bind (name, x, external_scope, /*invisible=*/true, |
- /*nested=*/false); |
+ /*nested=*/false, locus); |
nested = true; |
} |
} |
@@ -2258,9 +2745,9 @@ pushdecl (tree x) |
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, |
@@ -2309,11 +2796,12 @@ pushdecl_top_level (tree x) |
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; |
} |
@@ -2328,19 +2816,19 @@ implicit_decl_warning (tree id, tree olddecl) |
if (flag_isoc99) |
warned = pedwarn (input_location, OPT_Wimplicit_function_declaration, |
"implicit declaration of function %qE", id); |
- else |
- warned = warning (OPT_Wimplicit_function_declaration, |
+ else |
+ warned = warning (OPT_Wimplicit_function_declaration, |
G_("implicit declaration of function %qE"), id); |
if (olddecl && warned) |
locate_old_decl (olddecl); |
} |
} |
-/* Generate an implicit declaration for identifier FUNCTIONID as a |
+/* Generate an implicit declaration for identifier FUNCTIONID at LOC as a |
function of type int (). */ |
tree |
-implicitly_declare (tree functionid) |
+implicitly_declare (location_t loc, tree functionid) |
{ |
struct c_binding *b; |
tree decl = 0; |
@@ -2368,14 +2856,15 @@ implicitly_declare (tree functionid) |
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 |
{ |
tree newtype = default_function_type; |
- if (b->type) |
- TREE_TYPE (decl) = b->type; |
+ if (b->u.type) |
+ TREE_TYPE (decl) = b->u.type; |
/* Implicit declaration of a function already declared |
(somehow) in a different scope, or as a built-in. |
If this is the first time this has happened, warn; |
@@ -2392,8 +2881,8 @@ implicitly_declare (tree functionid) |
(TREE_TYPE (decl))); |
if (!comptypes (newtype, TREE_TYPE (decl))) |
{ |
- warning (0, "incompatible implicit declaration of built-in" |
- " function %qD", decl); |
+ warning_at (loc, 0, "incompatible implicit declaration of " |
+ "built-in function %qD", decl); |
newtype = TREE_TYPE (decl); |
} |
} |
@@ -2401,21 +2890,21 @@ implicitly_declare (tree functionid) |
{ |
if (!comptypes (newtype, TREE_TYPE (decl))) |
{ |
- error ("incompatible implicit declaration of function %qD", |
- decl); |
+ error_at (loc, "incompatible implicit declaration of function %qD", decl); |
locate_old_decl (decl); |
} |
} |
- b->type = TREE_TYPE (decl); |
+ b->u.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; |
} |
} |
/* Not seen before. */ |
- decl = build_decl (FUNCTION_DECL, functionid, default_function_type); |
+ decl = build_decl (loc, FUNCTION_DECL, functionid, default_function_type); |
DECL_EXTERNAL (decl) = 1; |
TREE_PUBLIC (decl) = 1; |
C_DECL_IMPLICIT (decl) = 1; |
@@ -2447,24 +2936,23 @@ implicitly_declare (tree functionid) |
in an appropriate scope, which will suppress further errors for the |
same identifier. The error message should be given location LOC. */ |
void |
-undeclared_variable (tree id, location_t loc) |
+undeclared_variable (location_t loc, tree id) |
{ |
static bool already = false; |
struct c_scope *scope; |
if (current_function_decl == 0) |
{ |
- error ("%H%qE undeclared here (not in a function)", &loc, id); |
+ error_at (loc, "%qE undeclared here (not in a function)", id); |
scope = current_scope; |
} |
else |
{ |
- error ("%H%qE undeclared (first use in this function)", &loc, id); |
- |
+ error_at (loc, "%qE undeclared (first use in this function)", id); |
if (!already) |
{ |
- error ("%H(Each undeclared identifier is reported only once", &loc); |
- error ("%Hfor each function it appears in.)", &loc); |
+ inform (loc, "each undeclared identifier is reported only" |
+ " once for each function it appears in"); |
already = true; |
} |
@@ -2472,20 +2960,30 @@ undeclared_variable (tree id, location_t loc) |
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); |
} |
/* Subroutine of lookup_label, declare_label, define_label: construct a |
- LABEL_DECL with all the proper frills. */ |
+ LABEL_DECL with all the proper frills. Also create a struct |
+ c_label_vars initialized for the current scope. */ |
static tree |
-make_label (tree name, location_t location) |
+make_label (location_t location, tree name, bool defining, |
+ struct c_label_vars **p_label_vars) |
{ |
- tree label = build_decl (LABEL_DECL, name, void_type_node); |
+ tree label = build_decl (location, LABEL_DECL, name, void_type_node); |
+ struct c_label_vars *label_vars; |
DECL_CONTEXT (label) = current_function_decl; |
DECL_MODE (label) = VOIDmode; |
- DECL_SOURCE_LOCATION (label) = location; |
+ |
+ label_vars = GGC_NEW (struct c_label_vars); |
+ label_vars->shadowed = NULL; |
+ set_spot_bindings (&label_vars->label_bindings, defining); |
+ label_vars->decls_in_scope = make_tree_vector (); |
+ label_vars->gotos = VEC_alloc (c_goto_bindings_p, gc, 0); |
+ *p_label_vars = label_vars; |
return label; |
} |
@@ -2499,6 +2997,7 @@ tree |
lookup_label (tree name) |
{ |
tree label; |
+ struct c_label_vars *label_vars; |
if (current_function_decl == 0) |
{ |
@@ -2516,17 +3015,91 @@ lookup_label (tree name) |
/* If the label has only been declared, update its apparent |
location to point here, for better diagnostics if it |
turns out not to have been defined. */ |
- if (!TREE_USED (label)) |
+ if (DECL_INITIAL (label) == NULL_TREE) |
DECL_SOURCE_LOCATION (label) = input_location; |
return label; |
} |
/* No label binding for that identifier; make one. */ |
- label = make_label (name, input_location); |
+ label = make_label (input_location, name, false, &label_vars); |
/* Ordinary labels go in the current function scope. */ |
- bind (name, label, current_function_scope, |
- /*invisible=*/false, /*nested=*/false); |
+ bind_label (name, label, current_function_scope, label_vars); |
+ |
+ return label; |
+} |
+ |
+/* Issue a warning about DECL for a goto statement at GOTO_LOC going |
+ to LABEL. */ |
+ |
+static void |
+warn_about_goto (location_t goto_loc, tree label, tree decl) |
+{ |
+ if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) |
+ error_at (goto_loc, |
+ "jump into scope of identifier with variably modified type"); |
+ else |
+ warning_at (goto_loc, OPT_Wjump_misses_init, |
+ "jump skips variable initialization"); |
+ inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); |
+ inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); |
+} |
+ |
+/* Look up a label because of a goto statement. This is like |
+ lookup_label, but also issues any appropriate warnings. */ |
+ |
+tree |
+lookup_label_for_goto (location_t loc, tree name) |
+{ |
+ tree label; |
+ struct c_label_vars *label_vars; |
+ unsigned int ix; |
+ tree decl; |
+ |
+ label = lookup_label (name); |
+ if (label == NULL_TREE) |
+ return NULL_TREE; |
+ |
+ /* If we are jumping to a different function, we can't issue any |
+ useful warnings. */ |
+ if (DECL_CONTEXT (label) != current_function_decl) |
+ { |
+ gcc_assert (C_DECLARED_LABEL_FLAG (label)); |
+ return label; |
+ } |
+ |
+ label_vars = I_LABEL_BINDING (name)->u.label; |
+ |
+ /* If the label has not yet been defined, then push this goto on a |
+ list for possible later warnings. */ |
+ if (label_vars->label_bindings.scope == NULL) |
+ { |
+ struct c_goto_bindings *g; |
+ |
+ g = GGC_NEW (struct c_goto_bindings); |
+ g->loc = loc; |
+ set_spot_bindings (&g->goto_bindings, true); |
+ VEC_safe_push (c_goto_bindings_p, gc, label_vars->gotos, g); |
+ return label; |
+ } |
+ |
+ /* If there are any decls in label_vars->decls_in_scope, then this |
+ goto has missed the declaration of the decl. This happens for a |
+ case like |
+ int i = 1; |
+ lab: |
+ ... |
+ goto lab; |
+ Issue a warning or error. */ |
+ for (ix = 0; VEC_iterate (tree, label_vars->decls_in_scope, ix, decl); ++ix) |
+ warn_about_goto (loc, label, decl); |
+ |
+ if (label_vars->label_bindings.left_stmt_expr) |
+ { |
+ error_at (loc, "jump into statement expression"); |
+ inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label); |
+ } |
+ |
return label; |
} |
@@ -2539,6 +3112,7 @@ declare_label (tree name) |
{ |
struct c_binding *b = I_LABEL_BINDING (name); |
tree label; |
+ struct c_label_vars *label_vars; |
/* Check to make sure that the label hasn't already been declared |
at this scope */ |
@@ -2551,15 +3125,74 @@ declare_label (tree name) |
return b->decl; |
} |
- label = make_label (name, input_location); |
+ label = make_label (input_location, name, false, &label_vars); |
C_DECLARED_LABEL_FLAG (label) = 1; |
/* Declared labels go in the current scope. */ |
- bind (name, label, current_scope, |
- /*invisible=*/false, /*nested=*/false); |
+ bind_label (name, label, current_scope, label_vars); |
+ |
return label; |
} |
+/* When we define a label, issue any appropriate warnings if there are |
+ any gotos earlier in the function which jump to this label. */ |
+ |
+static void |
+check_earlier_gotos (tree label, struct c_label_vars* label_vars) |
+{ |
+ unsigned int ix; |
+ struct c_goto_bindings *g; |
+ |
+ for (ix = 0; |
+ VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g); |
+ ++ix) |
+ { |
+ struct c_binding *b; |
+ struct c_scope *scope; |
+ |
+ /* We have a goto to this label. The goto is going forward. In |
+ g->scope, the goto is going to skip any binding which was |
+ defined after g->bindings_in_scope. */ |
+ for (b = g->goto_bindings.scope->bindings; |
+ b != g->goto_bindings.bindings_in_scope; |
+ b = b->prev) |
+ { |
+ if (decl_jump_unsafe (b->decl)) |
+ warn_about_goto (g->loc, label, b->decl); |
+ } |
+ |
+ /* We also need to warn about decls defined in any scopes |
+ between the scope of the label and the scope of the goto. */ |
+ for (scope = label_vars->label_bindings.scope; |
+ scope != g->goto_bindings.scope; |
+ scope = scope->outer) |
+ { |
+ gcc_assert (scope != NULL); |
+ if (scope == label_vars->label_bindings.scope) |
+ b = label_vars->label_bindings.bindings_in_scope; |
+ else |
+ b = scope->bindings; |
+ for (; b != NULL; b = b->prev) |
+ { |
+ if (decl_jump_unsafe (b->decl)) |
+ warn_about_goto (g->loc, label, b->decl); |
+ } |
+ } |
+ |
+ if (g->goto_bindings.stmt_exprs > 0) |
+ { |
+ error_at (g->loc, "jump into statement expression"); |
+ inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", |
+ label); |
+ } |
+ } |
+ |
+ /* Now that the label is defined, we will issue warnings about |
+ subsequent gotos to this label when we see them. */ |
+ VEC_truncate (c_goto_bindings_p, label_vars->gotos, 0); |
+ label_vars->gotos = NULL; |
+} |
+ |
/* Define a label, specifying the location in the source file. |
Return the LABEL_DECL node for the label, if the definition is valid. |
Otherwise return 0. */ |
@@ -2572,7 +3205,6 @@ define_label (location_t location, tree name) |
if there is a containing function with a declared label with |
the same name. */ |
tree label = I_LABEL_DECL (name); |
- struct c_label_list *nlist_se, *nlist_vm; |
if (label |
&& ((DECL_CONTEXT (label) == current_function_decl |
@@ -2580,60 +3212,128 @@ define_label (location_t location, tree name) |
|| (DECL_CONTEXT (label) != current_function_decl |
&& C_DECLARED_LABEL_FLAG (label)))) |
{ |
- error ("%Hduplicate label %qD", &location, label); |
+ error_at (location, "duplicate label %qD", label); |
locate_old_decl (label); |
return 0; |
} |
else if (label && DECL_CONTEXT (label) == current_function_decl) |
{ |
+ struct c_label_vars *label_vars = I_LABEL_BINDING (name)->u.label; |
+ |
/* The label has been used or declared already in this function, |
but not defined. Update its location to point to this |
definition. */ |
- 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; |
+ set_spot_bindings (&label_vars->label_bindings, true); |
+ |
+ /* Issue warnings as required about any goto statements from |
+ earlier in the function. */ |
+ check_earlier_gotos (label, label_vars); |
} |
else |
{ |
+ struct c_label_vars *label_vars; |
+ |
/* No label binding for that identifier; make one. */ |
- label = make_label (name, location); |
+ label = make_label (location, name, true, &label_vars); |
/* Ordinary labels go in the current function scope. */ |
- bind (name, label, current_function_scope, |
- /*invisible=*/false, /*nested=*/false); |
+ bind_label (name, label, current_function_scope, label_vars); |
} |
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; |
+ warning_at (location, OPT_Wtraditional, |
+ "traditional C lacks a separate namespace " |
+ "for labels, identifier %qE conflicts", name); |
/* Mark label as having been defined. */ |
DECL_INITIAL (label) = error_mark_node; |
return label; |
} |
+/* Get the bindings for a new switch statement. This is used to issue |
+ warnings as appropriate for jumps from the switch to case or |
+ default labels. */ |
+ |
+struct c_spot_bindings * |
+c_get_switch_bindings (void) |
+{ |
+ struct c_spot_bindings *switch_bindings; |
+ |
+ switch_bindings = XNEW (struct c_spot_bindings); |
+ set_spot_bindings (switch_bindings, true); |
+ return switch_bindings; |
+} |
+ |
+void |
+c_release_switch_bindings (struct c_spot_bindings *bindings) |
+{ |
+ gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr); |
+ XDELETE (bindings); |
+} |
+ |
+/* This is called at the point of a case or default label to issue |
+ warnings about decls as needed. It returns true if it found an |
+ error, not just a warning. */ |
+ |
+bool |
+c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings, |
+ location_t switch_loc, location_t case_loc) |
+{ |
+ bool saw_error; |
+ struct c_scope *scope; |
+ |
+ saw_error = false; |
+ for (scope = current_scope; |
+ scope != switch_bindings->scope; |
+ scope = scope->outer) |
+ { |
+ struct c_binding *b; |
+ |
+ gcc_assert (scope != NULL); |
+ for (b = scope->bindings; b != NULL; b = b->prev) |
+ { |
+ if (decl_jump_unsafe (b->decl)) |
+ { |
+ if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE)) |
+ { |
+ saw_error = true; |
+ error_at (case_loc, |
+ ("switch jumps into scope of identifier with " |
+ "variably modified type")); |
+ } |
+ else |
+ warning_at (case_loc, OPT_Wjump_misses_init, |
+ "switch jumps over variable initialization"); |
+ inform (switch_loc, "switch starts here"); |
+ inform (DECL_SOURCE_LOCATION (b->decl), "%qD declared here", |
+ b->decl); |
+ } |
+ } |
+ } |
+ |
+ if (switch_bindings->stmt_exprs > 0) |
+ { |
+ saw_error = true; |
+ error_at (case_loc, "switch jumps into statement expression"); |
+ inform (switch_loc, "switch starts here"); |
+ } |
+ |
+ return saw_error; |
+} |
+ |
/* Given NAME, an IDENTIFIER_NODE, |
return the structure (or union or enum) definition for that 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; |
@@ -2670,6 +3370,10 @@ lookup_tag (enum tree_code code, tree name, int thislevel_only) |
if (thislevel) |
pending_xref_error (); |
} |
+ |
+ if (ploc != NULL) |
+ *ploc = b->locus; |
+ |
return b->decl; |
} |
@@ -2682,8 +3386,8 @@ 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); |
+ error_at (pending_invalid_xref_location, "%qE defined as wrong kind of tag", |
+ pending_invalid_xref); |
pending_invalid_xref = 0; |
} |
@@ -2751,7 +3455,7 @@ c_init_decl_processing (void) |
truthvalue_false_node = integer_zero_node; |
/* Even in C99, which has a real boolean type. */ |
- pushdecl (build_decl (TYPE_DECL, get_identifier ("_Bool"), |
+ pushdecl (build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier ("_Bool"), |
boolean_type_node)); |
input_location = save_loc; |
@@ -2762,15 +3466,16 @@ c_init_decl_processing (void) |
start_fname_decls (); |
} |
-/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the |
- decl, NAME is the initialization string and TYPE_DEP indicates whether |
- NAME depended on the type of the function. As we don't yet implement |
- delayed emission of static data, we mark the decl as emitted |
- so it is not placed in the output. Anything using it must therefore pull |
- out the STRING_CST initializer directly. FIXME. */ |
+/* Create the VAR_DECL at LOC for __FUNCTION__ etc. ID is the name to |
+ give the decl, NAME is the initialization string and TYPE_DEP |
+ indicates whether NAME depended on the type of the function. As we |
+ don't yet implement delayed emission of static data, we mark the |
+ decl as emitted so it is not placed in the output. Anything using |
+ it must therefore pull out the STRING_CST initializer directly. |
+ FIXME. */ |
static tree |
-c_make_fname_decl (tree id, int type_dep) |
+c_make_fname_decl (location_t loc, tree id, int type_dep) |
{ |
const char *name = fname_as_string (type_dep); |
tree decl, type, init; |
@@ -2780,7 +3485,7 @@ c_make_fname_decl (tree id, int type_dep) |
build_index_type (size_int (length))); |
type = c_build_qualified_type (type, TYPE_QUAL_CONST); |
- decl = build_decl (VAR_DECL, id, type); |
+ decl = build_decl (loc, VAR_DECL, id, type); |
TREE_STATIC (decl) = 1; |
TREE_READONLY (decl) = 1; |
@@ -2795,10 +3500,10 @@ c_make_fname_decl (tree id, int type_dep) |
if (current_function_decl |
/* For invalid programs like this: |
- |
+ |
void foo() |
const char* p = __FUNCTION__; |
- |
+ |
the __FUNCTION__ is believed to appear in K&R style function |
parameter declarator. In that case we still don't have |
function_scope. */ |
@@ -2806,10 +3511,10 @@ c_make_fname_decl (tree id, int type_dep) |
{ |
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, loc, init, NULL_TREE, NULL_TREE); |
return decl; |
} |
@@ -2826,7 +3531,8 @@ c_builtin_function (tree 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. */ |
@@ -2851,7 +3557,8 @@ c_builtin_function_ext_scope (tree decl) |
/* 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. */ |
@@ -2899,6 +3606,12 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) |
found_tag = true; |
+ if (declspecs->restrict_p) |
+ { |
+ error ("invalid use of %<restrict%>"); |
+ warned = 1; |
+ } |
+ |
if (name == 0) |
{ |
if (warned != 1 && code != ENUMERAL_TYPE) |
@@ -2922,7 +3635,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) |
else if (!declspecs->tag_defined_p |
&& (declspecs->const_p |
|| declspecs->volatile_p |
- || declspecs->restrict_p)) |
+ || declspecs->restrict_p |
+ || declspecs->address_space)) |
{ |
if (warned != 1) |
pedwarn (input_location, 0, |
@@ -2934,12 +3648,12 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) |
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 (input_location, name, t); |
} |
} |
} |
@@ -2993,7 +3707,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) |
if (!warned && !in_system_header && (declspecs->const_p |
|| declspecs->volatile_p |
- || declspecs->restrict_p)) |
+ || declspecs->restrict_p |
+ || declspecs->address_space)) |
{ |
warning (0, "useless type qualifier in empty declaration"); |
warned = 2; |
@@ -3016,7 +3731,8 @@ 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)); |
+ | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) |
+ | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); |
gcc_assert (!specs->type |
&& !specs->decl_attr |
&& specs->typespec_word == cts_none |
@@ -3035,21 +3751,24 @@ quals_from_declspecs (const struct c_declspecs *specs) |
return quals; |
} |
-/* Construct an array declarator. EXPR is the expression inside [], |
- or NULL_TREE. QUALS are the type qualifiers inside the [] (to be |
- applied to the pointer to which a parameter array is converted). |
- STATIC_P is true if "static" is inside the [], false otherwise. |
- VLA_UNSPEC_P is true if the array is [*], a VLA of unspecified |
- length which is nevertheless a complete type, false otherwise. The |
- field for the contained declarator is left to be filled in by |
- set_array_declarator_inner. */ |
+/* Construct an array declarator. LOC is the location of the |
+ beginning of the array (usually the opening brace). EXPR is the |
+ expression inside [], or NULL_TREE. QUALS are the type qualifiers |
+ inside the [] (to be applied to the pointer to which a parameter |
+ array is converted). STATIC_P is true if "static" is inside the |
+ [], false otherwise. VLA_UNSPEC_P is true if the array is [*], a |
+ VLA of unspecified length which is nevertheless a complete type, |
+ false otherwise. The field for the contained declarator is left to |
+ be filled in by set_array_declarator_inner. */ |
struct c_declarator * |
-build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p, |
+build_array_declarator (location_t loc, |
+ tree expr, struct c_declspecs *quals, bool static_p, |
bool vla_unspec_p) |
{ |
struct c_declarator *declarator = XOBNEW (&parser_obstack, |
struct c_declarator); |
+ declarator->id_loc = loc; |
declarator->kind = cdk_array; |
declarator->declarator = 0; |
declarator->u.array.dimen = expr; |
@@ -3068,11 +3787,11 @@ build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p, |
if (!flag_isoc99) |
{ |
if (static_p || quals != NULL) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C90 does not support %<static%> or type " |
"qualifiers in parameter array declarators"); |
if (vla_unspec_p) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C90 does not support %<[*]%> array declarators"); |
} |
if (vla_unspec_p) |
@@ -3080,7 +3799,8 @@ build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p, |
if (!current_scope->parm_flag) |
{ |
/* C99 6.7.5.2p4 */ |
- error ("%<[*]%> not allowed in other than function prototype scope"); |
+ error_at (loc, "%<[*]%> not allowed in other than " |
+ "function prototype scope"); |
declarator->u.array.vla_unspec_p = false; |
return NULL; |
} |
@@ -3128,10 +3848,15 @@ add_flexible_array_elts_to_size (tree decl, tree init) |
} |
} |
-/* 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; |
@@ -3139,7 +3864,8 @@ groktypename (struct c_type_name *type_name) |
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); |
@@ -3168,6 +3894,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, |
{ |
tree decl; |
tree tem; |
+ tree expr = NULL_TREE; |
enum deprecated_states deprecated_state = DEPRECATED_NORMAL; |
/* An object declared as __attribute__((deprecated)) suppresses |
@@ -3176,11 +3903,14 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, |
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); |
@@ -3328,9 +4058,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, |
&& !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. */ |
@@ -3345,33 +4074,20 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, |
return tem; |
} |
-/* Initialize EH if not initialized yet and exceptions are enabled. */ |
- |
-void |
-c_maybe_initialize_eh (void) |
-{ |
- if (!flag_exceptions || c_eh_initialized_p) |
- return; |
- |
- c_eh_initialized_p = true; |
- eh_personality_libfunc |
- = init_one_libfunc (USING_SJLJ_EXCEPTIONS |
- ? "__gcc_personality_sj0" |
- : "__gcc_personality_v0"); |
- default_init_unwind_resume_libfunc (); |
- using_eh_for_cleanups (); |
-} |
- |
/* 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. */ |
+ it must be determined now, from the initial value, or it is an error. |
+ |
+ INIT_LOC is the location of the initial value. */ |
void |
-finish_decl (tree decl, tree init, tree asmspec_tree) |
+finish_decl (tree decl, location_t init_loc, tree init, |
+ tree origtype, tree asmspec_tree) |
{ |
tree type; |
- int was_incomplete = (DECL_SIZE (decl) == 0); |
+ bool was_incomplete = (DECL_SIZE (decl) == 0); |
const char *asmspec = 0; |
/* If a name was specified, get the string. */ |
@@ -3397,7 +4113,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) |
init = 0; |
if (init) |
- store_init_value (decl, init); |
+ store_init_value (init_loc, decl, init, origtype); |
if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL |
|| TREE_CODE (decl) == FUNCTION_DECL |
@@ -3457,10 +4173,10 @@ finish_decl (tree decl, tree init, tree asmspec_tree) |
b_ext = b_ext->shadowed; |
if (b_ext) |
{ |
- if (b_ext->type) |
- b_ext->type = composite_type (b_ext->type, type); |
+ if (b_ext->u.type) |
+ b_ext->u.type = composite_type (b_ext->u.type, type); |
else |
- b_ext->type = type; |
+ b_ext->u.type = type; |
} |
} |
break; |
@@ -3605,7 +4321,8 @@ finish_decl (tree decl, tree init, tree asmspec_tree) |
add_stmt (bind); |
BIND_EXPR_BODY (bind) = push_stmt_list (); |
} |
- add_stmt (build_stmt (DECL_EXPR, decl)); |
+ add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), |
+ DECL_EXPR, decl)); |
} |
} |
@@ -3630,7 +4347,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) |
{ |
if (!DECL_FILE_SCOPE_P (decl) |
&& variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) |
- add_stmt (build_stmt (DECL_EXPR, decl)); |
+ add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); |
rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); |
} |
@@ -3650,22 +4367,31 @@ finish_decl (tree decl, tree init, tree asmspec_tree) |
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 (DECL_SOURCE_LOCATION (decl), |
+ cleanup_decl, vec, NULL); |
+ VEC_free (tree, gc, vec); |
/* Don't warn about decl unused; the cleanup uses it. */ |
TREE_USED (decl) = 1; |
TREE_USED (cleanup_decl) = 1; |
- /* Initialize EH, if we've been told to do so. */ |
- c_maybe_initialize_eh (); |
- |
push_cleanup (decl, cleanup, false); |
} |
} |
+ |
+ if (warn_cxx_compat |
+ && TREE_CODE (decl) == VAR_DECL |
+ && TREE_READONLY (decl) |
+ && !DECL_EXTERNAL (decl) |
+ && DECL_INITIAL (decl) == NULL_TREE) |
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, |
+ "uninitialized const %qD is invalid in C++", decl); |
} |
/* Given a parsed parameter declaration, decode it into a PARM_DECL. */ |
@@ -3675,7 +4401,7 @@ grokparm (const struct c_parm *parm) |
{ |
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); |
@@ -3692,12 +4418,12 @@ push_parm_decl (const struct c_parm *parm) |
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, input_location, NULL_TREE, NULL_TREE, NULL_TREE); |
} |
/* Mark all the parameter declarations to date as forward decls. |
@@ -3722,11 +4448,12 @@ mark_forward_parm_decls (void) |
/* 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. */ |
+ initializer; INIT is a CONSTRUCTOR at LOC that initializes the compound |
+ 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 (location_t loc, 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 |
@@ -3735,10 +4462,11 @@ build_compound_literal (tree type, tree init) |
tree complit; |
tree stmt; |
- if (type == error_mark_node) |
+ if (type == error_mark_node |
+ || init == error_mark_node) |
return error_mark_node; |
- decl = build_decl (VAR_DECL, NULL_TREE, type); |
+ decl = build_decl (loc, VAR_DECL, NULL_TREE, type); |
DECL_EXTERNAL (decl) = 0; |
TREE_PUBLIC (decl) = 0; |
TREE_STATIC (decl) = (current_scope == file_scope); |
@@ -3746,7 +4474,7 @@ build_compound_literal (tree type, tree init) |
TREE_USED (decl) = 1; |
TREE_TYPE (decl) = type; |
TREE_READONLY (decl) = TYPE_READONLY (type); |
- store_init_value (decl, init); |
+ store_init_value (loc, decl, init, NULL_TREE); |
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) |
{ |
@@ -3761,7 +4489,7 @@ build_compound_literal (tree type, tree init) |
if (type == error_mark_node || !COMPLETE_TYPE_P (type)) |
return error_mark_node; |
- stmt = build_stmt (DECL_EXPR, decl); |
+ stmt = build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl); |
complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt); |
TREE_SIDE_EFFECTS (complit) = 1; |
@@ -3779,8 +4507,25 @@ build_compound_literal (tree type, tree init) |
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 (location_t loc, struct c_type_name *type_name) |
+{ |
+ 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++"); |
+} |
/* Determine whether TYPE is a structure with a flexible array member, |
or a union containing such a structure (possibly recursively). */ |
@@ -3818,23 +4563,37 @@ flexible_array_type_p (tree type) |
/* 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. */ |
- if (!INTEGRAL_TYPE_P (TREE_TYPE (*width)) |
- || TREE_CODE (*width) != INTEGER_CST) |
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (*width))) |
{ |
error ("bit-field %qs width not an integer constant", name); |
*width = integer_one_node; |
} |
else |
{ |
+ if (TREE_CODE (*width) != INTEGER_CST) |
+ { |
+ *width = c_fully_fold (*width, false, NULL); |
+ if (TREE_CODE (*width) == INTEGER_CST) |
+ pedwarn (input_location, OPT_pedantic, |
+ "bit-field %qs width not an integer constant expression", |
+ name); |
+ } |
+ if (TREE_CODE (*width) != INTEGER_CST) |
+ { |
+ error ("bit-field %qs width not an integer constant", name); |
+ *width = integer_one_node; |
+ } |
constant_expression_warning (*width); |
if (tree_int_cst_sgn (*width) < 0) |
{ |
@@ -3891,7 +4650,7 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_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); |
@@ -3900,7 +4659,8 @@ warn_variable_length_array (const char *name, tree 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 |
@@ -3909,8 +4669,9 @@ warn_variable_length_array (const char *name, tree size) |
} |
else |
{ |
- if (name) |
- pedwarn (input_location, OPT_Wvla, "ISO C90 forbids variable length array %qs", |
+ if (name) |
+ 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"); |
@@ -3922,7 +4683,7 @@ warn_variable_length_array (const char *name, tree size) |
{ |
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, |
@@ -3932,7 +4693,7 @@ warn_variable_length_array (const char *name, tree size) |
{ |
if (name) |
warning (OPT_Wvla, |
- "variable length array %qs is used", |
+ "variable length array %qE is used", |
name); |
else |
warning (OPT_Wvla, |
@@ -3941,6 +4702,34 @@ warn_variable_length_array (const char *name, tree size) |
} |
} |
+/* 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. |
@@ -3965,6 +4754,11 @@ warn_variable_length_array (const char *name, tree size) |
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. |
@@ -3979,7 +4773,8 @@ static tree |
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; |
@@ -3988,10 +4783,10 @@ grokdeclarator (const struct c_declarator *declarator, |
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 size_varies = false; |
tree decl_attr = declspecs->decl_attr; |
int array_ptr_quals = TYPE_UNQUALIFIED; |
tree array_ptr_attrs = NULL_TREE; |
@@ -4001,21 +4796,36 @@ grokdeclarator (const struct c_declarator *declarator, |
bool bitfield = width != NULL; |
tree element_type; |
struct c_arg_info *arg_info = 0; |
+ addr_space_t as1, as2, address_space; |
+ location_t loc = UNKNOWN_LOCATION; |
+ const char *errmsg; |
+ 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_function: |
case cdk_array: |
+ loc = decl->id_loc; |
+ /* FALL THRU. */ |
+ |
+ case cdk_function: |
case cdk_pointer: |
funcdef_syntax = (decl->kind == cdk_function); |
decl = decl->declarator; |
@@ -4026,17 +4836,23 @@ grokdeclarator (const struct c_declarator *declarator, |
break; |
case cdk_id: |
+ loc = decl->id_loc; |
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 |
@@ -4052,17 +4868,20 @@ grokdeclarator (const struct c_declarator *declarator, |
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_at (loc, "variably modified %qE at file scope", name); |
+ else |
+ error_at (loc, "variably modified field at file scope"); |
type = integer_type_node; |
} |
- size_varies = C_TYPE_VARIABLE_SIZE (type); |
+ size_varies = C_TYPE_VARIABLE_SIZE (type) != 0; |
/* Diagnose defaulting to "int". */ |
@@ -4074,9 +4893,16 @@ grokdeclarator (const struct c_declarator *declarator, |
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 (loc, 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, |
@@ -4101,20 +4927,30 @@ grokdeclarator (const struct c_declarator *declarator, |
constp = declspecs->const_p + TYPE_READONLY (element_type); |
restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); |
volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); |
+ as1 = declspecs->address_space; |
+ as2 = TYPE_ADDR_SPACE (element_type); |
+ address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; |
+ |
if (pedantic && !flag_isoc99) |
{ |
if (constp > 1) |
- pedwarn (input_location, OPT_pedantic, "duplicate %<const%>"); |
+ pedwarn (loc, OPT_pedantic, "duplicate %<const%>"); |
if (restrictp > 1) |
- pedwarn (input_location, OPT_pedantic, "duplicate %<restrict%>"); |
+ pedwarn (loc, OPT_pedantic, "duplicate %<restrict%>"); |
if (volatilep > 1) |
- pedwarn (input_location, OPT_pedantic, "duplicate %<volatile%>"); |
+ pedwarn (loc, OPT_pedantic, "duplicate %<volatile%>"); |
} |
+ |
+ if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) |
+ error_at (loc, "conflicting named address spaces (%s vs %s)", |
+ c_addr_space_name (as1), c_addr_space_name (as2)); |
+ |
if (!flag_gen_aux_info && (TYPE_QUALS (element_type))) |
type = TYPE_MAIN_VARIANT (type); |
type_quals = ((constp ? TYPE_QUAL_CONST : 0) |
| (restrictp ? TYPE_QUAL_RESTRICT : 0) |
- | (volatilep ? TYPE_QUAL_VOLATILE : 0)); |
+ | (volatilep ? TYPE_QUAL_VOLATILE : 0) |
+ | ENCODE_QUAL_ADDR_SPACE (address_space)); |
/* Warn about storage classes that are invalid for certain |
kinds of declarations (parameters, typenames, etc.). */ |
@@ -4126,15 +4962,15 @@ grokdeclarator (const struct c_declarator *declarator, |
|| storage_class == csc_typedef)) |
{ |
if (storage_class == csc_auto) |
- pedwarn (input_location, |
- (current_scope == file_scope) ? 0 : OPT_pedantic, |
+ pedwarn (loc, |
+ (current_scope == file_scope) ? 0 : OPT_pedantic, |
"function definition declared %<auto%>"); |
if (storage_class == csc_register) |
- error ("function definition declared %<register%>"); |
+ error_at (loc, "function definition declared %<register%>"); |
if (storage_class == csc_typedef) |
- error ("function definition declared %<typedef%>"); |
+ error_at (loc, "function definition declared %<typedef%>"); |
if (threadp) |
- error ("function definition declared %<__thread%>"); |
+ error_at (loc, "function definition declared %<__thread%>"); |
threadp = false; |
if (storage_class == csc_auto |
|| storage_class == csc_register |
@@ -4150,14 +4986,21 @@ grokdeclarator (const struct c_declarator *declarator, |
switch (decl_context) |
{ |
case FIELD: |
- error ("storage class specified for structure field %qs", |
- name); |
+ if (name) |
+ error_at (loc, "storage class specified for structure " |
+ "field %qE", name); |
+ else |
+ error_at (loc, "storage class specified for structure field"); |
break; |
case PARM: |
- error ("storage class specified for parameter %qs", name); |
+ if (name) |
+ error_at (loc, "storage class specified for parameter %qE", |
+ name); |
+ else |
+ error_at (loc, "storage class specified for unnamed parameter"); |
break; |
default: |
- error ("storage class specified for typename"); |
+ error_at (loc, "storage class specified for typename"); |
break; |
} |
storage_class = csc_none; |
@@ -4174,28 +5017,30 @@ grokdeclarator (const struct c_declarator *declarator, |
/* 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_at (loc, 0, "%qE initialized and declared %<extern%>", |
+ name); |
} |
else |
- error ("%qs has both %<extern%> and initializer", name); |
+ error_at (loc, "%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_at (loc, "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_at (loc, "nested function %qE declared %<extern%>", name); |
else if (threadp && storage_class == csc_none) |
{ |
- error ("function-scope %qs implicitly auto and declared " |
- "%<__thread%>", |
- name); |
+ error_at (loc, "function-scope %qE implicitly auto and declared " |
+ "%<__thread%>", |
+ name); |
threadp = false; |
} |
} |
@@ -4240,7 +5085,7 @@ grokdeclarator (const struct c_declarator *declarator, |
/* Only the innermost declarator (making a parameter be of |
array type which is converted to pointer type) |
may have static or type qualifiers. */ |
- error ("static or type qualifiers in non-parameter array declarator"); |
+ error_at (loc, "static or type qualifiers in non-parameter array declarator"); |
array_ptr_quals = TYPE_UNQUALIFIED; |
array_ptr_attrs = NULL_TREE; |
array_parm_static = 0; |
@@ -4287,18 +5132,26 @@ grokdeclarator (const struct c_declarator *declarator, |
if (VOID_TYPE_P (type)) |
{ |
- error ("declaration of %qs as array of voids", name); |
+ if (name) |
+ error_at (loc, "declaration of %qE as array of voids", name); |
+ else |
+ error_at (loc, "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_at (loc, "declaration of %qE as array of functions", |
+ name); |
+ else |
+ error_at (loc, "declaration of type name as array of " |
+ "functions"); |
type = error_mark_node; |
} |
if (pedantic && !in_system_header && flexible_array_type_p (type)) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"invalid use of structure with flexible array member"); |
if (size == error_mark_node) |
@@ -4313,33 +5166,72 @@ grokdeclarator (const struct c_declarator *declarator, |
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_at (loc, "size of array %qE has non-integer type", |
+ name); |
+ else |
+ error_at (loc, |
+ "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 (TREE_CODE (size) == INTEGER_CST) |
+ if (pedantic && size_maybe_const && integer_zerop (size)) |
+ { |
+ if (name) |
+ pedwarn (loc, OPT_pedantic, |
+ "ISO C forbids zero-size array %qE", name); |
+ else |
+ pedwarn (loc, OPT_pedantic, |
+ "ISO C forbids zero-size array"); |
+ } |
+ |
+ 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_at (loc, "size of array %qE is negative", name); |
+ else |
+ error_at (loc, "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 = true; |
+ 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_at (loc, "variably modified %qE at file scope", name); |
size = integer_one_node; |
} |
else |
@@ -4347,11 +5239,11 @@ grokdeclarator (const struct c_declarator *declarator, |
/* 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 = true; |
+ 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 |
@@ -4365,16 +5257,19 @@ grokdeclarator (const struct c_declarator *declarator, |
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 it is a variable the computations will be |
done in the proper mode. */ |
- itype = fold_build2 (MINUS_EXPR, index_type, |
- convert (index_type, size), |
- convert (index_type, |
- size_one_node)); |
+ itype = fold_build2_loc (loc, MINUS_EXPR, index_type, |
+ convert (index_type, size), |
+ convert (index_type, |
+ size_one_node)); |
/* If that overflowed, the array is too big. ??? |
While a size of INT_MAX+1 technically shouldn't |
@@ -4386,13 +5281,26 @@ grokdeclarator (const struct c_declarator *declarator, |
if (TREE_CODE (itype) == INTEGER_CST |
&& TREE_OVERFLOW (itype)) |
{ |
- error ("size of array %qs is too large", name); |
+ if (name) |
+ error_at (loc, "size of array %qE is too large", |
+ name); |
+ else |
+ error_at (loc, "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) |
{ |
@@ -4403,7 +5311,7 @@ grokdeclarator (const struct c_declarator *declarator, |
the field variably modified, not through being |
something other than a declaration with function |
prototype scope. */ |
- size_varies = 1; |
+ size_varies = true; |
else |
{ |
const struct c_declarator *t = declarator; |
@@ -4413,7 +5321,7 @@ grokdeclarator (const struct c_declarator *declarator, |
} |
if (flexible_array_member |
&& pedantic && !flag_isoc99 && !in_system_header) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C90 does not support flexible array members"); |
/* ISO C99 Flexible array members are effectively |
@@ -4427,7 +5335,7 @@ grokdeclarator (const struct c_declarator *declarator, |
if (array_parm_vla_unspec_p) |
{ |
itype = build_range_type (sizetype, size_zero_node, NULL_TREE); |
- size_varies = 1; |
+ size_varies = true; |
} |
} |
else if (decl_context == TYPENAME) |
@@ -4441,14 +5349,14 @@ grokdeclarator (const struct c_declarator *declarator, |
otherwise be modified below. */ |
itype = build_range_type (sizetype, size_zero_node, |
NULL_TREE); |
- size_varies = 1; |
+ size_varies = true; |
} |
} |
/* Complain about arrays of incomplete types. */ |
if (!COMPLETE_TYPE_P (type)) |
{ |
- error ("array type has incomplete element type"); |
+ error_at (loc, "array type has incomplete element type"); |
type = error_mark_node; |
} |
else |
@@ -4458,7 +5366,14 @@ grokdeclarator (const struct c_declarator *declarator, |
it, but here we want to make sure we don't ever |
modify the shared type, so we gcc_assert (itype) |
below. */ |
- type = build_array_type (type, itype); |
+ { |
+ addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); |
+ if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) |
+ type = build_qualified_type (type, |
+ ENCODE_QUAL_ADDR_SPACE (as)); |
+ |
+ type = build_array_type (type, itype); |
+ } |
if (type != error_mark_node) |
{ |
@@ -4483,6 +5398,7 @@ grokdeclarator (const struct c_declarator *declarator, |
gcc_assert (itype); |
TYPE_SIZE (type) = bitsize_zero_node; |
TYPE_SIZE_UNIT (type) = size_zero_node; |
+ SET_TYPE_STRUCTURAL_EQUALITY (type); |
} |
if (array_parm_vla_unspec_p) |
{ |
@@ -4490,6 +5406,7 @@ grokdeclarator (const struct c_declarator *declarator, |
/* The type is complete. C99 6.7.5.2p4 */ |
TYPE_SIZE (type) = bitsize_zero_node; |
TYPE_SIZE_UNIT (type) = size_zero_node; |
+ SET_TYPE_STRUCTURAL_EQUALITY (type); |
} |
} |
@@ -4498,7 +5415,7 @@ grokdeclarator (const struct c_declarator *declarator, |
|| array_ptr_attrs != NULL_TREE |
|| array_parm_static)) |
{ |
- error ("static or type qualifiers in non-parameter array declarator"); |
+ error_at (loc, "static or type qualifiers in non-parameter array declarator"); |
array_ptr_quals = TYPE_UNQUALIFIED; |
array_ptr_attrs = NULL_TREE; |
array_parm_static = 0; |
@@ -4525,17 +5442,33 @@ grokdeclarator (const struct c_declarator *declarator, |
if (type == error_mark_node) |
continue; |
- size_varies = 0; |
+ size_varies = false; |
/* 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_at (loc, "%qE declared as function returning a " |
+ "function", name); |
+ else |
+ error_at (loc, "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_at (loc, "%qE declared as function returning an array", |
+ name); |
+ else |
+ error_at (loc, "type name declared as function returning " |
+ "an array"); |
+ type = integer_type_node; |
+ } |
+ errmsg = targetm.invalid_return_type (type); |
+ if (errmsg) |
+ { |
+ error (errmsg); |
type = integer_type_node; |
} |
@@ -4557,10 +5490,10 @@ grokdeclarator (const struct c_declarator *declarator, |
function definitions in ISO C; GCC used to used |
them for noreturn functions. */ |
if (VOID_TYPE_P (type) && really_funcdef) |
- pedwarn (input_location, 0, |
+ pedwarn (loc, 0, |
"function definition has qualified void return type"); |
else |
- warning (OPT_Wignored_qualifiers, |
+ warning_at (loc, OPT_Wignored_qualifiers, |
"type qualifiers ignored on function return type"); |
type = c_build_qualified_type (type, type_quals); |
@@ -4590,11 +5523,11 @@ grokdeclarator (const struct c_declarator *declarator, |
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE |
&& type_quals) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C forbids qualified function types"); |
if (type_quals) |
type = c_build_qualified_type (type, type_quals); |
- size_varies = 0; |
+ size_varies = false; |
/* When the pointed-to type involves components of variable size, |
care must be taken to ensure that the size evaluation code is |
@@ -4623,10 +5556,10 @@ grokdeclarator (const struct c_declarator *declarator, |
&& (decl_context == NORMAL || decl_context == FIELD) |
&& variably_modified_type_p (type, NULL_TREE)) |
{ |
- tree decl = build_decl (TYPE_DECL, NULL_TREE, type); |
+ tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type); |
DECL_ARTIFICIAL (decl) = 1; |
pushdecl (decl); |
- finish_decl (decl, NULL_TREE, NULL_TREE); |
+ finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE); |
TYPE_NAME (type) = decl; |
} |
@@ -4648,9 +5581,62 @@ grokdeclarator (const struct c_declarator *declarator, |
/* Now TYPE has the actual type, apart from any qualifiers in |
TYPE_QUALS. */ |
+ /* Warn about address space used for things other than static memory or |
+ pointers. */ |
+ address_space = DECODE_QUAL_ADDR_SPACE (type_quals); |
+ if (!ADDR_SPACE_GENERIC_P (address_space)) |
+ { |
+ if (decl_context == NORMAL) |
+ { |
+ switch (storage_class) |
+ { |
+ case csc_auto: |
+ error ("%qs combined with %<auto%> qualifier for %qE", |
+ c_addr_space_name (address_space), name); |
+ break; |
+ case csc_register: |
+ error ("%qs combined with %<register%> qualifier for %qE", |
+ c_addr_space_name (address_space), name); |
+ break; |
+ case csc_none: |
+ if (current_function_scope) |
+ { |
+ error ("%qs specified for auto variable %qE", |
+ c_addr_space_name (address_space), name); |
+ break; |
+ } |
+ break; |
+ case csc_static: |
+ case csc_extern: |
+ case csc_typedef: |
+ break; |
+ default: |
+ gcc_unreachable (); |
+ } |
+ } |
+ else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) |
+ { |
+ if (name) |
+ error ("%qs specified for parameter %qE", |
+ c_addr_space_name (address_space), name); |
+ else |
+ error ("%qs specified for unnamed parameter", |
+ c_addr_space_name (address_space)); |
+ } |
+ else if (decl_context == FIELD) |
+ { |
+ if (name) |
+ error ("%qs specified for structure field %qE", |
+ c_addr_space_name (address_space), name); |
+ else |
+ error ("%qs specified for structure field", |
+ c_addr_space_name (address_space)); |
+ } |
+ } |
+ |
/* 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? */ |
@@ -4659,7 +5645,10 @@ grokdeclarator (const struct c_declarator *declarator, |
&& 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_at (loc, "size of array %qE is too large", name); |
+ else |
+ error_at (loc, "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; |
@@ -4672,16 +5661,36 @@ grokdeclarator (const struct c_declarator *declarator, |
tree decl; |
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE |
&& type_quals) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"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); |
- DECL_SOURCE_LOCATION (decl) = declarator->id_loc; |
+ decl = build_decl (declarator->id_loc, |
+ TYPE_DECL, declarator->u.id, type); |
if (declspecs->explicit_signed_p) |
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; |
if (declspecs->inline_p) |
- pedwarn (input_location, 0,"typedef %q+D declared %<inline%>", decl); |
+ pedwarn (loc, 0,"typedef %q+D declared %<inline%>", decl); |
+ |
+ if (warn_cxx_compat && declarator->u.id != NULL_TREE) |
+ { |
+ struct c_binding *b = I_TAG_BINDING (declarator->u.id); |
+ |
+ if (b != NULL |
+ && b->decl != NULL_TREE |
+ && (B_IN_CURRENT_SCOPE (b) |
+ || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b))) |
+ && TYPE_MAIN_VARIANT (b->decl) != TYPE_MAIN_VARIANT (type)) |
+ { |
+ warning_at (declarator->id_loc, OPT_Wc___compat, |
+ ("using %qD as both a typedef and a tag is " |
+ "invalid in C++"), |
+ decl); |
+ if (b->locus != UNKNOWN_LOCATION) |
+ inform (b->locus, "originally defined here"); |
+ } |
+ } |
+ |
return decl; |
} |
@@ -4696,7 +5705,7 @@ grokdeclarator (const struct c_declarator *declarator, |
&& !declspecs->inline_p); |
if (pedantic && TREE_CODE (type) == FUNCTION_TYPE |
&& type_quals) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C forbids const or volatile function types"); |
if (type_quals) |
type = c_build_qualified_type (type, type_quals); |
@@ -4707,8 +5716,8 @@ grokdeclarator (const struct c_declarator *declarator, |
&& variably_modified_type_p (type, NULL_TREE)) |
{ |
/* C99 6.7.2.1p8 */ |
- pedwarn (input_location, OPT_pedantic, |
- "a member of a structure or union cannot have a variably modified type"); |
+ pedwarn (loc, OPT_pedantic, "a member of a structure or union cannot " |
+ "have a variably modified type"); |
} |
/* Aside from typedefs and type names (handle above), |
@@ -4724,7 +5733,7 @@ grokdeclarator (const struct c_declarator *declarator, |
&& !(storage_class == csc_static |
|| storage_class == csc_register))))) |
{ |
- error ("variable or field %qs declared void", name); |
+ error_at (loc, "variable or field %qE declared void", name); |
type = integer_type_node; |
} |
@@ -4754,15 +5763,15 @@ grokdeclarator (const struct c_declarator *declarator, |
/* We don't yet implement attributes in this context. */ |
if (array_ptr_attrs != NULL_TREE) |
- warning (OPT_Wattributes, |
- "attributes in parameter array declarator ignored"); |
+ warning_at (loc, OPT_Wattributes, |
+ "attributes in parameter array declarator ignored"); |
- size_varies = 0; |
+ size_varies = false; |
} |
else if (TREE_CODE (type) == FUNCTION_TYPE) |
{ |
if (type_quals) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C forbids qualified function types"); |
if (type_quals) |
type = c_build_qualified_type (type, type_quals); |
@@ -4772,8 +5781,8 @@ grokdeclarator (const struct c_declarator *declarator, |
else if (type_quals) |
type = c_build_qualified_type (type, type_quals); |
- decl = build_decl (PARM_DECL, declarator->u.id, type); |
- DECL_SOURCE_LOCATION (decl) = declarator->id_loc; |
+ decl = build_decl (declarator->id_loc, |
+ PARM_DECL, declarator->u.id, type); |
if (size_varies) |
C_DECL_VARIABLE_SIZE (decl) = 1; |
@@ -4789,7 +5798,7 @@ grokdeclarator (const struct c_declarator *declarator, |
DECL_ARG_TYPE (decl) = promoted_type; |
if (declspecs->inline_p) |
- pedwarn (input_location, 0, "parameter %q+D declared %<inline%>", decl); |
+ pedwarn (loc, 0, "parameter %q+D declared %<inline%>", decl); |
} |
else if (decl_context == FIELD) |
{ |
@@ -4802,18 +5811,21 @@ grokdeclarator (const struct c_declarator *declarator, |
if (TREE_CODE (type) == FUNCTION_TYPE) |
{ |
- error ("field %qs declared as a function", name); |
+ error_at (loc, "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_at (loc, "field %qE has incomplete type", name); |
+ else |
+ error_at (loc, "unnamed field has incomplete type"); |
type = error_mark_node; |
} |
type = c_build_qualified_type (type, type_quals); |
- decl = build_decl (FIELD_DECL, declarator->u.id, type); |
- DECL_SOURCE_LOCATION (decl) = declarator->id_loc; |
+ decl = build_decl (declarator->id_loc, |
+ FIELD_DECL, declarator->u.id, type); |
DECL_NONADDRESSABLE_P (decl) = bitfield; |
if (bitfield && !declarator->u.id) |
TREE_NO_WARNING (decl) = 1; |
@@ -4825,7 +5837,7 @@ grokdeclarator (const struct c_declarator *declarator, |
{ |
if (storage_class == csc_register || threadp) |
{ |
- error ("invalid storage class for function %qs", name); |
+ error_at (loc, "invalid storage class for function %qE", name); |
} |
else if (current_scope != file_scope) |
{ |
@@ -4835,10 +5847,11 @@ grokdeclarator (const struct c_declarator *declarator, |
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 (loc, OPT_pedantic, |
+ "invalid storage class for function %qE", name); |
else if (storage_class == csc_static) |
{ |
- error ("invalid storage class for function %qs", name); |
+ error_at (loc, "invalid storage class for function %qE", name); |
if (funcdef_flag) |
storage_class = declspecs->storage_class = csc_none; |
else |
@@ -4846,19 +5859,19 @@ grokdeclarator (const struct c_declarator *declarator, |
} |
} |
- decl = build_decl (FUNCTION_DECL, declarator->u.id, type); |
- DECL_SOURCE_LOCATION (decl) = declarator->id_loc; |
+ decl = build_decl (declarator->id_loc, |
+ FUNCTION_DECL, declarator->u.id, type); |
decl = build_decl_attribute_variant (decl, decl_attr); |
if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl)) |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C forbids qualified function types"); |
/* GNU C interprets a volatile-qualified function type to indicate |
that the function does not return. */ |
if ((type_quals & TYPE_QUAL_VOLATILE) |
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) |
- warning (0, "%<noreturn%> function returns non-void value"); |
+ warning_at (loc, 0, "%<noreturn%> function returns non-void value"); |
/* Every function declaration is an external reference |
(DECL_EXTERNAL) except for those which are not at file |
@@ -4894,7 +5907,7 @@ grokdeclarator (const struct c_declarator *declarator, |
if (flag_hosted && MAIN_NAME_P (declarator->u.id)) |
{ |
if (declspecs->inline_p) |
- pedwarn (input_location, 0, "cannot inline function %<main%>"); |
+ pedwarn (loc, 0, "cannot inline function %<main%>"); |
} |
else if (declspecs->inline_p) |
/* Record that the function is declared `inline'. */ |
@@ -4923,17 +5936,17 @@ grokdeclarator (const struct c_declarator *declarator, |
&& global_decl != visible_decl |
&& TREE_CODE (global_decl) == VAR_DECL |
&& !TREE_PUBLIC (global_decl)) |
- error ("variable previously declared %<static%> redeclared " |
- "%<extern%>"); |
+ error_at (loc, "variable previously declared %<static%> " |
+ "redeclared %<extern%>"); |
} |
- decl = build_decl (VAR_DECL, declarator->u.id, type); |
- DECL_SOURCE_LOCATION (decl) = declarator->id_loc; |
+ decl = build_decl (declarator->id_loc, |
+ VAR_DECL, declarator->u.id, type); |
if (size_varies) |
C_DECL_VARIABLE_SIZE (decl) = 1; |
if (declspecs->inline_p) |
- pedwarn (input_location, 0, "variable %q+D declared %<inline%>", decl); |
+ pedwarn (loc, 0, "variable %q+D declared %<inline%>", decl); |
/* At file scope, an initialized extern declaration may follow |
a static declaration. In that case, DECL_EXTERNAL will be |
@@ -4960,11 +5973,18 @@ grokdeclarator (const struct c_declarator *declarator, |
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_at (loc, "non-nested function with variably modified type"); |
+ else |
+ error_at (loc, "object with variably modified type must have " |
+ "no linkage"); |
} |
/* Record `register' declaration for warnings on & |
@@ -5001,6 +6021,19 @@ grokdeclarator (const struct c_declarator *declarator, |
name of a variable. Thus, if it's known before this, die horribly. */ |
gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)); |
+ if (warn_cxx_compat |
+ && TREE_CODE (decl) == VAR_DECL |
+ && TREE_PUBLIC (decl) |
+ && TREE_STATIC (decl) |
+ && (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE |
+ || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE |
+ || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) |
+ && TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE) |
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat, |
+ ("non-local variable %qD with anonymous type is " |
+ "questionable in C++"), |
+ decl); |
+ |
return decl; |
} |
} |
@@ -5051,6 +6084,7 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag) |
{ |
tree parm, type, typelt; |
unsigned int parmno; |
+ const char *errmsg; |
/* If there is a parameter of incomplete type in a definition, |
this is an error. In a declaration this is valid, and a |
@@ -5074,26 +6108,40 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag) |
if (funcdef_flag) |
{ |
if (DECL_NAME (parm)) |
- error ("parameter %u (%q+D) has incomplete type", |
- parmno, parm); |
+ error_at (input_location, |
+ "parameter %u (%q+D) has incomplete type", |
+ parmno, parm); |
else |
- error ("%Jparameter %u has incomplete type", |
- parm, parmno); |
+ error_at (DECL_SOURCE_LOCATION (parm), |
+ "parameter %u has incomplete type", |
+ parmno); |
TREE_VALUE (typelt) = error_mark_node; |
TREE_TYPE (parm) = error_mark_node; |
+ arg_types = NULL_TREE; |
} |
else if (VOID_TYPE_P (type)) |
{ |
if (DECL_NAME (parm)) |
- warning (0, "parameter %u (%q+D) has void type", |
- parmno, parm); |
+ warning_at (input_location, 0, |
+ "parameter %u (%q+D) has void type", |
+ parmno, parm); |
else |
- warning (0, "%Jparameter %u has void type", |
- parm, parmno); |
+ warning_at (DECL_SOURCE_LOCATION (parm), 0, |
+ "parameter %u has void type", |
+ parmno); |
} |
} |
+ errmsg = targetm.invalid_parameter_type (type); |
+ if (errmsg) |
+ { |
+ error (errmsg); |
+ TREE_VALUE (typelt) = error_mark_node; |
+ TREE_TYPE (parm) = error_mark_node; |
+ arg_types = NULL_TREE; |
+ } |
+ |
if (DECL_NAME (parm) && TREE_USED (parm)) |
warn_if_shadowing (parm); |
} |
@@ -5255,6 +6303,11 @@ get_parm_info (bool ellipsis) |
type itself. FUNCTION_DECLs appear when there is an implicit |
function declaration in the parameter list. */ |
+ /* When we reinsert this decl in the function body, we need |
+ to reconstruct whether it was marked as nested. */ |
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL |
+ ? b->nested |
+ : !b->nested); |
TREE_CHAIN (decl) = others; |
others = decl; |
/* fall through */ |
@@ -5288,17 +6341,24 @@ get_parm_info (bool ellipsis) |
} |
/* Get the struct, enum or union (CODE says which) with tag NAME. |
- Define the tag as a forward-reference if it is not defined. |
- Return a c_typespec structure for the type specifier. */ |
+ Define the tag as a forward-reference with location LOC if it is |
+ not defined. Return a c_typespec structure for the type |
+ specifier. */ |
struct c_typespec |
-parser_xref_tag (enum tree_code code, tree name) |
+parser_xref_tag (location_t loc, enum tree_code code, tree name) |
{ |
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 |
@@ -5313,6 +6373,35 @@ parser_xref_tag (enum tree_code code, tree name) |
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; |
} |
@@ -5336,7 +6425,7 @@ parser_xref_tag (enum tree_code code, tree name) |
TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); |
} |
- pushtag (name, ref); |
+ pushtag (loc, name, ref); |
ret.spec = ref; |
return ret; |
@@ -5349,40 +6438,53 @@ parser_xref_tag (enum tree_code code, tree name) |
tree |
xref_tag (enum tree_code code, tree name) |
{ |
- return parser_xref_tag (code, name).spec; |
+ return parser_xref_tag (input_location, code, name).spec; |
} |
/* 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. */ |
+ LOC is the location of the struct's definition. |
+ CODE says which kind of tag NAME ought to be. |
+ |
+ This stores the current value of the file static STRUCT_PARSE_INFO |
+ in *ENCLOSING_STRUCT_PARSE_INFO, and points STRUCT_PARSE_INFO at a |
+ new c_struct_parse_info structure. The old value of |
+ STRUCT_PARSE_INFO is restored in finish_struct. */ |
tree |
-start_struct (enum tree_code code, tree name) |
+start_struct (location_t loc, enum tree_code code, tree name, |
+ struct c_struct_parse_info **enclosing_struct_parse_info) |
{ |
/* 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; |
} |
@@ -5393,11 +6495,29 @@ start_struct (enum tree_code code, tree name) |
if (ref == NULL_TREE || TREE_CODE (ref) != code) |
{ |
ref = make_node (code); |
- pushtag (name, ref); |
+ pushtag (loc, name, ref); |
} |
C_TYPE_BEING_DEFINED (ref) = 1; |
TYPE_PACKED (ref) = flag_pack_struct; |
+ |
+ *enclosing_struct_parse_info = struct_parse_info; |
+ struct_parse_info = XNEW (struct c_struct_parse_info); |
+ struct_parse_info->struct_types = VEC_alloc (tree, heap, 0); |
+ struct_parse_info->fields = VEC_alloc (c_binding_ptr, heap, 0); |
+ struct_parse_info->typedefs_seen = 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; |
} |
@@ -5467,12 +6587,31 @@ grokfield (location_t loc, |
} |
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, loc, NULL_TREE, NULL_TREE, NULL_TREE); |
DECL_INITIAL (value) = width; |
+ if (warn_cxx_compat && DECL_NAME (value) != NULL_TREE) |
+ { |
+ /* If we currently have a binding for this field, set the |
+ in_struct field in the binding, so that we warn about lookups |
+ which find it. */ |
+ struct c_binding *b = I_SYMBOL_BINDING (DECL_NAME (value)); |
+ if (b != NULL) |
+ { |
+ /* If the in_struct field is not yet set, push it on a list |
+ to be cleared when this struct is finished. */ |
+ if (!b->in_struct) |
+ { |
+ VEC_safe_push (c_binding_ptr, heap, |
+ struct_parse_info->fields, b); |
+ b->in_struct = 1; |
+ } |
+ } |
+ } |
+ |
return value; |
} |
@@ -5533,12 +6672,76 @@ detect_field_duplicates (tree fieldlist) |
} |
} |
+/* Finish up struct info used by -Wc++-compat. */ |
+ |
+static void |
+warn_cxx_compat_finish_struct (tree fieldlist) |
+{ |
+ unsigned int ix; |
+ tree x; |
+ struct c_binding *b; |
+ |
+ /* 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, and we |
+ only want to issue those warnings if the type is referenced |
+ outside of the struct declaration. */ |
+ for (ix = 0; VEC_iterate (tree, struct_parse_info->struct_types, ix, x); ++ix) |
+ C_TYPE_DEFINED_IN_STRUCT (x) = 1; |
+ |
+ /* The TYPEDEFS_SEEN field of STRUCT_PARSE_INFO is a list of |
+ typedefs used when declaring fields in this struct. If the name |
+ of any of the fields is also a typedef name then the struct would |
+ not parse in C++, because the C++ lookup rules say that the |
+ typedef name would be looked up in the context of the struct, and |
+ would thus be the field rather than the typedef. */ |
+ if (!VEC_empty (tree, struct_parse_info->typedefs_seen) |
+ && fieldlist != NULL_TREE) |
+ { |
+ /* Use a pointer_set using the name of the typedef. We can use |
+ a pointer_set because identifiers are interned. */ |
+ struct pointer_set_t *tset = pointer_set_create (); |
+ |
+ for (ix = 0; |
+ VEC_iterate (tree, struct_parse_info->typedefs_seen, ix, x); |
+ ++ix) |
+ pointer_set_insert (tset, DECL_NAME (x)); |
+ |
+ for (x = fieldlist; x != NULL_TREE; x = TREE_CHAIN (x)) |
+ { |
+ if (pointer_set_contains (tset, DECL_NAME (x))) |
+ { |
+ warning_at (DECL_SOURCE_LOCATION (x), OPT_Wc___compat, |
+ ("using %qD as both field and typedef name is " |
+ "invalid in C++"), |
+ x); |
+ /* FIXME: It would be nice to report the location where |
+ the typedef name is used. */ |
+ } |
+ } |
+ |
+ pointer_set_destroy (tset); |
+ } |
+ |
+ /* For each field which has a binding and which was not defined in |
+ an enclosing struct, clear the in_struct field. */ |
+ for (ix = 0; |
+ VEC_iterate (c_binding_ptr, struct_parse_info->fields, ix, b); |
+ ++ix) |
+ b->in_struct = 0; |
+} |
+ |
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. |
+ LOC is the location of the RECORD_TYPE or UNION_TYPE's definition. |
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_STRUCT_PARSE_INFO is the value of STRUCT_PARSE_INFO when |
+ the struct was started. */ |
tree |
-finish_struct (tree t, tree fieldlist, tree attributes) |
+finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, |
+ struct c_struct_parse_info *enclosing_struct_parse_info) |
{ |
tree x; |
bool toplevel = file_scope == current_scope; |
@@ -5562,16 +6765,16 @@ finish_struct (tree t, tree fieldlist, tree attributes) |
if (TREE_CODE (t) == UNION_TYPE) |
{ |
if (fieldlist) |
- pedwarn (input_location, OPT_pedantic, "union has no named members"); |
+ pedwarn (loc, OPT_pedantic, "union has no named members"); |
else |
- pedwarn (input_location, OPT_pedantic, "union has no members"); |
+ pedwarn (loc, OPT_pedantic, "union has no members"); |
} |
else |
{ |
if (fieldlist) |
- pedwarn (input_location, OPT_pedantic, "struct has no named members"); |
+ pedwarn (loc, OPT_pedantic, "struct has no named members"); |
else |
- pedwarn (input_location, OPT_pedantic, "struct has no members"); |
+ pedwarn (loc, OPT_pedantic, "struct has no members"); |
} |
} |
} |
@@ -5635,25 +6838,28 @@ finish_struct (tree t, tree fieldlist, tree attributes) |
{ |
if (TREE_CODE (t) == UNION_TYPE) |
{ |
- error ("%Jflexible array member in union", x); |
+ error_at (DECL_SOURCE_LOCATION (x), |
+ "flexible array member in union"); |
TREE_TYPE (x) = error_mark_node; |
} |
else if (TREE_CHAIN (x) != NULL_TREE) |
{ |
- error ("%Jflexible array member not at end of struct", x); |
+ error_at (DECL_SOURCE_LOCATION (x), |
+ "flexible array member not at end of struct"); |
TREE_TYPE (x) = error_mark_node; |
} |
else if (!saw_named_field) |
{ |
- error ("%Jflexible array member in otherwise empty struct", x); |
+ error_at (DECL_SOURCE_LOCATION (x), |
+ "flexible array member in otherwise empty struct"); |
TREE_TYPE (x) = error_mark_node; |
} |
} |
- if (pedantic && !in_system_header && TREE_CODE (t) == RECORD_TYPE |
+ if (pedantic && TREE_CODE (t) == RECORD_TYPE |
&& flexible_array_type_p (TREE_TYPE (x))) |
- pedwarn (input_location, OPT_pedantic, |
- "%Jinvalid use of structure with flexible array member", x); |
+ pedwarn (DECL_SOURCE_LOCATION (x), OPT_pedantic, |
+ "invalid use of structure with flexible array member"); |
if (DECL_NAME (x)) |
saw_named_field = 1; |
@@ -5758,11 +6964,11 @@ finish_struct (tree t, tree fieldlist, tree attributes) |
/* If this was supposed to be a transparent union, but we can't |
make it one, warn and turn off the flag. */ |
if (TREE_CODE (t) == UNION_TYPE |
- && TYPE_TRANSPARENT_UNION (t) |
+ && TYPE_TRANSPARENT_AGGR (t) |
&& (!TYPE_FIELDS (t) || TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))) |
{ |
- TYPE_TRANSPARENT_UNION (t) = 0; |
- warning (0, "union cannot be made transparent"); |
+ TYPE_TRANSPARENT_AGGR (t) = 0; |
+ warning_at (loc, 0, "union cannot be made transparent"); |
} |
/* If this structure or union completes the type of any previous |
@@ -5786,6 +6992,11 @@ finish_struct (tree t, tree fieldlist, tree attributes) |
} |
C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)) = 0; |
+ /* Update type location to the one of the definition, instead of e.g. |
+ a forward declaration. */ |
+ if (TYPE_STUB_DECL (t)) |
+ DECL_SOURCE_LOCATION (TYPE_STUB_DECL (t)) = loc; |
+ |
/* Finish debugging output for this type. */ |
rest_of_type_compilation (t, toplevel); |
@@ -5793,7 +7004,25 @@ finish_struct (tree t, tree fieldlist, tree attributes) |
parsing parameters, then arrange for the size of a variable sized type |
to be bound now. */ |
if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE)) |
- add_stmt (build_stmt (DECL_EXPR, build_decl (TYPE_DECL, NULL, t))); |
+ add_stmt (build_stmt (loc, |
+ DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); |
+ |
+ if (warn_cxx_compat) |
+ warn_cxx_compat_finish_struct (fieldlist); |
+ |
+ VEC_free (tree, heap, struct_parse_info->struct_types); |
+ VEC_free (c_binding_ptr, heap, struct_parse_info->fields); |
+ VEC_free (tree, heap, struct_parse_info->typedefs_seen); |
+ XDELETE (struct_parse_info); |
+ |
+ struct_parse_info = enclosing_struct_parse_info; |
+ |
+ /* If this struct is defined inside a struct, add it to |
+ struct_types. */ |
+ if (warn_cxx_compat |
+ && struct_parse_info != NULL |
+ && !in_sizeof && !in_typeof && !in_alignof) |
+ VEC_safe_push (tree, heap, struct_parse_info->struct_types, t); |
return t; |
} |
@@ -5810,37 +7039,41 @@ layout_array_type (tree t) |
/* Begin compiling the definition of an enumeration type. |
NAME is its name (or null if anonymous). |
+ LOC is the enum's location. |
Returns the type object, as yet incomplete. |
Also records info about it so that build_enumerator |
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 (location_t loc, struct c_enum_contents *the_enum, tree name) |
{ |
- 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 (loc, name, enumtype); |
} |
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. */ |
@@ -5853,6 +7086,16 @@ start_enum (struct c_enum_contents *the_enum, tree name) |
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; |
} |
@@ -5992,17 +7235,25 @@ finish_enum (tree enumtype, tree values, tree attributes) |
/* 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 (warn_cxx_compat |
+ && struct_parse_info != NULL |
+ && !in_sizeof && !in_typeof && !in_alignof) |
+ VEC_safe_push (tree, heap, struct_parse_info->struct_types, enumtype); |
+ |
return enumtype; |
} |
/* Build and install a CONST_DECL for one value of the |
current enumeration type (one that was begun with start_enum). |
+ LOC is the location of the enumerator. |
Return a tree-list containing the CONST_DECL and its value. |
Assignment of sequential values by default is handled here. */ |
tree |
-build_enumerator (struct c_enum_contents *the_enum, tree name, tree value, |
- location_t value_loc) |
+build_enumerator (location_t loc, |
+ struct c_enum_contents *the_enum, tree name, tree value) |
{ |
tree decl, type; |
@@ -6014,16 +7265,33 @@ build_enumerator (struct c_enum_contents *the_enum, tree name, tree value, |
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); |
+ error_at (loc, "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 (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); |
+ } |
} |
} |
@@ -6034,14 +7302,14 @@ build_enumerator (struct c_enum_contents *the_enum, tree name, tree value, |
{ |
value = the_enum->enum_next_value; |
if (the_enum->enum_overflow) |
- error ("overflow in enumeration values"); |
+ error_at (loc, "overflow in enumeration values"); |
} |
/* Even though the underlying type of an enum is unspecified, the |
type of enumeration constants is explicitly defined as int |
(6.4.4.3/2 in the C99 Standard). GCC allows any integer type as |
an extension. */ |
else if (!int_fits_type_p (value, integer_type_node)) |
- pedwarn (value_loc, OPT_pedantic, |
+ pedwarn (loc, OPT_pedantic, |
"ISO C restricts enumerator values to range of %<int%>"); |
/* The ISO C Standard mandates enumerators to have type int, even |
@@ -6072,7 +7340,7 @@ build_enumerator (struct c_enum_contents *the_enum, tree name, tree value, |
>= TYPE_PRECISION (integer_type_node) |
&& TYPE_UNSIGNED (type))); |
- decl = build_decl (CONST_DECL, name, type); |
+ decl = build_decl (loc, CONST_DECL, name, type); |
DECL_INITIAL (decl) = convert (type, value); |
pushdecl (decl); |
@@ -6098,8 +7366,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
{ |
tree decl1, old_decl; |
tree restype, resdecl; |
- struct c_label_context_se *nstack_se; |
- struct c_label_context_vm *nstack_vm; |
+ location_t loc; |
current_function_returns_value = 0; /* Assume, until we see it does. */ |
current_function_returns_null = 0; |
@@ -6107,43 +7374,29 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
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; |
- |
/* Indicate no valid break/continue context by setting these variables |
to some non-null, non-label value. We'll notice and emit the proper |
error message in c_finish_bc_stmt. */ |
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 (decl1 == 0) |
- { |
- label_context_stack_se = label_context_stack_se->next; |
- label_context_stack_vm = label_context_stack_vm->next; |
- return 0; |
- } |
+ return 0; |
+ |
+ loc = DECL_SOURCE_LOCATION (decl1); |
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); |
+ warning_at (loc, OPT_Wattributes, |
+ "inline function %qD given attribute noinline", |
+ decl1); |
/* Handle gnu_inline attribute. */ |
if (declspecs->inline_p |
@@ -6160,7 +7413,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) |
{ |
- error ("return type is an incomplete type"); |
+ error_at (loc, "return type is an incomplete type"); |
/* Make it return void instead. */ |
TREE_TYPE (decl1) |
= build_function_type (void_type_node, |
@@ -6168,7 +7421,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
} |
if (warn_about_return_type) |
- pedwarn_c99 (input_location, flag_isoc99 ? 0 |
+ pedwarn_c99 (loc, flag_isoc99 ? 0 |
: (warn_return_type ? OPT_Wreturn_type : OPT_Wimplicit_int), |
"return type defaults to %<int%>"); |
@@ -6214,7 +7467,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
{ |
tree ext_decl, ext_type; |
ext_decl = b->decl; |
- ext_type = b->type ? b->type : TREE_TYPE (ext_decl); |
+ ext_type = b->u.type ? b->u.type : TREE_TYPE (ext_decl); |
if (TREE_CODE (ext_type) == FUNCTION_TYPE |
&& comptypes (TREE_TYPE (TREE_TYPE (decl1)), |
TREE_TYPE (ext_type))) |
@@ -6235,15 +7488,16 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
&& 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"); |
+ warning_at (loc, OPT_Wstrict_prototypes, |
+ "function declaration isn%'t a prototype"); |
/* Optionally warn of any global def with no previous 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); |
+ warning_at (loc, OPT_Wmissing_prototypes, |
+ "no previous prototype for %qD", decl1); |
/* Optionally warn of any def with no previous prototype |
if the function has already been used. */ |
else if (warn_missing_prototypes |
@@ -6251,15 +7505,16 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
&& 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); |
+ warning_at (loc, OPT_Wmissing_prototypes, |
+ "%qD was used with no prototype before its definition", decl1); |
/* Optionally warn of any global def with no previous declaration. */ |
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); |
+ warning_at (loc, OPT_Wmissing_declarations, |
+ "no previous declaration for %qD", |
+ decl1); |
/* Optionally warn of any def with no previous declaration |
if the function has already been used. */ |
else if (warn_missing_declarations |
@@ -6267,8 +7522,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
&& 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); |
+ warning_at (loc, OPT_Wmissing_declarations, |
+ "%qD was used with no declaration before its definition", decl1); |
/* This function exists in static storage. |
(This does not mean `static' in the C sense!) */ |
@@ -6291,12 +7546,13 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
{ |
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) |
!= integer_type_node) |
- pedwarn (input_location, OPT_Wmain, "return type of %q+D is not %<int%>", decl1); |
+ pedwarn (loc, OPT_Wmain, "return type of %qD is not %<int%>", decl1); |
check_main_parameter_types (decl1); |
if (!TREE_PUBLIC (decl1)) |
- pedwarn (input_location, OPT_Wmain, "%q+D is normally a non-static function", decl1); |
+ pedwarn (loc, OPT_Wmain, |
+ "%qD is normally a non-static function", decl1); |
} |
/* Record the decl so that the function name is defined. |
@@ -6309,7 +7565,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, |
declare_parm_level (); |
restype = TREE_TYPE (TREE_TYPE (current_function_decl)); |
- resdecl = build_decl (RESULT_DECL, NULL_TREE, restype); |
+ resdecl = build_decl (loc, RESULT_DECL, NULL_TREE, restype); |
DECL_ARTIFICIAL (resdecl) = 1; |
DECL_IGNORED_P (resdecl) = 1; |
DECL_RESULT (current_function_decl) = resdecl; |
@@ -6330,8 +7586,9 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) |
if (current_scope->bindings) |
{ |
- error ("%Jold-style parameter declarations in prototyped " |
- "function definition", fndecl); |
+ error_at (DECL_SOURCE_LOCATION (fndecl), |
+ "old-style parameter declarations in prototyped " |
+ "function definition"); |
/* Get rid of the old-style declarations. */ |
pop_scope (); |
@@ -6343,9 +7600,8 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) |
its parameter list). */ |
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); |
+ warning_at (DECL_SOURCE_LOCATION (fndecl), OPT_Wtraditional, |
+ "traditional C rejects ISO C style function definitions"); |
/* Now make all the parameter declarations visible in the function body. |
We can bypass most of the grunt work of pushdecl. */ |
@@ -6355,12 +7611,13 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) |
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); |
} |
else |
- error ("%Jparameter name omitted", decl); |
+ error_at (DECL_SOURCE_LOCATION (decl), "parameter name omitted"); |
} |
/* Record the parameter list in the function declaration. */ |
@@ -6372,14 +7629,16 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info) |
DECL_CONTEXT (decl) = current_function_decl; |
if (DECL_NAME (decl)) |
bind (DECL_NAME (decl), decl, current_scope, |
- /*invisible=*/false, /*nested=*/false); |
+ /*invisible=*/false, |
+ /*nested=*/(TREE_CODE (decl) == FUNCTION_DECL), |
+ UNKNOWN_LOCATION); |
} |
/* And all the tag declarations. */ |
for (decl = arg_info->tags; decl; decl = TREE_CHAIN (decl)) |
if (TREE_PURPOSE (decl)) |
bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope, |
- /*invisible=*/false, /*nested=*/false); |
+ /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION); |
} |
/* Subroutine of store_parm_decls which handles old-style function |
@@ -6394,8 +7653,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
struct pointer_set_t *seen_args = pointer_set_create (); |
if (!in_system_header) |
- warning (OPT_Wold_style_definition, "%Jold-style function definition", |
- fndecl); |
+ warning_at (DECL_SOURCE_LOCATION (fndecl), |
+ OPT_Wold_style_definition, "old-style function definition"); |
/* Match each formal parameter name with its declaration. Save each |
decl in the appropriate TREE_PURPOSE slot of the parmids chain. */ |
@@ -6403,7 +7662,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
{ |
if (TREE_VALUE (parm) == 0) |
{ |
- error ("%Jparameter name missing from parameter list", fndecl); |
+ error_at (DECL_SOURCE_LOCATION (fndecl), |
+ "parameter name missing from parameter list"); |
TREE_PURPOSE (parm) = 0; |
continue; |
} |
@@ -6414,12 +7674,14 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
decl = b->decl; |
/* If we got something other than a PARM_DECL it is an error. */ |
if (TREE_CODE (decl) != PARM_DECL) |
- error ("%q+D declared as a non-parameter", decl); |
+ error_at (DECL_SOURCE_LOCATION (decl), |
+ "%qD declared as a non-parameter", decl); |
/* If the declaration is already marked, we have a duplicate |
name. Complain and ignore the duplicate. */ |
else if (pointer_set_contains (seen_args, decl)) |
{ |
- error ("multiple parameters named %q+D", decl); |
+ error_at (DECL_SOURCE_LOCATION (decl), |
+ "multiple parameters named %qD", decl); |
TREE_PURPOSE (parm) = 0; |
continue; |
} |
@@ -6427,7 +7689,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
an int. */ |
else if (VOID_TYPE_P (TREE_TYPE (decl))) |
{ |
- error ("parameter %q+D declared with void type", decl); |
+ error_at (DECL_SOURCE_LOCATION (decl), |
+ "parameter %qD declared with void type", decl); |
TREE_TYPE (decl) = integer_type_node; |
DECL_ARG_TYPE (decl) = integer_type_node; |
layout_decl (decl, 0); |
@@ -6437,16 +7700,30 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
/* If no declaration found, default to int. */ |
else |
{ |
- decl = build_decl (PARM_DECL, TREE_VALUE (parm), integer_type_node); |
+ /* FIXME diagnostics: This should be the location of the argument, |
+ not the FNDECL. E.g., for an old-style declaration |
+ |
+ int f10(v) { blah; } |
+ |
+ We should use the location of the V, not the F10. |
+ Unfortunately, the V is an IDENTIFIER_NODE which has no |
+ location. In the future we need locations for c_arg_info |
+ entries. |
+ |
+ See gcc.dg/Wshadow-3.c for an example of this problem. */ |
+ decl = build_decl (DECL_SOURCE_LOCATION (fndecl), |
+ 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 (input_location, 0, "type of %q+D defaults to %<int%>", decl); |
- else |
- warning (OPT_Wmissing_parameter_type, "type of %q+D defaults to %<int%>", decl); |
+ pedwarn (DECL_SOURCE_LOCATION (decl), |
+ 0, "type of %qD defaults to %<int%>", decl); |
+ else |
+ warning_at (DECL_SOURCE_LOCATION (decl), |
+ OPT_Wmissing_parameter_type, |
+ "type of %qD defaults to %<int%>", decl); |
} |
TREE_PURPOSE (parm) = decl; |
@@ -6465,13 +7742,16 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
if (TREE_TYPE (parm) != error_mark_node |
&& !COMPLETE_TYPE_P (TREE_TYPE (parm))) |
{ |
- error ("parameter %q+D has incomplete type", parm); |
+ error_at (DECL_SOURCE_LOCATION (parm), |
+ "parameter %qD 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); |
+ error_at (DECL_SOURCE_LOCATION (parm), |
+ "declaration for parameter %qD but no such parameter", |
+ parm); |
/* Pretend the parameter was not missing. |
This gets us to a standard state and minimizes |
@@ -6521,13 +7801,22 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
|| 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"); |
+ warning_at (DECL_SOURCE_LOCATION (fndecl), |
+ 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); |
+ /* FIXME diagnostics: This should be the location of |
+ FNDECL, but there is bug when a prototype is |
+ declared inside function context, but defined |
+ outside of it (e.g., gcc.dg/pr15698-2.c). In |
+ which case FNDECL gets the location of the |
+ prototype, not the definition. */ |
+ error_at (input_location, |
+ "number of arguments doesn%'t match prototype"); |
+ |
+ error_at (current_function_prototype_locus, |
+ "prototype declaration"); |
} |
break; |
} |
@@ -6560,11 +7849,13 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
been diagnosed as conflicting with an |
old-style definition and discarded? */ |
if (current_function_prototype_built_in) |
- warning (OPT_pedantic, "promoted argument %qD " |
- "doesn%'t match built-in prototype", parm); |
+ warning_at (DECL_SOURCE_LOCATION (parm), |
+ OPT_pedantic, "promoted argument %qD " |
+ "doesn%'t match built-in prototype", parm); |
else |
{ |
- pedwarn (input_location, OPT_pedantic, "promoted argument %qD " |
+ pedwarn (DECL_SOURCE_LOCATION (parm), |
+ OPT_pedantic, "promoted argument %qD " |
"doesn%'t match prototype", parm); |
pedwarn (current_function_prototype_locus, OPT_pedantic, |
"prototype declaration"); |
@@ -6573,13 +7864,15 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) |
else |
{ |
if (current_function_prototype_built_in) |
- warning (0, "argument %qD doesn%'t match " |
- "built-in prototype", parm); |
+ warning_at (DECL_SOURCE_LOCATION (parm), |
+ 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); |
+ error_at (DECL_SOURCE_LOCATION (parm), |
+ "argument %qD doesn%'t match prototype", parm); |
+ error_at (current_function_prototype_locus, |
+ "prototype declaration"); |
} |
} |
} |
@@ -6695,27 +7988,6 @@ store_parm_decls (void) |
cfun->dont_save_pending_sizes_p = 1; |
} |
-/* Emit diagnostics that require gimple input for detection. Operate on |
- FNDECL and all its nested functions. */ |
- |
-static void |
-c_gimple_diagnostics_recursively (tree fndecl) |
-{ |
- struct cgraph_node *cgn; |
- gimple_seq body = gimple_body (fndecl); |
- |
- /* Handle attribute((warn_unused_result)). Relies on gimple input. */ |
- c_warn_unused_result (body); |
- |
- /* Notice when OpenMP structured block constraints are violated. */ |
- if (flag_openmp) |
- diagnose_omp_structured_block_errors (fndecl); |
- |
- /* Finalize all nested functions now. */ |
- cgn = cgraph_node (fndecl); |
- for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) |
- c_gimple_diagnostics_recursively (cgn->decl); |
-} |
/* Finish up a function declaration and compile that function |
all the way to assembler language output. The free the storage |
@@ -6728,9 +8000,6 @@ 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))) |
{ |
@@ -6756,14 +8025,13 @@ finish_function (void) |
&& TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) |
== integer_type_node && flag_isoc99) |
{ |
- tree stmt = c_finish_return (integer_zero_node); |
/* 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 |
annotate_one_with_locus. A cleaner solution might be to |
ensure ! should_carry_locus_p (stmt), but that needs a flag. |
*/ |
- SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION); |
+ c_finish_return (BUILTINS_LOCATION, integer_zero_node, NULL_TREE); |
} |
/* Tie off the statement tree for this function. */ |
@@ -6800,7 +8068,7 @@ finish_function (void) |
c_determine_visibility (fndecl); |
/* For GNU C extern inline functions disregard inline limits. */ |
- if (DECL_EXTERNAL (fndecl) |
+ if (DECL_EXTERNAL (fndecl) |
&& DECL_DECLARED_INLINE_P (fndecl)) |
DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; |
@@ -6813,8 +8081,8 @@ finish_function (void) |
{ |
if (!decl_function_context (fndecl)) |
{ |
+ invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); |
c_genericize (fndecl); |
- c_gimple_diagnostics_recursively (fndecl); |
/* ??? Objc emits functions after finalizing the compilation unit. |
This should be cleaned up later and this conditional removed. */ |
@@ -6823,7 +8091,6 @@ finish_function (void) |
cgraph_add_new_function (fndecl, false); |
return; |
} |
- |
cgraph_finalize_function (fndecl, false); |
} |
else |
@@ -6846,10 +8113,11 @@ finish_function (void) |
} |
/* Check the declarations given in a for-loop for satisfying the C99 |
- constraints. If exactly one such decl is found, return it. */ |
+ constraints. If exactly one such decl is found, return it. LOC is |
+ the location of the opening parenthesis of the for loop. */ |
tree |
-check_for_loop_decls (void) |
+check_for_loop_decls (location_t loc) |
{ |
struct c_binding *b; |
tree one_decl = NULL_TREE; |
@@ -6861,10 +8129,11 @@ check_for_loop_decls (void) |
/* If we get here, declarations have been used in a for loop without |
the C99 for loop scope. This doesn't make much sense, so don't |
allow it. */ |
- error ("%<for%> loop initial declarations are only allowed in C99 mode"); |
+ error_at (loc, "%<for%> loop initial declarations " |
+ "are only allowed in C99 mode"); |
if (hint) |
{ |
- inform (input_location, |
+ inform (loc, |
"use option -std=c99 or -std=gnu99 to compile your code"); |
hint = false; |
} |
@@ -6895,29 +8164,36 @@ check_for_loop_decls (void) |
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); |
+ { |
+ location_t decl_loc = DECL_SOURCE_LOCATION (decl); |
+ if (TREE_STATIC (decl)) |
+ error_at (decl_loc, |
+ "declaration of static variable %qD in %<for%> loop " |
+ "initial declaration", decl); |
+ else if (DECL_EXTERNAL (decl)) |
+ error_at (decl_loc, |
+ "declaration of %<extern%> variable %qD in %<for%> loop " |
+ "initial declaration", decl); |
+ } |
break; |
case RECORD_TYPE: |
- error ("%<struct %E%> declared in %<for%> loop initial declaration", |
- id); |
+ error_at (loc, |
+ "%<struct %E%> declared in %<for%> loop initial " |
+ "declaration", id); |
break; |
case UNION_TYPE: |
- error ("%<union %E%> declared in %<for%> loop initial declaration", |
- id); |
+ error_at (loc, |
+ "%<union %E%> declared in %<for%> loop initial declaration", |
+ id); |
break; |
case ENUMERAL_TYPE: |
- error ("%<enum %E%> declared in %<for%> loop initial declaration", |
- id); |
+ error_at (loc, "%<enum %E%> declared in %<for%> loop " |
+ "initial declaration", id); |
break; |
default: |
- error ("declaration of non-variable %q+D in %<for%> loop " |
- "initial declaration", decl); |
+ error_at (loc, "declaration of non-variable " |
+ "%qD in %<for%> loop initial declaration", decl); |
} |
n_decls++; |
@@ -6982,21 +8258,6 @@ c_pop_function_context (void) |
warn_about_return_type = p->warn_about_return_type; |
} |
-/* Copy the DECL_LANG_SPECIFIC data associated with DECL. */ |
- |
-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; |
-} |
- |
/* The functions below are required for functionality of doing |
function at once processing in the C front end. Currently these |
functions are not called from anywhere in the C front end, but as |
@@ -7037,7 +8298,7 @@ record_builtin_type (enum rid rid_index, const char *name, tree type) |
id = ridpointers[(int) rid_index]; |
else |
id = get_identifier (name); |
- decl = build_decl (TYPE_DECL, id, type); |
+ decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, id, type); |
pushdecl (decl); |
if (debug_hooks->type_decl) |
debug_hooks->type_decl (decl, false); |
@@ -7141,10 +8402,12 @@ build_null_declspecs (void) |
{ |
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; |
@@ -7165,9 +8428,29 @@ build_null_declspecs (void) |
ret->volatile_p = false; |
ret->restrict_p = false; |
ret->saturating_p = false; |
+ ret->address_space = ADDR_SPACE_GENERIC; |
return ret; |
} |
+/* Add the address space ADDRSPACE to the declaration specifiers |
+ SPECS, returning SPECS. */ |
+ |
+struct c_declspecs * |
+declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) |
+{ |
+ specs->non_sc_seen_p = true; |
+ specs->declspecs_seen_p = true; |
+ |
+ if (!ADDR_SPACE_GENERIC_P (specs->address_space) |
+ && specs->address_space != as) |
+ error ("incompatible address space qualifiers %qs and %qs", |
+ c_addr_space_name (as), |
+ c_addr_space_name (specs->address_space)); |
+ else |
+ specs->address_space = as; |
+ return specs; |
+} |
+ |
/* Add the type qualifier QUAL to the declaration specifiers SPECS, |
returning SPECS. */ |
@@ -7207,7 +8490,8 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual) |
returning SPECS. */ |
struct c_declspecs * |
-declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
+declspecs_add_type (location_t loc, struct c_declspecs *specs, |
+ struct c_typespec spec) |
{ |
tree type = spec.spec; |
specs->non_sc_seen_p = true; |
@@ -7224,7 +8508,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
enum rid i = C_RID_CODE (type); |
if (specs->type) |
{ |
- error ("two or more data types in declaration specifiers"); |
+ error_at (loc, "two or more data types in declaration specifiers"); |
return specs; |
} |
if ((int) i <= (int) RID_LAST_MODIFIER) |
@@ -7236,203 +8520,257 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
case RID_LONG: |
if (specs->long_long_p) |
{ |
- error ("%<long long long%> is too long for GCC"); |
+ error_at (loc, "%<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"); |
+ error_at (loc, |
+ ("both %<long long%> and %<double%> in " |
+ "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 (loc, OPT_Wlong_long, |
+ "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"); |
+ error_at (loc, |
+ ("both %<long%> and %<short%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_void) |
- error ("both %<long%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_bool) |
- error ("both %<long%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_char) |
- error ("both %<long%> and %<char%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<char%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_float) |
- error ("both %<long%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat32) |
- error ("both %<long%> and %<_Decimal32%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<_Decimal32%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat64) |
- error ("both %<long%> and %<_Decimal64%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<_Decimal64%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat128) |
- error ("both %<long%> and %<_Decimal128%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("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"); |
+ error_at (loc, |
+ ("both %<long%> and %<short%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_void) |
- error ("both %<short%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_bool) |
- error ("both %<short%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_char) |
- error ("both %<short%> and %<char%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<char%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_float) |
- error ("both %<short%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_double) |
- error ("both %<short%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat32) |
- error ("both %<short%> and %<_Decimal32%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<_Decimal32%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat64) |
- error ("both %<short%> and %<_Decimal64%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<_Decimal64%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat128) |
- error ("both %<short%> and %<_Decimal128%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("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"); |
+ error_at (loc, |
+ ("both %<signed%> and %<unsigned%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_void) |
- error ("both %<signed%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_bool) |
- error ("both %<signed%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_float) |
- error ("both %<signed%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_double) |
- error ("both %<signed%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat32) |
- error ("both %<signed%> and %<_Decimal32%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<_Decimal32%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat64) |
- error ("both %<signed%> and %<_Decimal64%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<_Decimal64%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat128) |
- error ("both %<signed%> and %<_Decimal128%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("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"); |
+ error_at (loc, |
+ ("both %<signed%> and %<unsigned%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_void) |
- error ("both %<unsigned%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_bool) |
- error ("both %<unsigned%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_float) |
- error ("both %<unsigned%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_double) |
- error ("both %<unsigned%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat32) |
- error ("both %<unsigned%> and %<_Decimal32%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<_Decimal32%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat64) |
- error ("both %<unsigned%> and %<_Decimal64%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<_Decimal64%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat128) |
- error ("both %<unsigned%> and %<_Decimal128%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<_Decimal128%> in " |
+ "declaration specifiers")); |
else |
specs->unsigned_p = true; |
break; |
case RID_COMPLEX: |
dupe = specs->complex_p; |
if (!flag_isoc99 && !in_system_header) |
- pedwarn (input_location, OPT_pedantic, "ISO C90 does not support complex types"); |
+ pedwarn (loc, OPT_pedantic, |
+ "ISO C90 does not support complex types"); |
if (specs->typespec_word == cts_void) |
- error ("both %<complex%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_bool) |
- error ("both %<complex%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat32) |
- error ("both %<complex%> and %<_Decimal32%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Decimal32%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat64) |
- error ("both %<complex%> and %<_Decimal64%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Decimal64%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat128) |
- error ("both %<complex%> and %<_Decimal128%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Decimal128%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_fract) |
- error ("both %<complex%> and %<_Fract%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Fract%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_accum) |
- error ("both %<complex%> and %<_Accum%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Accum%> in " |
+ "declaration specifiers")); |
else if (specs->saturating_p) |
- error ("both %<complex%> and %<_Sat%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Sat%> in " |
+ "declaration specifiers")); |
else |
specs->complex_p = true; |
break; |
case RID_SAT: |
dupe = specs->saturating_p; |
- pedwarn (input_location, OPT_pedantic, "ISO C does not support saturating types"); |
+ pedwarn (loc, OPT_pedantic, |
+ "ISO C does not support saturating types"); |
if (specs->typespec_word == cts_void) |
- error ("both %<_Sat%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_bool) |
- error ("both %<_Sat%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_char) |
- error ("both %<_Sat%> and %<char%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<char%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_int) |
- error ("both %<_Sat%> and %<int%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<int%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_float) |
- error ("both %<_Sat%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_double) |
- error ("both %<_Sat%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat32) |
- error ("both %<_Sat%> and %<_Decimal32%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<_Decimal32%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat64) |
- error ("both %<_Sat%> and %<_Decimal64%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<_Decimal64%> in " |
+ "declaration specifiers")); |
else if (specs->typespec_word == cts_dfloat128) |
- error ("both %<_Sat%> and %<_Decimal128%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<_Decimal128%> in " |
+ "declaration specifiers")); |
else if (specs->complex_p) |
- error ("both %<_Sat%> and %<complex%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<complex%> in " |
+ "declaration specifiers")); |
else |
specs->saturating_p = true; |
break; |
@@ -7441,7 +8779,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
} |
if (dupe) |
- error ("duplicate %qE", type); |
+ error_at (loc, "duplicate %qE", type); |
return specs; |
} |
@@ -7451,117 +8789,144 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
"_Decimal64", "_Decimal128", "_Fract" or "_Accum". */ |
if (specs->typespec_word != cts_none) |
{ |
- error ("two or more data types in declaration specifiers"); |
+ error_at (loc, |
+ "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"); |
+ error_at (loc, |
+ ("both %<long%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->short_p) |
- error ("both %<short%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->signed_p) |
- error ("both %<signed%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->unsigned_p) |
- error ("both %<unsigned%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->complex_p) |
- error ("both %<complex%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<void%> in " |
+ "declaration specifiers")); |
else if (specs->saturating_p) |
- error ("both %<_Sat%> and %<void%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> 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"); |
+ error_at (loc, |
+ ("both %<long%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->short_p) |
- error ("both %<short%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->signed_p) |
- error ("both %<signed%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->unsigned_p) |
- error ("both %<unsigned%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->complex_p) |
- error ("both %<complex%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<complex%> and %<_Bool%> in " |
+ "declaration specifiers")); |
else if (specs->saturating_p) |
- error ("both %<_Sat%> and %<_Bool%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> 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"); |
+ error_at (loc, |
+ ("both %<long%> and %<char%> in " |
+ "declaration specifiers")); |
else if (specs->short_p) |
- error ("both %<short%> and %<char%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<char%> in " |
+ "declaration specifiers")); |
else if (specs->saturating_p) |
- error ("both %<_Sat%> and %<char%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<char%> in " |
+ "declaration specifiers")); |
else |
specs->typespec_word = cts_char; |
return specs; |
case RID_INT: |
if (specs->saturating_p) |
- error ("both %<_Sat%> and %<int%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<int%> in " |
+ "declaration specifiers")); |
else |
specs->typespec_word = cts_int; |
return specs; |
case RID_FLOAT: |
if (specs->long_p) |
- error ("both %<long%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<long%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->short_p) |
- error ("both %<short%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->signed_p) |
- error ("both %<signed%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->unsigned_p) |
- error ("both %<unsigned%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<float%> in " |
+ "declaration specifiers")); |
else if (specs->saturating_p) |
- error ("both %<_Sat%> and %<float%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> 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"); |
+ error_at (loc, |
+ ("both %<long long%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->short_p) |
- error ("both %<short%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<short%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->signed_p) |
- error ("both %<signed%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<signed%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->unsigned_p) |
- error ("both %<unsigned%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<double%> in " |
+ "declaration specifiers")); |
else if (specs->saturating_p) |
- error ("both %<_Sat%> and %<double%> in " |
- "declaration specifiers"); |
+ error_at (loc, |
+ ("both %<_Sat%> 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"; |
@@ -7570,26 +8935,40 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
else |
str = "_Decimal128"; |
if (specs->long_long_p) |
- error ("both %<long long%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<long long%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
if (specs->long_p) |
- error ("both %<long%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<long%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (specs->short_p) |
- error ("both %<short%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<short%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (specs->signed_p) |
- error ("both %<signed%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<signed%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (specs->unsigned_p) |
- error ("both %<unsigned%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<unsigned%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (specs->complex_p) |
- error ("both %<complex%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<complex%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (specs->saturating_p) |
- error ("both %<_Sat%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<_Sat%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (i == RID_DFLOAT32) |
specs->typespec_word = cts_dfloat32; |
else if (i == RID_DFLOAT64) |
@@ -7598,8 +8977,10 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
specs->typespec_word = cts_dfloat128; |
} |
if (!targetm.decimal_float_supported_p ()) |
- error ("decimal floating point not supported for this target"); |
- pedwarn (input_location, OPT_pedantic, |
+ error_at (loc, |
+ ("decimal floating point not supported " |
+ "for this target")); |
+ pedwarn (loc, OPT_pedantic, |
"ISO C does not support decimal floating point"); |
return specs; |
case RID_FRACT: |
@@ -7611,16 +8992,19 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
else |
str = "_Accum"; |
if (specs->complex_p) |
- error ("both %<complex%> and %<%s%> in " |
- "declaration specifiers", str); |
+ error_at (loc, |
+ ("both %<complex%> and %<%s%> in " |
+ "declaration specifiers"), |
+ str); |
else if (i == RID_FRACT) |
specs->typespec_word = cts_fract; |
else |
specs->typespec_word = cts_accum; |
} |
if (!targetm.fixed_point_supported_p ()) |
- error ("fixed-point types not supported for this target"); |
- pedwarn (input_location, OPT_pedantic, |
+ error_at (loc, |
+ "fixed-point types not supported for this target"); |
+ pedwarn (loc, OPT_pedantic, |
"ISO C does not support fixed-point types"); |
return specs; |
default: |
@@ -7638,7 +9022,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
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"); |
+ error_at (loc, "two or more data types in declaration specifiers"); |
else if (TREE_CODE (type) == TYPE_DECL) |
{ |
if (TREE_TYPE (type) == error_mark_node) |
@@ -7649,13 +9033,26 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
specs->decl_attr = DECL_ATTRIBUTES (type); |
specs->typedef_p = true; |
specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type); |
+ |
+ /* If this typedef name is defined in a struct, then a C++ |
+ lookup would return a different value. */ |
+ if (warn_cxx_compat |
+ && I_SYMBOL_BINDING (DECL_NAME (type))->in_struct) |
+ warning_at (loc, OPT_Wc___compat, |
+ "C++ lookup of %qD would return a field, not a type", |
+ type); |
+ |
+ /* If we are parsing a struct, record that a struct field |
+ used a typedef. */ |
+ if (warn_cxx_compat && struct_parse_info != NULL) |
+ VEC_safe_push (tree, heap, struct_parse_info->typedefs_seen, 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); |
+ error_at (loc, "%qE fails to be a typedef or built in type", type); |
else if (TREE_TYPE (t) == error_mark_node) |
; |
else |
@@ -7666,7 +9063,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec) |
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; |
} |
@@ -7687,7 +9095,7 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec) |
&& C_IS_RESERVED_WORD (scspec)); |
i = C_RID_CODE (scspec); |
if (specs->non_sc_seen_p) |
- warning (OPT_Wold_style_declaration, |
+ warning (OPT_Wold_style_declaration, |
"%qE is not at beginning of declaration", scspec); |
switch (i) |
{ |
@@ -7809,7 +9217,7 @@ finish_declspecs (struct c_declspecs *specs) |
else if (specs->complex_p) |
{ |
specs->typespec_word = cts_double; |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (input_location, OPT_pedantic, |
"ISO C does not support plain %<complex%> meaning " |
"%<double complex%>"); |
} |
@@ -7854,7 +9262,7 @@ finish_declspecs (struct c_declspecs *specs) |
specs->type = char_type_node; |
if (specs->complex_p) |
{ |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (input_location, OPT_pedantic, |
"ISO C does not support complex integer types"); |
specs->type = build_complex_type (specs->type); |
} |
@@ -7880,7 +9288,7 @@ finish_declspecs (struct c_declspecs *specs) |
: integer_type_node); |
if (specs->complex_p) |
{ |
- pedwarn (input_location, OPT_pedantic, |
+ pedwarn (input_location, OPT_pedantic, |
"ISO C does not support complex integer types"); |
specs->type = build_complex_type (specs->type); |
} |
@@ -8078,9 +9486,9 @@ c_write_global_declarations (void) |
if (pch_file) |
return; |
- /* 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)) |
+ /* Don't waste time on further processing if -fsyntax-only. |
+ Continue for warning and errors issued during lowering though. */ |
+ if (flag_syntax_only) |
return; |
/* Close the external scope. */ |
@@ -8108,7 +9516,7 @@ c_write_global_declarations (void) |
/* We're done parsing; proceed to optimize and emit assembly. |
FIXME: shouldn't be the front end's responsibility to call this. */ |
- cgraph_optimize (); |
+ cgraph_finalize_compilation_unit (); |
/* After cgraph has had a chance to emit everything that's going to |
be emitted, output debug information for globals. */ |