diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 771a19bc402..c39f66a4deb 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -41,7 +41,6 @@ static tree finish_init_stmts (bool, tree, tree);
 static void construct_virtual_base (tree, tree);
 static bool expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
 static bool expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
-static void perform_member_init (tree, tree);
 static int member_init_ok_or_else (tree, tree, tree);
 static void expand_virtual_init (tree, tree);
 static tree sort_mem_initializers (tree, tree);
@@ -525,19 +524,19 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
   return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
 }
 
-/* Initialize current class with INIT, a TREE_LIST of
-   arguments for a target constructor. If TREE_LIST is void_type_node,
-   an empty initializer list was given.  */
+/* Initialize current class with INIT, a TREE_LIST of arguments for
+   a target constructor.  If TREE_LIST is void_type_node, an empty
+   initializer list was given.  Return the target constructor.  */
 
-static void
+static tree
 perform_target_ctor (tree init)
 {
   tree decl = current_class_ref;
   tree type = current_class_type;
 
-  finish_expr_stmt (build_aggr_init (decl, init,
-				     LOOKUP_NORMAL|LOOKUP_DELEGATING_CONS,
-				     tf_warning_or_error));
+  init = build_aggr_init (decl, init, LOOKUP_NORMAL|LOOKUP_DELEGATING_CONS,
+			  tf_warning_or_error);
+  finish_expr_stmt (init);
   if (type_build_dtor_call (type))
     {
       tree expr = build_delete (input_location,
@@ -550,6 +549,7 @@ perform_target_ctor (tree init)
 	  && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
 	finish_eh_cleanup (expr);
     }
+  return init;
 }
 
 /* Return the non-static data initializer for FIELD_DECL MEMBER.  */
@@ -775,12 +775,126 @@ maybe_warn_list_ctor (tree member, tree init)
 	     "of the underlying array", member, begin);
 }
 
