diff options
author | Ian Lance Taylor <iant@google.com> | 2009-05-11 01:02:40 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2009-05-11 01:02:40 +0000 |
commit | 24b97832e7fdb1be20e493105798dac42999c34a (patch) | |
tree | 6b70d6a26b24127001f8d3a73561028aafd73246 /gcc/c-decl.c | |
parent | 76a5dd01ebb7570ee186acf68fb7943101495536 (diff) | |
download | gcc-24b97832e7fdb1be20e493105798dac42999c34a.zip gcc-24b97832e7fdb1be20e493105798dac42999c34a.tar.gz gcc-24b97832e7fdb1be20e493105798dac42999c34a.tar.bz2 |
basic-block.h (enum profile_status): Break out of struct control_flow_graph.
./: * basic-block.h (enum profile_status): Break out of struct
control_flow_graph.
* cgraph.h (struct inline_summary): Break out of struct
cgraph_local_info.
* cgraphunit.c (enum cgraph_order_sort_kind): New enum, broken out
of struct cgraph_order_sort.
* combine.c (enum undo_kind): New enum, broken out of struct
undo.
* cse.c (struct branch_path): Break out of struct
cse_basic_block_data.
* except.h (enum eh_region_type): Break out of struct eh_region.
* gcc.c (enum add_del): Break out of struct modify_target.
* genrecog.c (enum decision_type): Break out of struct
decision_test.
* ggc-page.c (struct ggc_pch_ondisk): Break out of struct
ggc_pch_data.
* matrix-reorg.c (struct free_info): Break out of struct
matrix_info.
* regmove.c (enum match_use): New enum, broken out of struct
match.
* sched-int.h (enum post_call_group): New enum, broken out of
struct deps.
(struct deps_reg): Break out of struct deps.
* target.h (struct asm_int_op): Break out of struct gcc_target.
* tree-eh.c (struct goto_queue_node): Break out of struct
leh_tf_state.
* tree-inline.h (enum copy_body_cge_which): Break out of
copy_body_data.
* tree-pass.h (enum opt_pass_type): Break out of struct opt_pass.
* c-decl.c (in_struct, struct_types): New static variables.
(pushtag): Add loc parameter. Change all callers.
(lookup_tag): Add ploc parameter. Change all callers.
(check_compound_literal_type): New function.
(parser_xref_tag): Add loc parameter. Change all callers. If
-Wc++-compat, warn about struct/union/enum types defined within a
struct or union.
(start_struct): Add enclosing_in_struct, enclosing_struct_types,
and loc parameters. Change all callers. Change error calls to
error_at, using loc. For a redefinition, if the location of the
original definition is known, report it. Set in_struct and
struct_types. If -Wc++-compat warn if in sizeof, typeof, or
alignof.
(finish_struct): Add new parameters enclosing_in_struct and
enclosing_struct_types. Change all callers. Set
C_TYPE_DEFINED_IN_STRUCT for all struct/union/enum types defined
in the struct. If in a struct, add this struct to struct_types.
(start_enum): Add loc parameter. Change all callers. Use
error_at for errors, using loc. For a redefinition, if the
location of the original definition is known, report it. If in a
struct, add this enum type to struct_types. If -Wc++-compat warn
if in sizeof, typeof, or alignof.
* c-parser.c (disable_extension_diagnostics): Disable
-Wc++-compat.
(enable_extension_diagnostics): Reenable -Wc++-compat if
appropriate.
(c_parser_enum_specifier): Get enum location for start_enum.
(c_parser_struct_or_union_specifier): Get struct location for
start_struct. Save in_struct and struct_types status between
start_struct and finish_struct.
(c_parser_cast_expression): Get location of cast.
(c_parser_alignof_expression): Get location of type.
(c_parser_postfix_expression): Likewise.
(c_parser_postfix_expression_after_paren_type): Add type_loc
parameter. Change all callers. Call
check_compound_literal_type. Use type_loc for error about
variable size type.
* c-typeck.c (build_external_ref): If -Wc++-compat, warn about a
use of an enum constant from an enum type defined in a struct or
union.
(c_cast_expr): Add loc parameter. Change all callers. If
-Wc++-compat, warn about defining a type in a cast.
* c-tree.h (C_TYPE_DEFINED_IN_STRUCT): Define.
(start_enum, start_struct, finish_struct): Update declarations.
(parser_xref_tag, c_cast_expr): Update declarations.
(check_compound_literal_type): Declare.
fortran/:
* gfortran.h (enum gfc_omp_sched_kind): New enum, broken out of
gfc_omp_clauses.
(enum gfc_omp_default_sharing): Likewise.
* module.c (enum gfc_rsym_state): New enum, broken out of
pointer_info.
(enum gfc_wsym_state): Likewise.
* parse.c (enum state_order): New enum, broken out of st_state.
objc/:
* objc-act.c (objc_building_struct): New static variable.
(objc_in_struct, objc_struct_types): New static variables.
(objc_start_struct, objc_finish_struct): New static functions.
(generate_struct_by_value_array): Call objc_start_struct instead
of start_struct, and call objc_finish_struct instead of
finish_struct.
(objc_build_struct, build_objc_symtab_template): Likewise.
(build_module_descriptor): Likewise.
(build_next_objc_exception_stuff): Likewise.
(build_protocol_template): Likewise.
(build_method_prototype_list_template): Likewise.
(build_method_prototype_template): Likewise.
(build_category_template, build_selector_template): Likewise.
(build_class_template, build_super_template): Likewise.
(build_ivar_template, build_ivar_list_template): Likewise.
(build_method_list_template): Likewise.
(build_method_template): Likewise.
objcp/:
* objcp-decl.h (start_struct): Add three new, ignored, macro
parameters.
(finish_struct): Add two new, ignored, macro parameters.
testsuite/:
* gcc.dg/Wcxx-compat-7.c: New testcase.
* gcc.dg/Wcxx-compat-8.c: New testcase.
* gcc.dg/c99-tag-1.c: Recognize new "originally defined here"
notes
* gcc.dg/pr17188-1.c: Likewise.
* gcc.dg/pr39084.c: Likewise.
From-SVN: r147358
Diffstat (limited to 'gcc/c-decl.c')
-rw-r--r-- | gcc/c-decl.c | 188 |
1 files changed, 159 insertions, 29 deletions
diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 5b44153..a9929c1 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -126,6 +126,15 @@ static GTY(()) struct stmt_tree_s c_stmt_tree; tree c_break_label; tree c_cont_label; +/* True if we are currently parsing the fields of a struct or + union. */ + +static bool in_struct; + +/* A list of types defined in the current struct or union. */ + +static VEC(tree,heap) *struct_types; + /* Linked list of TRANSLATION_UNIT_DECLS for the translation units included in this invocation. Note that the current translation unit is not included in this list. */ @@ -1086,13 +1095,12 @@ pop_file_scope (void) In that case, the TYPE_SIZE will be zero. */ static void -pushtag (tree name, tree type) +pushtag (tree name, tree type, location_t loc) { /* Record the identifier as the type's name if it has none. */ if (name && !TYPE_NAME (type)) TYPE_NAME (type) = name; - bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false, - UNKNOWN_LOCATION); + 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 @@ -2725,10 +2733,13 @@ define_label (location_t location, tree 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; @@ -2765,6 +2776,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; } @@ -3037,12 +3052,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 (name, t, input_location); } } } @@ -3897,6 +3912,17 @@ build_compound_literal (tree type, tree init, bool non_const) return complit; } + +/* Check the type of a compound literal. Here we just check that it + is valid for C++. */ + +void +check_compound_literal_type (struct c_type_name *type_name, location_t loc) +{ + if (warn_cxx_compat && type_name->specs->tag_defined_p) + warning_at (loc, OPT_Wc___compat, + "defining a type in a compound literal is invalid in C++"); +} /* Determine whether TYPE is a structure with a flexible array member, or a union containing such a structure (possibly recursively). */ @@ -5555,10 +5581,11 @@ get_parm_info (bool ellipsis) Return a c_typespec structure for the type specifier. */ struct c_typespec -parser_xref_tag (enum tree_code code, tree name) +parser_xref_tag (enum tree_code code, tree name, location_t loc) { struct c_typespec ret; tree ref; + location_t refloc; ret.expr = NULL_TREE; ret.expr_const_operands = true; @@ -5566,7 +5593,7 @@ parser_xref_tag (enum tree_code code, tree name) /* If a cross reference is requested, look up the type already defined for this tag and return it. */ - 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 @@ -5581,6 +5608,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; } @@ -5604,7 +5660,7 @@ parser_xref_tag (enum tree_code code, tree name) TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); } - pushtag (name, ref); + pushtag (name, ref, loc); ret.spec = ref; return ret; @@ -5617,40 +5673,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 (code, name, UNKNOWN_LOCATION).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. */ + CODE says which kind of tag NAME ought to be. + + This stores the current value of the file static IN_STRUCT in + *ENCLOSING_IN_STRUCT, and sets IN_STRUCT to true. Similarly, this + sets STRUCT_TYPES in *ENCLOSING_STRUCT_TYPES, and sets STRUCT_TYPES + to an empty vector. The old values are restored in + finish_struct. */ tree -start_struct (enum tree_code code, tree name) +start_struct (enum tree_code code, tree name, bool *enclosing_in_struct, + VEC(tree,heap) **enclosing_struct_types, location_t loc) { /* If there is already a tag defined at this scope (as a forward reference), just return it. */ - tree ref = 0; + tree ref = NULL_TREE; + location_t refloc = UNKNOWN_LOCATION; - if (name != 0) - ref = lookup_tag (code, name, 1); + if (name != NULL_TREE) + ref = lookup_tag (code, name, 1, &refloc); if (ref && TREE_CODE (ref) == code) { if (TYPE_SIZE (ref)) { if (code == UNION_TYPE) - error ("redefinition of %<union %E%>", name); + error_at (loc, "redefinition of %<union %E%>", name); else - error ("redefinition of %<struct %E%>", name); + error_at (loc, "redefinition of %<struct %E%>", name); + if (refloc != UNKNOWN_LOCATION) + inform (refloc, "originally defined here"); /* Don't create structures using a name already in use. */ ref = NULL_TREE; } else if (C_TYPE_BEING_DEFINED (ref)) { if (code == UNION_TYPE) - error ("nested redefinition of %<union %E%>", name); + error_at (loc, "nested redefinition of %<union %E%>", name); else - error ("nested redefinition of %<struct %E%>", name); + error_at (loc, "nested redefinition of %<struct %E%>", name); + /* Don't bother to report "originally defined here" for a + nested redefinition; the original definition should be + obvious. */ /* Don't create structures that contain themselves. */ ref = NULL_TREE; } @@ -5661,11 +5730,28 @@ start_struct (enum tree_code code, tree name) if (ref == NULL_TREE || TREE_CODE (ref) != code) { ref = make_node (code); - pushtag (name, ref); + pushtag (name, ref, loc); } C_TYPE_BEING_DEFINED (ref) = 1; TYPE_PACKED (ref) = flag_pack_struct; + + *enclosing_in_struct = in_struct; + *enclosing_struct_types = struct_types; + in_struct = true; + struct_types = VEC_alloc(tree, heap, 0); + + /* FIXME: This will issue a warning for a use of a type defined + within a statement expr used within sizeof, et. al. This is not + terribly serious as C++ doesn't permit statement exprs within + sizeof anyhow. */ + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + warning_at (loc, OPT_Wc___compat, + "defining type in %qs expression is invalid in C++", + (in_sizeof + ? "sizeof" + : (in_typeof ? "typeof" : "alignof"))); + return ref; } @@ -5803,14 +5889,22 @@ detect_field_duplicates (tree fieldlist) /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. FIELDLIST is a chain of FIELD_DECL nodes for the fields. - ATTRIBUTES are attributes to be applied to the structure. */ + ATTRIBUTES are attributes to be applied to the structure. + + ENCLOSING_IN_STRUCT is the value of IN_STRUCT, and + ENCLOSING_STRUCT_TYPES is the value of STRUCT_TYPES, when the + struct was started. This sets the C_TYPE_DEFINED_IN_STRUCT flag + for any type defined in the current struct. */ tree -finish_struct (tree t, tree fieldlist, tree attributes) +finish_struct (tree t, tree fieldlist, tree attributes, + bool enclosing_in_struct, + VEC(tree,heap) *enclosing_struct_types) { tree x; bool toplevel = file_scope == current_scope; int saw_named_field; + unsigned int ix; /* If this type was previously laid out as a forward reference, make sure we lay it out again. */ @@ -6063,6 +6157,24 @@ finish_struct (tree t, tree fieldlist, tree attributes) if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE)) add_stmt (build_stmt (DECL_EXPR, build_decl (TYPE_DECL, NULL, t))); + /* Set the C_TYPE_DEFINED_IN_STRUCT flag for each type defined in + the current struct. We do this now at the end of the struct + because the flag is used to issue visibility warnings when using + -Wc++-compat, and we only want to issue those warnings if the + type is referenced outside of the struct declaration. */ + for (ix = 0; VEC_iterate (tree, struct_types, ix, x); ++ix) + C_TYPE_DEFINED_IN_STRUCT (x) = 1; + + VEC_free (tree, heap, struct_types); + + in_struct = enclosing_in_struct; + struct_types = enclosing_struct_types; + + /* If this struct is defined inside a struct, add it to + STRUCT_TYPES. */ + if (in_struct && !in_sizeof && !in_typeof && !in_alignof) + VEC_safe_push (tree, heap, struct_types, t); + return t; } @@ -6083,32 +6195,35 @@ layout_array_type (tree t) may be used to declare the individual values as they are read. */ tree -start_enum (struct c_enum_contents *the_enum, tree name) +start_enum (struct c_enum_contents *the_enum, tree name, location_t loc) { - tree enumtype = 0; + tree enumtype = NULL_TREE; + location_t enumloc = UNKNOWN_LOCATION; /* If this is the real definition for a previous forward reference, fill in the contents in the same object that used to be the forward reference. */ - if (name != 0) - enumtype = lookup_tag (ENUMERAL_TYPE, name, 1); + if (name != NULL_TREE) + enumtype = lookup_tag (ENUMERAL_TYPE, name, 1, &enumloc); if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE) { enumtype = make_node (ENUMERAL_TYPE); - pushtag (name, enumtype); + pushtag (name, enumtype, loc); } if (C_TYPE_BEING_DEFINED (enumtype)) - error ("nested redefinition of %<enum %E%>", name); + error_at (loc, "nested redefinition of %<enum %E%>", name); C_TYPE_BEING_DEFINED (enumtype) = 1; if (TYPE_VALUES (enumtype) != 0) { /* This enum is a named one that has been declared already. */ - error ("redeclaration of %<enum %E%>", name); + error_at (loc, "redeclaration of %<enum %E%>", name); + if (enumloc != UNKNOWN_LOCATION) + inform (enumloc, "originally defined here"); /* Completely replace its old definition. The old enumerators remain defined, however. */ @@ -6121,6 +6236,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; } @@ -6260,6 +6385,11 @@ 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 (in_struct && !in_sizeof && !in_typeof && !in_alignof) + VEC_safe_push (tree, heap, struct_types, enumtype); + return enumtype; } |