diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bbf1a83cd29ad8d98e3592d5a980fef16264cb85..949c8e105e647cd4083b73625b69c574ded5981e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,22 @@
+2009-01-01  Jakub Jelinek  <jakub@redhat.com>
+
+	PR c/36489
+	* c-typeck.c (add_pending_init): Add IMPLICIT argument.  Only
+	warn about overwriting initializer with side-effects or
+	-Woverride-init if !IMPLICIT.
+	(output_init_element): Likewise.  Pass IMPLICIT down to
+	add_pending_init.
+	(process_init_element): Add IMPLICIT argument.  Pass it down
+	to output_init_element.
+	(push_init_element, pop_init_level, set_designator): Adjust
+	process_init_element callers.
+	(set_nonincremental_init, set_nonincremental_init_from_string):
+	Adjust add_pending_init callers.
+	(output_pending_init_elements): Adjust output_init_element callers.
+	* c-tree.h (process_init_element): Adjust prototype.
+	* c-parser.c (c_parser_initelt, c_parser_initval): Adjust
+	process_init_element callers.
+
 2008-12-31  Uros Bizjak  <ubizjak@gmail.com>
 
 	* sched-deps.c (sched_analyze_2) [UNSPEC_VOLATILE]: Flush pending
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 8c4a96fdee671b5f08547ac3a25fbce11df6e9fd..99c6c187a1e6060635e8a8b9e48c442872957f8e 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -1,6 +1,6 @@
 /* Parser for C and Objective-C.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
    Parser actions based on the old Bison parser; structure somewhat
@@ -3090,7 +3090,7 @@ c_parser_initelt (c_parser *parser)
 		  init.original_code = ERROR_MARK;
 		  c_parser_error (parser, "expected identifier");
 		  c_parser_skip_until_found (parser, CPP_COMMA, NULL);
-		  process_init_element (init);
+		  process_init_element (init, false);
 		  return;
 		}
 	    }
@@ -3213,7 +3213,7 @@ c_parser_initelt (c_parser *parser)
 		  init.original_code = ERROR_MARK;
 		  c_parser_error (parser, "expected %<=%>");
 		  c_parser_skip_until_found (parser, CPP_COMMA, NULL);
-		  process_init_element (init);
+		  process_init_element (init, false);
 		  return;
 		}
 	    }
@@ -3243,7 +3243,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after)
 	  && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
 	init = default_function_array_conversion (init);
     }
-  process_init_element (init);
+  process_init_element (init, false);
 }
 
 /* Parse a compound statement (possibly a function body) (C90 6.6.2,
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index b7430af4b08f8fc011dafe3752b0f8beebcfc858..395659512ac2759274d3d5623e78bdb7cac9bbcc 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -1,6 +1,7 @@
 /* Definitions for C parsing and type checking.
    Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -575,7 +576,7 @@ extern void push_init_level (int);
 extern struct c_expr pop_init_level (int);
 extern void set_init_index (tree, tree);
 extern void set_init_label (tree);
-extern void process_init_element (struct c_expr);
+extern void process_init_element (struct c_expr, bool);
 extern tree build_compound_literal (tree, tree);
 extern tree c_start_case (tree);
 extern void c_finish_case (tree);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index c751b4f0e917d67b025bc0fefef4b67b91a7cc7b..35c8d232878353824b00d6b8faf2f6ba3fcd0459 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C compiler.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -92,11 +92,11 @@ static int spelling_length (void);
 static char *print_spelling (char *);
 static void warning_init (int, const char *);
 static tree digest_init (tree, tree, bool, int);
-static void output_init_element (tree, bool, tree, tree, int);
+static void output_init_element (tree, bool, tree, tree, int, bool);
 static void output_pending_init_elements (int);
 static int set_designator (int);
 static void push_range_stack (tree);
-static void add_pending_init (tree, tree);
+static void add_pending_init (tree, tree, bool);
 static void set_nonincremental_init (void);
 static void set_nonincremental_init_from_string (tree);
 static tree find_init_member (tree);
@@ -5389,12 +5389,12 @@ push_init_level (int implicit)
 	  if ((TREE_CODE (constructor_type) == RECORD_TYPE
 	       || TREE_CODE (constructor_type) == UNION_TYPE)
 	      && constructor_fields == 0)
-	    process_init_element (pop_init_level (1));
+	    process_init_element (pop_init_level (1), true);
 	  else if (TREE_CODE (constructor_type) == ARRAY_TYPE
 		   && constructor_max_index
 		   && tree_int_cst_lt (constructor_max_index,
 				       constructor_index))
-	    process_init_element (pop_init_level (1));
+	    process_init_element (pop_init_level (1), true);
 	  else
 	    break;
 	}
@@ -5588,7 +5588,7 @@ pop_init_level (int implicit)
       /* When we come to an explicit close brace,
 	 pop any inner levels that didn't have explicit braces.  */
       while (constructor_stack->implicit)