+/* Data structure for find_uninit_fields_r, below.  */
+
+struct find_uninit_data {
+  /* The set tracking the yet-uninitialized members.  */
+  hash_set<tree> *uninitialized;
+  /* The data member we are currently initializing.  It can be either
+     a type (initializing a base class/delegating constructors), or
+     a COMPONENT_REF.  */
+  tree member;
+};
+
+/* walk_tree callback that warns about using uninitialized data in
+   a member-initializer-list.  */
+
+static tree
+find_uninit_fields_r (tree *tp, int *walk_subtrees, void *data)
+{
+  find_uninit_data *d = static_cast<find_uninit_data *>(data);
+  hash_set<tree> *uninitialized = d->uninitialized;
+  tree init = *tp;
+  const tree_code code = TREE_CODE (init);
+
+  /* No need to look into types or unevaluated operands.  */
+  if (TYPE_P (init) || unevaluated_p (code))
+    {
+      *walk_subtrees = false;
+      return NULL_TREE;
+    }
+
+  switch (code)
+    {
+    /* We'd need data flow info to avoid false positives.  */
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+    /* We might see a MODIFY_EXPR in cases like S() : a((b = 42)), c(b) { }
+       where the initializer for 'a' surreptitiously initializes 'b'.  Let's
+       not bother with these complicated scenarios in the front end.  */
+    case MODIFY_EXPR:
+    /* Don't attempt to handle statement-expressions, either.  */
+    case STATEMENT_LIST:
+      uninitialized->empty ();
+      gcc_fallthrough ();
+    /* If we're just taking the address of an object, it doesn't matter
+       whether it's been initialized.  */
+    case ADDR_EXPR:
+      *walk_subtrees = false;
+      return NULL_TREE;
+    default:
+      break;
+    }
+
+  /* We'd need data flow info to avoid false positives.  */
+  if (truth_value_p (code))
+    goto give_up;
+  /* Attempt to handle a simple a{b}, but no more.  */
+  else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+    {
+      if (CONSTRUCTOR_NELTS (init) == 1
+	  && !BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (init, 0)->value))
+	init = CONSTRUCTOR_ELT (init, 0)->value;
+      else
+	goto give_up;
+    }
+  /* Warn about uninitialized 'this'.  */
+  else if (code == CALL_EXPR)
+    {
+      tree fn = get_callee_fndecl (init);
+      if (fn && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+	{
+	  tree op = CALL_EXPR_ARG (init, 0);
+	  if (TREE_CODE (op) == ADDR_EXPR)
+	    op = TREE_OPERAND (op, 0);
+	  temp_override<tree> ovr (d->member, DECL_ARGUMENTS (fn));
+	  cp_walk_tree_without_duplicates (&op, find_uninit_fields_r, data);
+	}
+      /* Functions may have side effects and initialize other members; it's
+	 not the front end's job to try to figure it out.  */
+      else
+	goto give_up;
+    }
+
+  /* If we find FIELD in the uninitialized set, we warn.  */
+  if (code == COMPONENT_REF)
+    {
+      tree field = TREE_OPERAND (init, 1);
+      tree type = TYPE_P (d->member) ? d->member : TREE_TYPE (d->member);
+
+      /* We're initializing a reference member with itself.  */
+      if (TYPE_REF_P (type) && cp_tree_equal (d->member, init))
+	warning_at (EXPR_LOCATION (init), OPT_Winit_self,
+		    "%qD is initialized with itself", field);
+      else if (cp_tree_equal (TREE_OPERAND (init, 0), current_class_ref)
+	       && uninitialized->contains (field))
+	{
+	  if (TYPE_REF_P (TREE_TYPE (field)))
+	    warning_at (EXPR_LOCATION (init), OPT_Wuninitialized,
+			"reference %qD is not yet bound to a value when used "
+			"here", field);
+	  else if (!INDIRECT_TYPE_P (type) || is_this_parameter (d->member))
+	    warning_at (EXPR_LOCATION (init), OPT_Wuninitialized,
+			"field %qD is used uninitialized", field);
+	  *walk_subtrees = false;
+	}
+    }
+
+  return NULL_TREE;
+
+give_up:
+  *walk_subtrees = false;
+  uninitialized->empty ();
+  return integer_zero_node;
+}
+
 /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
    arguments.  If TREE_LIST is void_type_node, an empty initializer
-   list was given; if NULL_TREE no initializer was given.  */
+   list was given; if NULL_TREE no initializer was given.  UNINITIALIZED
+   is the hash set that tracks uninitialized fields.  */
 
 static void
-perform_member_init (tree member, tree init)
+perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
 {
   tree decl;
   tree type = TREE_TYPE (member);
@@ -808,7 +922,9 @@ perform_member_init (tree member, tree init)
   if (decl == error_mark_node)
     return;
 
-  if (warn_init_self && init && TREE_CODE (init) == TREE_LIST
+  if ((warn_init_self || warn_uninitialized)
+      && init
+      && TREE_CODE (init) == TREE_LIST
       && TREE_CHAIN (init) == NULL_TREE)
     {
       tree val = TREE_VALUE (init);
@@ -820,6 +936,12 @@ perform_member_init (tree member, tree init)
 	warning_at (DECL_SOURCE_LOCATION (current_function_decl),
 		    OPT_Winit_self, "%qD is initialized with itself",
 		    member);
+      else if (!uninitialized.is_empty ())
+	{
+	  find_uninit_data data = { &uninitialized, decl };
+	  cp_walk_tree_without_duplicates (&val, find_uninit_fields_r,
+					   &data);
+	}
     }
 
   if (array_of_unknown_bound_p (type))
@@ -848,6 +970,9 @@ perform_member_init (tree member, tree init)
 	 do aggregate-initialization.  */
     }
 
+  /* Assume we are initializing the member.  */
+  bool member_initialized_p = true;
+
   if (init == void_type_node)
     {
       /* mem() means value-initialization.  */
@@ -988,6 +1113,9 @@ perform_member_init (tree member, tree init)
 	    diagnose_uninitialized_cst_or_ref_member (core_type,
 						      /*using_new=*/false,
 						      /*complain=*/true);
+
+	  /* We left the member uninitialized.  */
+	  member_initialized_p = false;
 	}
 
       maybe_warn_list_ctor (member, init);
@@ -998,6 +1126,11 @@ perform_member_init (tree member, tree init)
 						tf_warning_or_error));
     }
 
