This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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; };

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]