-	process_init_element (pop_init_level (1));
+	process_init_element (pop_init_level (1), true);
 
       gcc_assert (!constructor_range_stack);
     }
@@ -5747,7 +5747,7 @@ set_designator (int array)
       /* Designator list starts at the level of closest explicit
 	 braces.  */
       while (constructor_stack->implicit)
-	process_init_element (pop_init_level (1));
+	process_init_element (pop_init_level (1), true);
       constructor_designated = 1;
       return 0;
     }
@@ -5908,10 +5908,15 @@ set_init_label (tree fieldname)
 
 /* Add a new initializer to the tree of pending initializers.  PURPOSE
    identifies the initializer, either array index or field in a structure.
-   VALUE is the value of that index or field.  */
+   VALUE is the value of that index or field.
+
+   IMPLICIT is true if value comes from pop_init_level (1),
+   the new initializer has been merged with the existing one
+   and thus no warnings should be emitted about overriding an
+   existing initializer.  */
 
 static void
-add_pending_init (tree purpose, tree value)
+add_pending_init (tree purpose, tree value, bool implicit)
 {
   struct init_node *p, **q, *r;
 
@@ -5929,10 +5934,13 @@ add_pending_init (tree purpose, tree value)
 	    q = &p->right;
 	  else
 	    {
-	      if (TREE_SIDE_EFFECTS (p->value))
-		warning_init (0, "initialized field with side-effects overwritten");
-	      else if (warn_override_init)
-		warning_init (OPT_Woverride_init, "initialized field overwritten");
+	      if (!implicit)
+		{
+		  if (TREE_SIDE_EFFECTS (p->value))
+		    warning_init (0, "initialized field with side-effects overwritten");
+		  else if (warn_override_init)
+		    warning_init (OPT_Woverride_init, "initialized field overwritten");
+		}
 	      p->value = value;
 	      return;
 	    }
@@ -5952,10 +5960,13 @@ add_pending_init (tree purpose, tree value)
 	    q = &p->right;
 	  else
 	    {
-	      if (TREE_SIDE_EFFECTS (p->value))
-		warning_init (0, "initialized field with side-effects overwritten");
-	      else if (warn_override_init)
-		warning_init (OPT_Woverride_init, "initialized field overwritten");
+	      if (!implicit)
+		{
+		  if (TREE_SIDE_EFFECTS (p->value))
+		    warning_init (0, "initialized field with side-effects overwritten");
+		  else if (warn_override_init)
+		    warning_init (OPT_Woverride_init, "initialized field overwritten");
+		}
 	      p->value = value;
 	      return;
 	    }
@@ -6140,7 +6151,7 @@ set_nonincremental_init (void)
     return;
 
   FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
-    add_pending_init (index, value);
+    add_pending_init (index, value, false);
   constructor_elements = 0;
   if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
@@ -6230,7 +6241,7 @@ set_nonincremental_init_from_string (tree str)
 	}
 
       value = build_int_cst_wide (type, val[1], val[0]);
-      add_pending_init (purpose, value);
+      add_pending_init (purpose, value, false);
     }
 
   constructor_incremental = 0;