+  if (member_initialized_p && warn_uninitialized)
+    /* This member is now initialized, remove it from the uninitialized
+       set.  */
+    uninitialized.remove (member);
+
   if (type_build_dtor_call (type))
     {
       tree expr;
@@ -1311,13 +1444,30 @@ emit_mem_initializers (tree mem_inits)
   if (!COMPLETE_TYPE_P (current_class_type))
     return;
 
+  /* Keep a set holding fields that are not initialized.  */
+  hash_set<tree> uninitialized;
+
+  /* Initially that is all of them.  */
+  if (warn_uninitialized)
+    for (tree field = TYPE_FIELDS (current_class_type); field;
+	 field = TREE_CHAIN (field))
+      if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field))
+	uninitialized.add (field);
+
   if (mem_inits
       && TYPE_P (TREE_PURPOSE (mem_inits))
       && same_type_p (TREE_PURPOSE (mem_inits), current_class_type))
     {
       /* Delegating constructor. */
       gcc_assert (TREE_CHAIN (mem_inits) == NULL_TREE);
-      perform_target_ctor (TREE_VALUE (mem_inits));
+      tree ctor = perform_target_ctor (TREE_VALUE (mem_inits));
+      if (!uninitialized.is_empty ())
+	{
+	  find_uninit_data data = { &uninitialized, current_class_type };
+	  cp_walk_tree_without_duplicates (&ctor,
+					   find_uninit_fields_r,
+					   &data);
+	}
       return;
     }
 
@@ -1378,6 +1528,15 @@ emit_mem_initializers (tree mem_inits)
 			      flags,
                               tf_warning_or_error);
 	  expand_cleanup_for_base (subobject, NULL_TREE);
