This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
Re: Improve -Wc++-compat to warn about types defined inside structs
"Joseph S. Myers" <joseph@codesourcery.com> writes:
> On Wed, 6 May 2009, Ian Lance Taylor wrote:
>
>> In C it is valid to write
>>
>> struct s1 { struct s2 { int i; } f; };
>> struct s2 v;
>>
>> This is invalid in C++, because struct s2 is defined inside struct s1.
>> The only way to refer to struct s2 is to say s1::s2.
>>
>> The first patch in this message improves the C frontend to warn about
>> this type of case. The only types which can be defined inside a struct
>> (or union) in C are struct, union, and enum types. For those types, I
>> use TYPE_LANG_FLAG_2, now known as C_TYPE_DEFINED_IN_STRUCT, to record
>> whether the type was defined inside a struct.
>
> As I read the patch, it will diagnose both those cases where C++ permits
> the definition inside a struct, and cases where the type is defined inside
> a cast or sizeof in an expression inside the struct definition, which are
> not permitted by C++ at all, but not other cases of types defined in casts
> and sizeof. That is OK, but it would make sense to open a PR to record
> that type definitions in casts and sizeof shouldn't only be caught when
> inside struct definitions. (I don't expect much code actually to use type
> definitions inside casts and sizeof.)
Thanks for pointing that out. I extended the patch to catch types
defined in sizeof/typeof/alignof and in casts. For sizeof/typeof/
alignof it will only issue that warning, not the warning about being
defined in a struct/union.
One issue I noticed is that gcc itself uses a type defined in a cast, in
CONST_CAST in system.h. Therefore, I changed __extension__ to disable
-Wc++-compat. I didn't change the documentation, as by my reading of it
this is covered, though I can certainly see an argument for improving
the documentation.
> The patch should use something other than a TREE_LIST for the struct_types
> list; we'd like eventually to get rid of TREE_LIST, so introducing new
> uses of it is a bad idea.
Good point. I changed it to use VEC(tree,heap), which should be better
in every way.
This updated patch was bootstrapped and tested on i686-pc-linux-gnu.
The 2nd patch in http://gcc.gnu.org/ml/gcc-patches/2009-05/msg00299.html
is unchanged (and still requires approval from a Fortran maintainer).
OK for mainline?
Ian
gcc/ChangeLog:
2009-05-08 Ian Lance Taylor <iant@google.com>
* 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.
(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-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.
objc/ChangeLog:
2009-05-08 Ian Lance Taylor <iant@google.com>
* 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/ChangeLog:
2009-05-08 Ian Lance Taylor <iant@google.com>
* objcp-decl.h (start_struct): Add three new, ignored, macro
parameters.
(finish_struct): Add two new, ignored, macro parameters.
testsuite/ChangeLog:
2009-05-08 Ian Lance Taylor <iant@google.com>
* 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.
Index: c-decl.c
===================================================================
--- c-decl.c (revision 147115)
+++ c-decl.c (working copy)
@@ -126,6 +126,15 @@ static GTY(()) struct stmt_tree_s c_stmt
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. */
@@ -1046,13 +1055,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
@@ -2685,10 +2693,13 @@ define_label (location_t location, tree
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;
@@ -2725,6 +2736,10 @@ lookup_tag (enum tree_code code, tree na
if (thislevel)
pending_xref_error ();
}
+
+ if (ploc != NULL)
+ *ploc = b->locus;
+
return b->decl;
}
@@ -2997,12 +3012,12 @@ shadow_tag_warned (const struct c_declsp
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);
}
}
}
@@ -5512,10 +5527,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;
@@ -5523,7 +5539,7 @@ parser_xref_tag (enum tree_code code, tr
/* 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
@@ -5538,6 +5554,35 @@ parser_xref_tag (enum tree_code code, tr
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;
}
@@ -5561,7 +5606,7 @@ parser_xref_tag (enum tree_code code, tr
TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
}
- pushtag (name, ref);
+ pushtag (name, ref, loc);
ret.spec = ref;
return ret;
@@ -5574,40 +5619,53 @@ parser_xref_tag (enum tree_code code, tr
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;
}
@@ -5618,11 +5676,28 @@ start_struct (enum tree_code code, tree
if (ref == NULL_TREE || TREE_CODE (ref) != code)
{
ref = make_node (code);
- pushtag (name, ref);
+ pushtag (name, ref, loc);
}
C_TYPE_BEING_DEFINED (ref) = 1;
TYPE_PACKED (ref) = flag_pack_struct;
+
+ *enclosing_in_struct = in_struct;
+ *enclosing_struct_types = struct_types;
+ in_struct = true;
+ struct_types = VEC_alloc(tree, heap, 0);
+
+ /* FIXME: This will issue a warning for a use of a type defined
+ within a statement expr used within sizeof, et. al. This is not
+ terribly serious as C++ doesn't permit statement exprs within
+ sizeof anyhow. */
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ warning_at (loc, OPT_Wc___compat,
+ "defining type in %qs expression is invalid in C++",
+ (in_sizeof
+ ? "sizeof"
+ : (in_typeof ? "typeof" : "alignof")));
+
return ref;
}
@@ -5760,14 +5835,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. */
@@ -6020,6 +6103,24 @@ finish_struct (tree t, tree fieldlist, t
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;
}
@@ -6040,32 +6141,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. */
@@ -6078,6 +6182,16 @@ start_enum (struct c_enum_contents *the_
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;
}
@@ -6217,6 +6331,11 @@ finish_enum (tree enumtype, tree values,
/* 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;
}
Index: c-parser.c
===================================================================
--- c-parser.c (revision 147115)
+++ c-parser.c (working copy)
@@ -820,12 +820,14 @@ disable_extension_diagnostics (void)
| (warn_pointer_arith << 1)
| (warn_traditional << 2)
| (flag_iso << 3)
- | (warn_long_long << 4));
+ | (warn_long_long << 4)
+ | (warn_cxx_compat << 5));
cpp_opts->pedantic = pedantic = 0;
warn_pointer_arith = 0;
cpp_opts->warn_traditional = warn_traditional = 0;
flag_iso = 0;
cpp_opts->warn_long_long = warn_long_long = 0;
+ warn_cxx_compat = 0;
return ret;
}
@@ -840,6 +842,7 @@ restore_extension_diagnostics (int flags
cpp_opts->warn_traditional = warn_traditional = (flags >> 2) & 1;
flag_iso = (flags >> 3) & 1;
cpp_opts->warn_long_long = warn_long_long = (flags >> 4) & 1;
+ warn_cxx_compat = (flags >> 5) & 1;
}
/* Possibly kinds of declarator to parse. */
@@ -1617,8 +1620,10 @@ c_parser_enum_specifier (c_parser *parse
struct c_typespec ret;
tree attrs;
tree ident = NULL_TREE;
+ location_t enum_loc;
location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
+ enum_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
attrs = c_parser_attributes (parser);
/* Set the location in case we create a decl now. */
@@ -1627,13 +1632,14 @@ c_parser_enum_specifier (c_parser *parse
{
ident = c_parser_peek_token (parser)->value;
ident_loc = c_parser_peek_token (parser)->location;
+ enum_loc = ident_loc;
c_parser_consume_token (parser);
}
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
/* Parse an enum definition. */
struct c_enum_contents the_enum;
- tree type = start_enum (&the_enum, ident);
+ tree type = start_enum (&the_enum, ident, enum_loc);
tree postfix_attrs;
/* We chain the enumerators in reverse order, then put them in
forward order at the end. */
@@ -1712,7 +1718,7 @@ c_parser_enum_specifier (c_parser *parse
ret.expr_const_operands = true;
return ret;
}
- ret = parser_xref_tag (ENUMERAL_TYPE, ident);
+ ret = parser_xref_tag (ENUMERAL_TYPE, ident, ident_loc);
/* In ISO C, enumerated types can be referred to only if already
defined. */
if (pedantic && !COMPLETE_TYPE_P (ret.spec))
@@ -1769,6 +1775,8 @@ c_parser_struct_or_union_specifier (c_pa
struct c_typespec ret;
tree attrs;
tree ident = NULL_TREE;
+ location_t struct_loc;
+ location_t ident_loc = UNKNOWN_LOCATION;
enum tree_code code;
switch (c_parser_peek_token (parser)->keyword)
{
@@ -1781,6 +1789,7 @@ c_parser_struct_or_union_specifier (c_pa
default:
gcc_unreachable ();
}
+ struct_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
attrs = c_parser_attributes (parser);
/* Set the location in case we create a decl now. */
@@ -1788,13 +1797,18 @@ c_parser_struct_or_union_specifier (c_pa
if (c_parser_next_token_is (parser, CPP_NAME))
{
ident = c_parser_peek_token (parser)->value;
+ ident_loc = c_parser_peek_token (parser)->location;
+ struct_loc = ident_loc;
c_parser_consume_token (parser);
}
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
/* Parse a struct or union definition. Start the scope of the
tag before parsing components. */
- tree type = start_struct (code, ident);
+ bool in_struct;
+ VEC(tree,heap) *struct_types;
+ tree type = start_struct (code, ident, &in_struct, &struct_types,
+ struct_loc);
tree postfix_attrs;
/* We chain the components in reverse order, then put them in
forward order at the end. Each struct-declaration may
@@ -1884,7 +1898,8 @@ c_parser_struct_or_union_specifier (c_pa
}
postfix_attrs = c_parser_attributes (parser);
ret.spec = finish_struct (type, nreverse (contents),
- chainon (attrs, postfix_attrs));
+ chainon (attrs, postfix_attrs),
+ in_struct, struct_types);
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
@@ -1899,7 +1914,7 @@ c_parser_struct_or_union_specifier (c_pa
ret.expr_const_operands = true;
return ret;
}
- ret = parser_xref_tag (code, ident);
+ ret = parser_xref_tag (code, ident, ident_loc);
return ret;
}
@@ -4828,10 +4843,12 @@ c_parser_cast_expression (c_parser *pars
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_typename (c_parser_peek_2nd_token (parser)))
{
+ location_t loc;
struct c_type_name *type_name;
struct c_expr ret;
struct c_expr expr;
c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
type_name = c_parser_type_name (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (type_name == NULL)
@@ -4850,7 +4867,7 @@ c_parser_cast_expression (c_parser *pars
type_name);
expr = c_parser_cast_expression (parser, NULL);
expr = default_function_array_conversion (expr);
- ret.value = c_cast_expr (type_name, expr.value);
+ ret.value = c_cast_expr (type_name, expr.value, loc);
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
return ret;
Index: c-typeck.c
===================================================================
--- c-typeck.c (revision 147115)
+++ c-typeck.c (working copy)
@@ -2246,6 +2246,17 @@ build_external_ref (tree id, int fun, lo
if (TREE_CODE (ref) == CONST_DECL)
{
used_types_insert (TREE_TYPE (ref));
+
+ if (warn_cxx_compat
+ && TREE_CODE (TREE_TYPE (ref)) == ENUMERAL_TYPE
+ && C_TYPE_DEFINED_IN_STRUCT (TREE_TYPE (ref)))
+ {
+ warning_at (loc, OPT_Wc___compat,
+ ("enum constant defined in struct or union "
+ "is not visible in C++"));
+ inform (DECL_SOURCE_LOCATION (ref), "enum constant defined here");
+ }
+
ref = DECL_INITIAL (ref);
TREE_CONSTANT (ref) = 1;
}
@@ -4262,7 +4273,7 @@ build_c_cast (tree type, tree expr)
/* Interpret a cast of expression EXPR to type TYPE. */
tree
-c_cast_expr (struct c_type_name *type_name, tree expr)
+c_cast_expr (struct c_type_name *type_name, tree expr, location_t loc)
{
tree type;
tree type_expr = NULL_TREE;
@@ -4283,6 +4294,15 @@ c_cast_expr (struct c_type_name *type_na
ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret);
C_MAYBE_CONST_EXPR_NON_CONST (ret) = !type_expr_const;
}
+
+ if (CAN_HAVE_LOCATION_P (ret) && !EXPR_HAS_LOCATION (ret))
+ SET_EXPR_LOCATION (ret, loc);
+
+ /* C++ does not permits types to be defined in a cast. */
+ if (warn_cxx_compat && type_name->specs->tag_defined_p)
+ warning_at (loc, OPT_Wc___compat,
+ "defining a type in a cast is invalid in C++");
+
return ret;
}
Index: c-tree.h
===================================================================
--- c-tree.h (revision 147115)
+++ c-tree.h (working copy)
@@ -73,6 +73,10 @@ struct GTY(()) lang_type {
#define C_TYPE_VARIABLE_SIZE(TYPE) TYPE_LANG_FLAG_1 (TYPE)
#define C_DECL_VARIABLE_SIZE(TYPE) DECL_LANG_FLAG_0 (TYPE)
+/* Record whether a type is defined inside a struct or union type.
+ This is used for -Wc++-compat. */
+#define C_TYPE_DEFINED_IN_STRUCT(TYPE) TYPE_LANG_FLAG_2 (TYPE)
+
/* Record whether a typedef for type `int' was actually `signed int'. */
#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
@@ -514,7 +518,7 @@ extern void c_maybe_initialize_eh (void)
extern void finish_decl (tree, tree, tree, tree);
extern tree finish_enum (tree, tree, tree);
extern void finish_function (void);
-extern tree finish_struct (tree, tree, tree);
+extern tree finish_struct (tree, tree, tree, bool, VEC(tree,heap) *);
extern struct c_arg_info *get_parm_info (bool);
extern tree grokfield (location_t, struct c_declarator *,
struct c_declspecs *, tree, tree *);
@@ -532,15 +536,16 @@ extern tree c_builtin_function (tree);
extern tree c_builtin_function_ext_scope (tree);
extern void shadow_tag (const struct c_declspecs *);
extern void shadow_tag_warned (const struct c_declspecs *, int);
-extern tree start_enum (struct c_enum_contents *, tree);
+extern tree start_enum (struct c_enum_contents *, tree, location_t);
extern int start_function (struct c_declspecs *, struct c_declarator *, tree);
extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool,
tree);
-extern tree start_struct (enum tree_code, tree);
+extern tree start_struct (enum tree_code, tree, bool *, VEC(tree,heap) **,
+ location_t);
extern void store_parm_decls (void);
extern void store_parm_decls_from (struct c_arg_info *);
extern tree xref_tag (enum tree_code, tree);
-extern struct c_typespec parser_xref_tag (enum tree_code, tree);
+extern struct c_typespec parser_xref_tag (enum tree_code, tree, location_t);
extern int c_expand_decl (tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
struct c_declarator *);
@@ -604,7 +609,7 @@ extern struct c_expr parser_build_binary
struct c_expr);
extern tree build_conditional_expr (tree, bool, tree, tree);
extern tree build_compound_expr (tree, tree);
-extern tree c_cast_expr (struct c_type_name *, tree);
+extern tree c_cast_expr (struct c_type_name *, tree, location_t);
extern tree build_c_cast (tree, tree);
extern void store_init_value (tree, tree, tree);
extern void error_init (const char *);
Index: objc/objc-act.c
===================================================================
--- objc/objc-act.c (revision 147115)
+++ objc/objc-act.c (working copy)
@@ -415,6 +415,35 @@ FILE *gen_declaration_file;
static int generating_instance_variables = 0;
+/* For building an objc struct. These may not be used when this file
+ is compiled as part of obj-c++. */
+
+static bool objc_building_struct;
+static bool objc_in_struct ATTRIBUTE_UNUSED;
+static VEC(tree,heap) *objc_struct_types ATTRIBUTE_UNUSED;
+
+/* Start building a struct for objc. */
+
+static tree
+objc_start_struct (tree name)
+{
+ gcc_assert (!objc_building_struct);
+ objc_building_struct = true;
+ return start_struct (RECORD_TYPE, name, &objc_in_struct, &objc_struct_types,
+ UNKNOWN_LOCATION);
+}
+
+/* Finish building a struct for objc. */
+
+static tree
+objc_finish_struct (tree type, tree fieldlist)
+{
+ gcc_assert (objc_building_struct);
+ objc_building_struct = false;
+ return finish_struct (type, fieldlist, NULL_TREE, objc_in_struct,
+ objc_struct_types);
+}
+
/* Some platforms pass small structures through registers versus
through an invisible pointer. Determine at what size structure is
the transition point between the two possibilities. */
@@ -434,7 +463,7 @@ generate_struct_by_value_array (void)
char buffer[5];
/* Create an unnamed struct that has `i' character components */
- type = start_struct (RECORD_TYPE, NULL_TREE);
+ type = objc_start_struct (NULL_TREE);
strcpy (buffer, "c1");
field_decl = create_field_decl (char_type_node,
@@ -448,7 +477,7 @@ generate_struct_by_value_array (void)
buffer);
chainon (field_decl_chain, field_decl);
}
- finish_struct (type, field_decl_chain, NULL_TREE);
+ objc_finish_struct (type, field_decl_chain);
aggregate_in_mem[i] = aggregate_value_p (type, 0);
if (!aggregate_in_mem[i])
@@ -788,7 +817,7 @@ static tree
objc_build_struct (tree klass, tree fields, tree super_name)
{
tree name = CLASS_NAME (klass);
- tree s = start_struct (RECORD_TYPE, name);
+ tree s = objc_start_struct (name);
tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE);
tree t, objc_info = NULL_TREE;
@@ -849,7 +878,7 @@ objc_build_struct (tree klass, tree fiel
INIT_TYPE_OBJC_INFO (s);
TYPE_OBJC_INTERFACE (s) = klass;
- s = finish_struct (s, fields, NULL_TREE);
+ s = objc_finish_struct (s, fields);
for (t = TYPE_NEXT_VARIANT (s); t;
t = TYPE_NEXT_VARIANT (t), objc_info = TREE_CHAIN (objc_info))
@@ -2057,8 +2086,7 @@ build_objc_symtab_template (void)
{
tree field_decl, field_decl_chain;
- objc_symtab_template
- = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB));
+ objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB));
/* long sel_ref_cnt; */
field_decl = create_field_decl (long_integer_type_node, "sel_ref_cnt");
@@ -2092,7 +2120,7 @@ build_objc_symtab_template (void)
chainon (field_decl_chain, field_decl);
}
- finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_symtab_template, field_decl_chain);
}
/* Create the initial value for the `defs' field of _objc_symtab.
@@ -2292,8 +2320,7 @@ build_module_descriptor (void)
push_lang_context (lang_name_c); /* extern "C" */
#endif
- objc_module_template
- = start_struct (RECORD_TYPE, get_identifier (UTAG_MODULE));
+ objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE));
/* long version; */
field_decl = create_field_decl (long_integer_type_node, "version");
@@ -2315,7 +2342,7 @@ build_module_descriptor (void)
"symtab");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_module_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_module_template, field_decl_chain);
/* Create an instance of "_objc_module". */
UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES");
@@ -3993,7 +4020,7 @@ build_next_objc_exception_stuff (void)
tree field_decl, field_decl_chain, index, temp_type;
objc_exception_data_template
- = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
+ = objc_start_struct (get_identifier (UTAG_EXCDATA));
/* int buf[OBJC_JBLEN]; */
@@ -4009,7 +4036,7 @@ build_next_objc_exception_stuff (void)
"pointers");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_exception_data_template, field_decl_chain);
/* int _setjmp(...); */
/* If the user includes <setjmp.h>, this shall be superseded by
@@ -4156,8 +4183,7 @@ build_protocol_template (void)
{
tree field_decl, field_decl_chain;
- objc_protocol_template = start_struct (RECORD_TYPE,
- get_identifier (UTAG_PROTOCOL));
+ objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL));
/* struct _objc_class *isa; */
field_decl = create_field_decl (build_pointer_type
@@ -4187,7 +4213,7 @@ build_protocol_template (void)
"class_methods");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_protocol_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_protocol_template, field_decl_chain);
}
static tree
@@ -4237,7 +4263,7 @@ build_method_prototype_list_template (tr
/* Generate an unnamed struct definition. */
- objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
+ objc_ivar_list_record = objc_start_struct (NULL_TREE);
/* int method_count; */
field_decl = create_field_decl (integer_type_node, "method_count");
@@ -4251,7 +4277,7 @@ build_method_prototype_list_template (tr
"method_list");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_ivar_list_record, field_decl_chain);
return objc_ivar_list_record;
}
@@ -4262,8 +4288,7 @@ build_method_prototype_template (void)
tree proto_record;
tree field_decl, field_decl_chain;
- proto_record
- = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE));
+ proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE));
/* SEL _cmd; */
field_decl = create_field_decl (objc_selector_type, "_cmd");
@@ -4273,7 +4298,7 @@ build_method_prototype_template (void)
field_decl = create_field_decl (string_type_node, "method_types");
chainon (field_decl_chain, field_decl);
- finish_struct (proto_record, field_decl_chain, NULL_TREE);
+ objc_finish_struct (proto_record, field_decl_chain);
return proto_record;
}
@@ -4758,8 +4783,7 @@ build_category_template (void)
{
tree field_decl, field_decl_chain;
- objc_category_template = start_struct (RECORD_TYPE,
- get_identifier (UTAG_CATEGORY));
+ objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY));
/* char *category_name; */
field_decl = create_field_decl (string_type_node, "category_name");
@@ -4786,7 +4810,7 @@ build_category_template (void)
"protocol_list");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_category_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_category_template, field_decl_chain);
}
/* struct _objc_selector {
@@ -4797,11 +4821,9 @@ build_category_template (void)
static void
build_selector_template (void)
{
-
tree field_decl, field_decl_chain;
- objc_selector_template
- = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR));
+ objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR));
/* SEL sel_id; */
field_decl = create_field_decl (objc_selector_type, "sel_id");
@@ -4811,7 +4833,7 @@ build_selector_template (void)
field_decl = create_field_decl (string_type_node, "sel_type");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_selector_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_selector_template, field_decl_chain);
}
/* struct _objc_class {
@@ -4847,8 +4869,7 @@ build_class_template (void)
{
tree field_decl, field_decl_chain;
- objc_class_template
- = start_struct (RECORD_TYPE, get_identifier (UTAG_CLASS));
+ objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS));
/* struct _objc_class *isa; */
field_decl = create_field_decl (build_pointer_type (objc_class_template),
@@ -4941,7 +4962,7 @@ build_class_template (void)
"gc_object_type");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_class_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_class_template, field_decl_chain);
}
/* Generate appropriate forward declarations for an implementation. */
@@ -5042,7 +5063,7 @@ build_super_template (void)
{
tree field_decl, field_decl_chain;
- objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER));
+ objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER));
/* struct _objc_object *self; */
field_decl = create_field_decl (objc_object_type, "self");
@@ -5053,7 +5074,7 @@ build_super_template (void)
"super_class");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_super_template, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_super_template, field_decl_chain);
}
/* struct _objc_ivar {
@@ -5069,7 +5090,7 @@ build_ivar_template (void)
tree field_decl, field_decl_chain;
objc_ivar_id = get_identifier (UTAG_IVAR);
- objc_ivar_record = start_struct (RECORD_TYPE, objc_ivar_id);
+ objc_ivar_record = objc_start_struct (objc_ivar_id);
/* char *ivar_name; */
field_decl = create_field_decl (string_type_node, "ivar_name");
@@ -5083,7 +5104,7 @@ build_ivar_template (void)
field_decl = create_field_decl (integer_type_node, "ivar_offset");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_ivar_record, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_ivar_record, field_decl_chain);
return objc_ivar_record;
}
@@ -5099,7 +5120,7 @@ build_ivar_list_template (tree list_type
tree objc_ivar_list_record;
tree field_decl, field_decl_chain;
- objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
+ objc_ivar_list_record = objc_start_struct (NULL_TREE);
/* int ivar_count; */
field_decl = create_field_decl (integer_type_node, "ivar_count");
@@ -5113,7 +5134,7 @@ build_ivar_list_template (tree list_type
"ivar_list");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_ivar_list_record, field_decl_chain);
return objc_ivar_list_record;
}
@@ -5130,7 +5151,7 @@ build_method_list_template (tree list_ty
tree objc_ivar_list_record;
tree field_decl, field_decl_chain;
- objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
+ objc_ivar_list_record = objc_start_struct (NULL_TREE);
/* struct _objc__method_prototype_list *method_next; */
field_decl = create_field_decl (objc_method_proto_list_ptr,
@@ -5149,7 +5170,7 @@ build_method_list_template (tree list_ty
"method_list");
chainon (field_decl_chain, field_decl);
- finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
+ objc_finish_struct (objc_ivar_list_record, field_decl_chain);
return objc_ivar_list_record;
}
@@ -5337,7 +5358,7 @@ build_method_template (void)
tree _SLT_record;
tree field_decl, field_decl_chain;
- _SLT_record = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD));
+ _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD));
/* SEL _cmd; */
field_decl = create_field_decl (objc_selector_type, "_cmd");
@@ -5352,7 +5373,7 @@ build_method_template (void)
"_imp");
chainon (field_decl_chain, field_decl);
- finish_struct (_SLT_record, field_decl_chain, NULL_TREE);
+ objc_finish_struct (_SLT_record, field_decl_chain);
return _SLT_record;
}
Index: objcp/objcp-decl.h
===================================================================
--- objcp/objcp-decl.h (revision 147115)
+++ objcp/objcp-decl.h (working copy)
@@ -1,6 +1,6 @@
/* Process the ObjC-specific declarations and variables for
the Objective-C++ compiler.
- Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
Contributed by Ziemowit Laski <zlaski@apple.com>
This file is part of GCC.
@@ -37,9 +37,9 @@ extern tree objcp_end_compound_stmt (tre
invoke the original C++ functions if needed). */
#ifdef OBJCP_REMAP_FUNCTIONS
-#define start_struct(code, name) \
+#define start_struct(code, name, in_struct, struct_types, loc) \
objcp_start_struct (code, name)
-#define finish_struct(t, fieldlist, attributes) \
+#define finish_struct(t, fieldlist, attributes, in_struct, struct_types) \
objcp_finish_struct (t, fieldlist, attributes)
#define finish_function() \
objcp_finish_function ()
Index: testsuite/gcc.dg/Wcxx-compat-7.c
===================================================================
--- testsuite/gcc.dg/Wcxx-compat-7.c (revision 0)
+++ testsuite/gcc.dg/Wcxx-compat-7.c (revision 0)
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-Wc++-compat" } */
+
+struct s1
+{
+ enum e1 /* { dg-message "note: enum type defined here" } */
+ {
+ A, /* { dg-message "note: enum constant defined here" } */
+ B
+ } f1;
+ struct s2 /* { dg-message "note: struct defined here" } */
+ {
+ struct s3 /* { dg-message "note: struct defined here" } */
+ {
+ enum e1 f3;
+ struct s1 *p1;
+ struct s2 *p2;
+ struct s3 *p3;
+ } f2;
+ union u1 /* { dg-message "note: union defined here" } */
+ {
+ int f4;
+ } f5;
+ struct s3 f6;
+ } f7;
+ struct s2 f8;
+ enum e1 f9;
+};
+
+struct s1 v1;
+enum e1 v2; /* { dg-warning "not visible in C\[+\]\[+\]" } */
+struct s2 v3; /* { dg-warning "not visible in C\[+\]\[+\]" } */
+struct s3 v4; /* { dg-warning "not visible in C\[+\]\[+\]" } */
+union u1 v5; /* { dg-warning "not visible in C\[+\]\[+\]" } */
+int i = A; /* { dg-warning "not visible in C\[+\]\[+\]" } */
Index: testsuite/gcc.dg/Wcxx-compat-8.c
===================================================================
--- testsuite/gcc.dg/Wcxx-compat-8.c (revision 0)
+++ testsuite/gcc.dg/Wcxx-compat-8.c (revision 0)
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-Wc++-compat" } */
+
+struct s1
+{
+ enum e1 /* { dg-message "note: enum type defined here" } */
+ {
+ A = sizeof (struct s2 { int i; }), /* { dg-warning "invalid in C\[+\]\[+\]" } */
+ B
+ } f1;
+};
+struct s2 v1; /* Don't issue another warning about s2. */
+enum e1 v2; /* { dg-warning "not visible in C\[+\]\[+\]" } */
+
+enum e2
+{
+ C = sizeof (struct s3 { int i; }), /* { dg-warning "invalid in C\[+\]\[+\]" } */
+ D = __alignof__ (struct s4 { int i; }), /* { dg-warning "invalid in C\[+\]\[+\]" } */
+ E
+};
+
+struct s3 v3;
+int v4 = C;
+
+__typeof__ (struct s5 { int i; }) v5; /* { dg-warning "invalid in C\[+\]\[+\]" } */
+
+int
+f1(struct s1 *p)
+{
+ return ((struct s2 { int j; } *) p)->j; /* { dg-warning "invalid in C\[+\]\[+\]" } */
+}
Index: testsuite/gcc.dg/pr39084.c
===================================================================
--- testsuite/gcc.dg/pr39084.c (revision 147115)
+++ testsuite/gcc.dg/pr39084.c (working copy)
@@ -1,7 +1,7 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
-struct color { int i; };
+struct color { int i; }; /* { dg-message "note: originally defined here" } */
static const struct color col;
struct color * f(void)
{
Index: testsuite/gcc.dg/c99-tag-1.c
===================================================================
--- testsuite/gcc.dg/c99-tag-1.c (revision 147115)
+++ testsuite/gcc.dg/c99-tag-1.c (working copy)
@@ -24,7 +24,7 @@ foo (void)
/* A specific type shall have its content defined at most once. But we
may redeclare the tag in different scopes. */
{
- struct s0 { int i; };
+ struct s0 { int i; }; /* { dg-message "note: originally defined here" } */
{
struct s0 { long l; };
}
@@ -33,7 +33,7 @@ foo (void)
}
struct s0 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "rede" "struct redef" { target *-*-* } 34 } */
- union u0 { int i; };
+ union u0 { int i; }; /* { dg-message "note: originally defined here" } */
{
union u0 { long l; };
}
@@ -42,7 +42,7 @@ foo (void)
}
union u0 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "rede" "union redef" { target *-*-* } 43 } */
- enum e0 { E0A };
+ enum e0 { E0A }; /* { dg-message "note: originally defined here" } */
{
enum e0 { E0B };
}
Index: testsuite/gcc.dg/pr17188-1.c
===================================================================
--- testsuite/gcc.dg/pr17188-1.c (revision 147115)
+++ testsuite/gcc.dg/pr17188-1.c (working copy)
@@ -5,20 +5,20 @@
/* { dg-do compile } */
/* { dg-options "" } */
-struct s0 { };
+struct s0 { }; /* { dg-message "note: originally defined here" } */
struct s0;
struct s0 { }; /* { dg-error "redefinition of 'struct s0'" } */
-struct s1 { };
+struct s1 { }; /* { dg-message "note: originally defined here" } */
struct s1 { }; /* { dg-error "redefinition of 'struct s1'" } */
-struct s2 { int a : 1; };
+struct s2 { int a : 1; }; /* { dg-message "note: originally defined here" } */
struct s2 { int a : 1; }; /* { dg-error "redefinition of 'struct s2'" } */
-struct s3 { };
+struct s3 { }; /* { dg-message "note: originally defined here" } */
struct s3 { int a : 1; }; /* { dg-error "redefinition of 'struct s3'" } */
-struct s4 { int a : 1; };
+struct s4 { int a : 1; }; /* { dg-message "note: originally defined here" } */
struct s4 { }; /* { dg-error "redefinition of 'struct s4'" } */
struct s5 { int a : 1; };