@@ -6303,11 +6314,16 @@ find_init_member (tree field)
 
    PENDING if non-nil means output pending elements that belong
    right after this element.  (PENDING is normally 1;
-   it is 0 while outputting pending elements, to avoid recursion.)  */
+   it is 0 while outputting pending elements, to avoid recursion.)
+
+   IMPLICIT is true if value comes from pop_init_level (1),
+   the new initializer has been merged with the existing one
+   and thus no warnings should be emitted about overriding an
+   existing initializer.  */
 
 static void
 output_init_element (tree value, bool strict_string, tree type, tree field,
-		     int pending)
+		     int pending, bool implicit)
 {
   constructor_elt *celt;
 
@@ -6386,7 +6402,7 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
 	  && tree_int_cst_lt (field, constructor_unfilled_index))
 	set_nonincremental_init ();
 
-      add_pending_init (field, value);
+      add_pending_init (field, value, implicit);
       return;
     }
   else if (TREE_CODE (constructor_type) == RECORD_TYPE
@@ -6412,17 +6428,21 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
 	    }
 	}
 
-      add_pending_init (field, value);
+      add_pending_init (field, value, implicit);
       return;
     }
   else if (TREE_CODE (constructor_type) == UNION_TYPE
 	   && !VEC_empty (constructor_elt, constructor_elements))
     {
-      if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
-				       constructor_elements)->value))
-	warning_init (0, "initialized field with side-effects overwritten");
-      else if (warn_override_init)
-	warning_init (OPT_Woverride_init, "initialized field overwritten");
+      if (!implicit)
+	{
+	  if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
+					   constructor_elements)->value))
+	    warning_init (0,
+			  "initialized field with side-effects overwritten");
+	  else if (warn_override_init)
+	    warning_init (OPT_Woverride_init, "initialized field overwritten");
+	}
 
       /* We can have just one union field set.  */
       constructor_elements = 0;
@@ -6493,7 +6513,7 @@ output_pending_init_elements (int all)
 				  constructor_unfilled_index))
 	    output_init_element (elt->value, true,
 				 TREE_TYPE (constructor_type),
-				 constructor_unfilled_index, 0);
+				 constructor_unfilled_index, 0, false);
 	  else if (tree_int_cst_lt (constructor_unfilled_index,
 				    elt->purpose))
 	    {
@@ -6546,7 +6566,7 @@ output_pending_init_elements (int all)
 	    {
 	      constructor_unfilled_fields = elt->purpose;
 	      output_init_element (elt->value, true, TREE_TYPE (elt->purpose),
-				   elt->purpose, 0);
+				   elt->purpose, 0, false);
 	    }
 	  else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
 	    {
@@ -6609,10 +6629,15 @@ output_pending_init_elements (int all)
    to handle a partly-braced initializer.
 
    Once this has found the correct level for the new element,
-   it calls output_init_element.  */
+   it calls output_init_element.
+
+   IMPLICIT is true if value comes from pop_init_level (1),
+   the new initializer has been merged with the existing one
+   and thus no warnings should be emitted about overriding an
+   existing initializer.  */
 
 void
-process_init_element (struct c_expr value)
+process_init_element (struct c_expr value, bool implicit)
 {
   tree orig_value = value.value;
   int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST;
@@ -6653,12 +6678,12 @@ process_init_element (struct c_expr value)
       if ((TREE_CODE (constructor_type) == RECORD_TYPE
 	   || TREE_CODE (constructor_type) == UNION_TYPE)
 	  && constructor_fields == 0)
-	process_init_element (pop_init_level (1));
+	process_init_element (pop_init_level (1), true);
       else if (TREE_CODE (constructor_type) == ARRAY_TYPE
 	       && (constructor_max_index == 0
 		   || tree_int_cst_lt (constructor_max_index,
 				       constructor_index)))
-	process_init_element (pop_init_level (1));
+	process_init_element (pop_init_level (1), true);
       else
 	break;
     }
@@ -6725,7 +6750,7 @@ process_init_element (struct c_expr value)
 	    {
 	      push_member_name (constructor_fields);
 	      output_init_element (value.value, strict_string,
-				   fieldtype, constructor_fields, 1);
+				   fieldtype, constructor_fields, 1, implicit);
 	      RESTORE_SPELLING_DEPTH (constructor_depth);
 	    }
 	  else