+	  if (!uninitialized.is_empty ()
+	      && STATEMENT_LIST_TAIL (cur_stmt_list))
+	    {
+	      tree last = STATEMENT_LIST_TAIL (cur_stmt_list)->stmt;
+	      find_uninit_data data = { &uninitialized,
+					BINFO_TYPE (subobject) };
+	      cp_walk_tree_without_duplicates (&last, find_uninit_fields_r,
+					       &data);
+	    }
 	}
       else if (!ABSTRACT_CLASS_TYPE_P (current_class_type))
 	/* C++14 DR1658 Means we do not have to construct vbases of
@@ -1405,7 +1564,9 @@ emit_mem_initializers (tree mem_inits)
       iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
 
       perform_member_init (TREE_PURPOSE (mem_inits),
-			   TREE_VALUE (mem_inits));
+			   TREE_VALUE (mem_inits),
+			   uninitialized);
+
       mem_inits = TREE_CHAIN (mem_inits);
     }
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9fb74d34920..018248f07f4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6982,6 +6982,18 @@ to compute a value that itself is never used, because such
 computations may be deleted by data flow analysis before the warnings
 are printed.
 
+In C++, this warning also warns about using uninitialized objects in
+member-initializer-lists.  For example, GCC warns about @code{b} being
+uninitialized in the following snippet:
+
+@smallexample
+struct A @{
+  int a;
+  int b;
+  A() : a(b) @{ @}
+@};
+@end smallexample
+
 @item -Wno-invalid-memory-model
 @opindex Winvalid-memory-model
 @opindex Wno-invalid-memory-model
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C
new file mode 100644
index 00000000000..62052e7d3c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C
@@ -0,0 +1,31 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+
+struct A {
+  int m;
+  int get() const { return m; }
+
+  A() { }
+  A(int) { }
+  A(const A &) { }
+  A(A *) { }
+};
+
+struct S {
+  A a, b;
+
+  S(int (*)[1]) : a() {}
+  S(int (*)[2]) : b(a.get()) {}
+  S(int (*)[3]) : b(a) {}
+  S(int (*)[4]) : a(&a) {}
+};
+
+struct R {
+  A a, b;
+
+  R(int (*)[1]) : a{} {}
+  R(int (*)[2]) : b{a.get()} {}
+  R(int (*)[3]) : b{a} {}
+  R(int (*)[4]) : a{&a} {}
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-15.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-15.C
new file mode 100644
index 00000000000..3e06f6ebae4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-15.C
@@ -0,0 +1,118 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized -Winit-self" }
+// Largely copied from clang's test/SemaCXX/uninitialized.cpp.
+
+int x;
+struct U {
+  U() : b(a) { }
+  int &a = x;
+  int &b;
+};
+
+struct T {
+  T() : a(b), b(a) { } // { dg-warning "reference .T::b. is not yet bound" }
+  int &a, &b;
+};
+
+struct S {
+  S() : a(a) { } // { dg-warning ".S::a. is initialized with itself" }
+  int &a;
+};
+
+struct A {
+  int a;
+  int b;
+  A() { }
+  A(int (*)[1]) : b(a) { } // { dg-warning ".A::a. is used uninitialized" }
+  A(int (*)[2]) : a(b) { } // { dg-warning ".A::b. is used uninitialized" }
+};
+
+struct D {
+  int a;
+  int &b;
+  int &c = a;
+  int d = b;
+  D() : b(a) { }
+};
+
+struct E {
+  int a;
+  int get();
+  static int num();
+  E() { }
+  E(int) { }
+};
+
+struct F {
+  int a;
+  E e;
+  int b;
+  F(int (*)[1]) : a(e.get()) { } // { dg-warning "field .F::e. is used uninitialized" }
+  F(int (*)[2]) : a(e.num()) { }
+  F(int (*)[3]) : e(a) { } // { dg-warning "field .F::a. is used uninitialized" }
+  F(int (*)[4]) : a(4), e(a) { }
+  F(int (*)[5]) : e(b) { } // { dg-warning "field .F::b. is used uninitialized" }
+  F(int (*)[6]) : e(b), b(4) { } // { dg-warning "field .F::b. is used uninitialized" }
+};
+
+struct G {
+  G(const A&) { };
+};
+
+struct H {
+  A a1;
+  G g;
+  A a2;
+  H() : g(a1) { }
+  // ??? clang++ doesn't warn here
+  H(int) : g(a2) { } // { dg-warning "field .H::a2. is used uninitialized" }
+};
+
+struct I {
+  I(int *) { }
+};
+
+struct J : I {
+  int *a;
+  int *b;
+  int c;
+  J() : I((a = new int(5))), b(a), c(*a) { }
+};
+
+struct M { };
+
+struct N : public M {
+  int a;
+  int b;
+  N() : b(a) { } // { dg-warning "field .N::a. is used uninitialized" }
+};
+
+struct O {
+  int x = 42;
+  int get() { return x; }
+};
+
+struct P {
+  O o;
+  int x = o.get();
+  P() : x(o.get()) { }
+};
+
+struct Q {
+  int a;
+  int b;
+  int &c;
+  Q() :
+    a(c = 5), // "reference .Q::c. is not yet bound" but too complex for the FE
+    b(c), // "reference .Q::c. is not yet bound" but too complex for the FE
+    c(a) { }
+};
+
+struct R {
+  int a;
+  int b;
+  int c;
+  int d = a + b + c;
+  R() : a(c = 5), b(c), c(a) { }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-16.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-16.C
new file mode 100644
index 00000000000..38f587bc024
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-16.C
@@ -0,0 +1,12 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+
+struct S {
+  int a;
+  int b;
+  int c;
+  S() : a((b = 42)), c(b) { }
+  S(int) : a(((1, b) = 42)), c(b) { }
+  S(char) : a(((c++, b) = 42)), c(b) { } // "field .S::c. is used uninitialized" but too complex for the FE
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C
new file mode 100644
index 00000000000..e76a86ca274
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C
@@ -0,0 +1,24 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized -Winit-self" }
+
+int
+foo (int *p)
+{
+  *p = 42;
+  return 5;
+}
+
+struct S {
+  int x;
+  int y;
+  int z;
+  S() : x(foo (&y)), z(y) { } // { dg-bogus "uninitialized" }
+};
+
+struct T {
+  int x;
+  int y;
+  int z;
+  T() : x(({ y = 30; 42; })), z(y) { } // { dg-bogus "uninitialized" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-18.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-18.C
new file mode 100644
index 00000000000..c05ad42f95e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-18.C
@@ -0,0 +1,22 @@
+// PR c++/96121
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+
+struct A {
+  A();
+  int i;
+};
+struct B {
+  B(A);
+  int i;
+};
+
+struct composed2 {
+  B b_;
+  A a_;
+  composed2() : b_(a_) {} // { dg-warning "field .composed2::a_. is used uninitialized" }
+};
+
+composed2 test() {
+    return composed2{};
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-19.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-19.C
new file mode 100644
index 00000000000..c401f8636bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-19.C
@@ -0,0 +1,50 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+// Test we warn when initializing a base class.
+
+struct A {
+  A(int) { }
+};
+
+struct B : public A {
+  int x;
+  B() : A(x) { } // { dg-warning "field .B::x. is used uninitialized" }
+};
+
+struct C : public A {
+  int x;
+  int y;
+  C() : A(y = 4), x(y) { }
+};
+
+struct D : public A {
+  int x;
+  D() : A{x} { } // { dg-warning "field .D::x. is used uninitialized" }
+};
+
+struct E : public A {
+  int x;
+  int y;
+  E() : A{y = 4}, x(y) { }
+};
+
+struct F {
+  F(int&) { }
+};
+
+struct G : F {
+  int x;
+  G() : F(x) { }
+};
+
+struct H {
+  H(int *) { }
+};
+
+struct I : H {
+  int x;
+  int arr[2];
+  I() : H(&x) { }
+  I(int) : H(arr) { }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-20.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-20.C
new file mode 100644
index 00000000000..9f367f0fdfd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-20.C
@@ -0,0 +1,16 @@
+// PR c++/96121
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+// Test we warn with delegating constructors.
+
+struct A {
+  A(int);
+  A(int &, int);
+  A(int (*)[1]) : A(x) { } // { dg-warning "21:field .A::x. is used uninitialized" }
+  A(int (*)[2]) : A(x, x) { } // { dg-warning "24:field .A::x. is used uninitialized" }
+  A(int (*)[3]) : A(x, 0) { }
+  A(int (*)[4]) : A{x} { } // { dg-warning "21:field .A::x. is used uninitialized" }
+  A(int (*)[5]) : A{x, x} { } // { dg-warning "24:field .A::x. is used uninitialized" }
+  A(int (*)[6]) : A{x, 0} { }
+  int x;
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-21.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-21.C
new file mode 100644
index 00000000000..57ca00ab042
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-21.C
@@ -0,0 +1,20 @@
+// PR c++/19808
+// { dg-do compile }
+// { dg-options "-Wuninitialized" }
+
+struct A {
+  int a;
+  int b;
+  A(int) {}
+};
+
+struct S {
+  A a;
+  A a2;
+  S() :
+    /* We don't warn here, because we consider partial initialization
+       as initializing the whole object.  */
+    a((a2.a = 42)),
+    a2(a2.a)
+  { }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-22.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-22.C
new file mode 100644
index 00000000000..003fdd300c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-22.C
@@ -0,0 +1,37 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized -Winit-self" }
+// Test that we don't warn when initializing a reference, unless it's
+// self-init.
+
+struct R {
+  int &r;
+};
+
+struct S {
+  R r;
+  int a;
+  int &b;
+  int c;
+};
+
+struct X {
+  S s;
+  X() : s{ { s.a }, 1, s.c, 3} { }
+};
+
+struct A {
+  int &r;
+  A() : r{r} { } // { dg-warning ".A::r. is initialized with itself" }
+};
+
+struct B {
+  int &r;
+  int a;
+  B() : r{a} { }
+};
+
+struct C {
+  R x;
+  C() : x{x.r} { } // { dg-warning "field .C::x. is used uninitialized" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-23.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-23.C
new file mode 100644
index 00000000000..db3778300be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-23.C
@@ -0,0 +1,24 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+// Test that we don't warn in an uninstantiated template.
+
+struct A {
+  int *fn() { return nullptr; }
+};
+
+template<typename T>
+struct B {
+  B() : p(a->fn()) { }
+  A *a;
+  int *p;
+};
+
+template<typename T>
+struct C {
+  C() : p(a->fn()) { } // { dg-warning "field .C<int>::a. is used uninitialized" }
+  A *a;
+  int *p;
+};
+
+C<int> c;
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C
new file mode 100644
index 00000000000..3f81d52fa69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C
@@ -0,0 +1,89 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized -Winit-self" }
+
+int fint(int);
+int fintp(int *);
+int fintr(int &);
+int fintcr(const int &);
+
+int arr[10];
+
+struct S {
+  int x;
+  int y;
+  const int z = 42;
+  int *p;
+
+  S(int (*)[1]) : x(x) { } // { dg-warning "initialized with itself" }
+  S(int (*)[2]) : x(x + x) { } // { dg-warning "field .S::x. is used uninitialized" }
+  S(int (*)[3]) : x(static_cast<int>(y)) { } // { dg-warning "field .S::y. is used uninitialized" }
+  S(int (*)[4]) : x(static_cast<int>(x)) { } // { dg-warning "field .S::x. is used uninitialized" }
+  S(int (*)[5]) : x(fint(x)) { }
+  S(int (*)[6]) : x(fint(y)) { }
+
+  S(int (*)[7]) : x(sizeof(x)) { }
+  S(int (*)[8]) : x(sizeof(y)) { }
+  S(int (*)[9]) : p(&x) { }
+  S(int (*)[10]) : x(fintp(&y)) { }
+  S(int (*)[11]) : x(fintr(y)) { }
+  S(int (*)[12]) : x(fintcr(y)) { }
+  S(int (*)[26]) : x(((void)(__typeof(y)) 1, 1)) { }
+  S(int (*)[27]) : x(((void)(decltype(y)) 1, 1)) { }
+  S(int (*)[28]) : x(__alignof__(y)) { }
+  S(int (*)[29]) : x(noexcept(y)) { }
+
+  S(int (*)[13]) : x(0), y(x ? y : y) { }
+  S(int (*)[14]) : x(0), y(1 + (x ? y : y)) { }
+  S(int (*)[15]) : x(-y) { } // { dg-warning "field .S::y. is used uninitialized" }
+  S(int (*)[16]) : x(1 << y) { } // { dg-warning "field .S::y. is used uninitialized" }
+  S(int (*)[17]) : x(this->y) { } // { dg-warning "field .S::y. is used uninitialized" }
+  S(int (*)[18]) : x(arr[y]) { } // { dg-warning "field .S::y. is used uninitialized" }
+  S(int (*)[19]) : x(0), y(x ? x : y) { }
+  S(int (*)[20]) : x(0), y(y ? x : y) { }
+  S(int (*)[21]) : x(0), y(y ? x : x) { }
+  S(int (*)[22]) : x(0), y((fint(y), x)) { }
+  S(int (*)[23]) : x(0), y(x += y) { } // "field .S::y. is used uninitialized" but too complex for the FE
+  S(int (*)[24]) : x(y += 10) { } // "field .S::y. is used uninitialized" but too complex for the FE
+  S(int (*)[25]) : x(y++) { } // { dg-warning "field .S::y. is used uninitialized" }
+};
+
+// Same, but { }.
+struct R {
+  int x;
+  int y;
+  const int z = 42;
+  int *p;
+
+  R(int (*)[1]) : x{x} { } // { dg-warning "field .R::x. is used uninitialized" }
+  R(int (*)[2]) : x{x + x} { } // { dg-warning "field .R::x. is used uninitialized" }
+  R(int (*)[3]) : x{static_cast<int>(y)} { } // { dg-warning "field .R::y. is used uninitialized" }
+  R(int (*)[4]) : x{static_cast<int>(x)} { } // { dg-warning "field .R::x. is used uninitialized" }
+  R(int (*)[5]) : x{fint(x)} { }
+  R(int (*)[6]) : x{fint(y)} { }
+
+  R(int (*)[7]) : x{sizeof(x)} { }
+  R(int (*)[8]) : x{sizeof(y)} { }
+  R(int (*)[9]) : p{&x} { }
+  R(int (*)[10]) : x{fintp(&y)} { }
+  R(int (*)[11]) : x{fintr(y)} { }
+  R(int (*)[12]) : x{fintcr(y)} { }
+  R(int (*)[26]) : x{((void)(__typeof(y)) 1, 1)} { }
+  R(int (*)[27]) : x{((void)(decltype(y)) 1, 1)} { }
+  R(int (*)[28]) : x{__alignof__(y)} { }
+  R(int (*)[29]) : x{noexcept(y)} { }
+
+  R(int (*)[13]) : x{0}, y{x ? y : y} { }
+  R(int (*)[14]) : x{0}, y{1 + (x ? y : y)} { }
+  R(int (*)[15]) : x{-y} { } // { dg-warning "field .R::y. is used uninitialized" }
+  R(int (*)[16]) : x{1 << y} { } // { dg-warning "field .R::y. is used uninitialized" }
+  R(int (*)[17]) : x{this->y} { } // { dg-warning "field .R::y. is used uninitialized" }
+  R(int (*)[18]) : x{arr[y]} { } // { dg-warning "field .R::y. is used uninitialized" }
+  R(int (*)[19]) : x{0}, y{x ? x : y} { }
+  R(int (*)[20]) : x{0}, y{y ? x : y} { }
+  R(int (*)[21]) : x{0}, y{y ? x : x} { }
+  R(int (*)[22]) : x{0}, y{(fint(y), x)} { }
+  R(int (*)[23]) : x{0}, y{x += y} { } // "field .R::y. is used uninitialized" but too complex for the FE
+  R(int (*)[24]) : x{y += 10} { } // "field .R::y. is used uninitialized" but too complex for the FE
+  R(int (*)[25]) : x{y++} { } // { dg-warning "field .R::y. is used uninitialized" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-25.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-25.C
new file mode 100644
index 00000000000..fb652f989a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-25.C
@@ -0,0 +1,12 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wall" }
+
+struct A {
+  A *a;
+};
+
+struct B : A {
+  int i;
+  B() : A{a} {}
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-26.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-26.C
new file mode 100644
index 00000000000..a887d12e9f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-26.C
@@ -0,0 +1,22 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+// Anonymous union/struct.
+// ??? The diagnostic should be improved to say 'b' instead of
+// "<anonymous>".
+
+struct S {
+  __extension__ struct {
+    int a;
+    int b;
+  };
+  S() : a(b) { } // { dg-warning "is used uninitialized" }
+};
+
+struct U {
+  union {
+    int a;
+    int b;
+  };
+  U() : a(b) { } // { dg-warning "is used uninitialized" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-27.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-27.C
new file mode 100644
index 00000000000..24e6b9b5b48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-27.C
@@ -0,0 +1,20 @@
+// PR c++/19808
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+enum E { red };
+
+struct C {
+  C(int *, unsigned);
+};
+
+template <unsigned U> struct D : C {
+  D(int, int, E) : C(e, U) {}
+  int e[2];
+};
+
+void
+g ()
+{
+  D<1>(0, 0, red);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C
new file mode 100644
index 00000000000..4e51b4b09f2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C
@@ -0,0 +1,59 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+
+struct S {
+  int i, j, k, l;
+  S() : i(j), // { dg-warning "field .S::j. is used uninitialized" }
+	j(1),
+	k(l + 1), // { dg-warning "field .S::l. is used uninitialized" }
+	l(2) { }
+};
+
+struct A {
+  int a, b, c;
+  A() : a(b // { dg-warning "field .A::b. is used uninitialized" }
+	  + c) { } // { dg-warning "field .A::c. is used uninitialized" }
+};
+
+struct B {
+  int &r;
+  int *p;
+  int a;
+  B() : r(a), p(&a), a(1) { }
+};
+
+struct C {
+  const int &r1, &r2;
+  C () : r1(r2), // { dg-warning "reference .C::r2. is not yet bound to a value when used here" }
+	 r2(r1) { }
+};
+
+struct D {
+  int a = 1;
+  int b = 2;
+  D() : a(b + 1), b(a + 1) { } // { dg-warning "field .D::b. is used uninitialized" }
+};
+
+struct E {
+  int a = 1;
+  E() : a(a + 1) { } // { dg-warning "field .E::a. is used uninitialized" }
+};
+
+struct F {
+  int a = 1;
+  int b;
+  F() : b(a + 1) { }
+};
+
+struct bar {
+  bar() {}
+  bar(bar&) {}
+};
+
+class foo {
+  bar first;
+  bar second;
+public:
+  foo() : first(second) {} // { dg-warning "field .foo::second. is used uninitialized" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C
new file mode 100644
index 00000000000..f21760f4e70
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C
@@ -0,0 +1,59 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+
+struct S {
+  int i, j, k, l;
+  S() : i{j}, // { dg-warning "field .S::j. is used uninitialized" }
+	j{1},
+	k{l + 1}, // { dg-warning "field .S::l. is used uninitialized" }
+	l{2} { }
+};
+
+struct A {
+  int a, b, c;
+  A() : a{b // { dg-warning "field .A::b. is used uninitialized" }
+	  + c} { } // { dg-warning "field .A::c. is used uninitialized" }
+};
+
+struct B {
+  int &r;
+  int *p;
+  int a;
+  B() : r{a}, p{&a}, a{1} { }
+};
+
+struct C {
+  const int &r1, &r2;
+  C () : r1{r2}, // { dg-warning "reference .C::r2. is not yet bound to a value when used here" }
+	 r2{r1} { }
+};
+
+struct D {
+  int a = 1;
+  int b = 2;
+  D() : a{b + 1}, b{a + 1} { } // { dg-warning "field .D::b. is used uninitialized" }
+};
+
+struct E {
+  int a = 1;
+  E() : a{a + 1} { } // { dg-warning "field .E::a. is used uninitialized" }
+};
+
+struct F {
+  int a = 1;
+  int b;
+  F() : b{a + 1} { }
+};
+
+struct bar {
+  bar() {}
+  bar(bar&) {}
+};
+
+class foo {
+  bar first;
+  bar second;
+public:
+  foo() : first{second} {} // { dg-warning "field .foo::second. is used uninitialized" }
+};
diff --git a/gcc/tree.c b/gcc/tree.c
index 7bfd64160f4..15c064cc0ce 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4781,6 +4781,7 @@ stabilize_reference (tree ref)
   TREE_READONLY (result) = TREE_READONLY (ref);
   TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
+  protected_set_expr_location (result, EXPR_LOCATION (ref));
 
   return result;
 }