@@ -6815,7 +6840,7 @@ process_init_element (struct c_expr value)
 	    {
 	      push_member_name (constructor_fields);
 	      output_init_element (value.value, strict_string,
-				   fieldtype, constructor_fields, 1);
+				   fieldtype, constructor_fields, 1, implicit);
 	      RESTORE_SPELLING_DEPTH (constructor_depth);
 	    }
 	  else
@@ -6865,7 +6890,7 @@ process_init_element (struct c_expr value)
 	    {
 	      push_array_bounds (tree_low_cst (constructor_index, 1));
 	      output_init_element (value.value, strict_string,
-				   elttype, constructor_index, 1);
+				   elttype, constructor_index, 1, implicit);
 	      RESTORE_SPELLING_DEPTH (constructor_depth);
 	    }
 
@@ -6894,7 +6919,7 @@ process_init_element (struct c_expr value)
 	  /* Now output the actual element.  */
 	  if (value.value)
 	    output_init_element (value.value, strict_string,
-				 elttype, constructor_index, 1);
+				 elttype, constructor_index, 1, implicit);
 
 	  constructor_index
 	    = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
@@ -6919,7 +6944,7 @@ process_init_element (struct c_expr value)
 	{
 	  if (value.value)
 	    output_init_element (value.value, strict_string,
-				 constructor_type, NULL_TREE, 1);
+				 constructor_type, NULL_TREE, 1, implicit);
 	  constructor_fields = 0;
 	}
 
@@ -6935,14 +6960,14 @@ process_init_element (struct c_expr value)
 	  while (constructor_stack != range_stack->stack)
 	    {
 	      gcc_assert (constructor_stack->implicit);
-	      process_init_element (pop_init_level (1));
+	      process_init_element (pop_init_level (1), true);
 	    }
 	  for (p = range_stack;
 	       !p->range_end || tree_int_cst_equal (p->index, p->range_end);
 	       p = p->prev)
 	    {
 	      gcc_assert (constructor_stack->implicit);
-	      process_init_element (pop_init_level (1));
+	      process_init_element (pop_init_level (1), true);
 	    }
 
 	  p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a5600c256139c059752896e0b9208d33e12509cd..001bab0159d03efc755c8134a156a1e476b1ee8f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-01-01  Jakub Jelinek  <jakub@redhat.com>
+
+	PR c/36489
+	* gcc.dg/pr36489.c: New test.
+
 2008-12-31  Daniel Franke  <franke.daniel@gmail.com>
 
 	* gfortran.dg/mapping_2.f90: Fixed testcase.
diff --git a/gcc/testsuite/gcc.dg/pr36489.c b/gcc/testsuite/gcc.dg/pr36489.c
new file mode 100644
index 0000000000000000000000000000000000000000..5cf221615ec33c46963684731c747ac5b6d33814
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr36489.c
@@ -0,0 +1,22 @@
+/* PR c/36489 */
+/* { dg-do compile } */
+/* { dg-options "-Woverride-init" } */
+
+struct A { int a; int b[3]; };
+union B { int a; int b[3]; };
+int t1[10][10]
+  = { [1][2] = 11, [1][3] = 12 };
+int t2[10][10]
+  = { [1][2] = 11, [1] = { [3] = 12 } };	/* { dg-warning "initializ" } */
+int t3[10][10]
+  = { [1][2] = 11, [1][2] = 12 };		/* { dg-warning "initializ" } */
+struct A t4[2]
+  = { [0].b[0] = 1, [0].b[1] = 2, [0].b[2] = 3 };
+struct A t5[2]
+  = { [0].b[0] = 1, [0].b[1] = 2, [0].b = { 3 } }; /* { dg-warning "initializ" } */
+union B t6
+  = { .b[0] = 1, .b[1] = 2, .b[2] = 3 };
+union B t7
+  = { .b[0] = 1, .b[1] = 2, .b = { 2 } };	/* { dg-warning "initializ" } */
+union B t8
+  = { .b[0] = 1, .b[1] = 2, .b[1] = 3 };	/* { dg-warning "initializ" } */