aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/init.c194
-rw-r--r--gcc/doc/invoke.texi12
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-14.C31
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-15.C118
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-16.C12
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-17.C33
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-18.C22
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-19.C50
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-20.C16
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-21.C20
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-22.C37
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-23.C24
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-24.C89
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-25.C12
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-26.C22
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-27.C20
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-28.C59
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-29.C59
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-30.C13
-rw-r--r--gcc/tree.c1
20 files changed, 831 insertions, 13 deletions
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3ba2e3b..975f2ed 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,148 @@ 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:
+ case BIND_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 (whether static or nonstatic member) may have side effects
+ and initialize other members; it's not the front end's job to try to
+ figure it out. But don't give up for constructors: we still want to
+ warn when initializing base classes:
+
+ struct D : public B {
+ int x;
+ D() : B(x) {}
+ };
+
+ so carry on to detect that 'x' is used uninitialized. */
+ if (!fn || !DECL_CONSTRUCTOR_P (fn))
+ 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,
+ "member %qD is used uninitialized", field);
+ *walk_subtrees = false;
+ }
+ }
+
+ return NULL_TREE;
+
+give_up:
+ *walk_subtrees = false;
+ uninitialized->empty ();
+ return integer_zero_node;
+}
+
+/* Wrapper around find_uninit_fields_r above. */
+
+static void
+find_uninit_fields (tree *t, hash_set<tree> *uninitialized, tree member)
+{
+ if (!uninitialized->is_empty ())
+ {
+ find_uninit_data data = { uninitialized, member };
+ cp_walk_tree_without_duplicates (t, find_uninit_fields_r, &data);
+ }
+}
+
/* 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 +944,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 +958,8 @@ 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
+ find_uninit_fields (&val, &uninitialized, decl);
}
if (array_of_unknown_bound_p (type))
@@ -848,6 +988,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 +1131,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 +1144,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 +1462,25 @@ 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 f = next_initializable_field (TYPE_FIELDS (current_class_type));
+ f != NULL_TREE;
+ f = next_initializable_field (DECL_CHAIN (f)))
+ if (!DECL_ARTIFICIAL (f))
+ uninitialized.add (f);
+
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));
+ find_uninit_fields (&ctor, &uninitialized, current_class_type);
return;
}
@@ -1378,6 +1541,9 @@ emit_mem_initializers (tree mem_inits)
flags,
tf_warning_or_error);
expand_cleanup_for_base (subobject, NULL_TREE);
+ if (STATEMENT_LIST_TAIL (cur_stmt_list))
+ find_uninit_fields (&STATEMENT_LIST_TAIL (cur_stmt_list)->stmt,
+ &uninitialized, BINFO_TYPE (subobject));
}
else if (!ABSTRACT_CLASS_TYPE_P (current_class_type))
/* C++14 DR1658 Means we do not have to construct vbases of
@@ -1405,7 +1571,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 5fed1dd..1b02ea0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6996,6 +6996,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 0000000..cebadf1
--- /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() : m{} { }
+ 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 0000000..89e9066
--- /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 "member .F::e. is used uninitialized" }
+ F(int (*)[2]) : a(e.num()) { }
+ F(int (*)[3]) : e(a) { } // { dg-warning "member .F::a. is used uninitialized" }
+ F(int (*)[4]) : a(4), e(a) { }
+ F(int (*)[5]) : e(b) { } // { dg-warning "member .F::b. is used uninitialized" }
+ F(int (*)[6]) : e(b), b(4) { } // { dg-warning "member .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 "member .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 "member .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 0000000..38f587b
--- /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 0000000..80c37ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C
@@ -0,0 +1,33 @@
+// 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" }
+};
+
+struct A {
+ int x, y, z;
+ int f () { y = 1; return 2; }
+ A ():
+ x (f ()),
+ 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 0000000..29ae77a
--- /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 "member .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 0000000..e4d53d4
--- /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 "member .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 "member .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 0000000..867c4da
--- /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:member .A::x. is used uninitialized" }
+ A(int (*)[2]) : A(x, x) { } // { dg-warning "24:member .A::x. is used uninitialized" }
+ A(int (*)[3]) : A(x, 0) { }
+ A(int (*)[4]) : A{x} { } // { dg-warning "21:member .A::x. is used uninitialized" }
+ A(int (*)[5]) : A{x, x} { } // { dg-warning "24:member .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 0000000..57ca00a
--- /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 0000000..89686a0
--- /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 "member .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 0000000..7cb2a9e
--- /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 "member .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 0000000..e5dd429
--- /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 "member .S::x. is used uninitialized" }
+ S(int (*)[3]) : x(static_cast<int>(y)) { } // { dg-warning "member .S::y. is used uninitialized" }
+ S(int (*)[4]) : x(static_cast<int>(x)) { } // { dg-warning "member .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 "member .S::y. is used uninitialized" }
+ S(int (*)[16]) : x(1 << y) { } // { dg-warning "member .S::y. is used uninitialized" }
+ S(int (*)[17]) : x(this->y) { } // { dg-warning "member .S::y. is used uninitialized" }
+ S(int (*)[18]) : x(arr[y]) { } // { dg-warning "member .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) { } // "member .S::y. is used uninitialized" but too complex for the FE
+ S(int (*)[24]) : x(y += 10) { } // "member .S::y. is used uninitialized" but too complex for the FE
+ S(int (*)[25]) : x(y++) { } // { dg-warning "member .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 "member .R::x. is used uninitialized" }
+ R(int (*)[2]) : x{x + x} { } // { dg-warning "member .R::x. is used uninitialized" }
+ R(int (*)[3]) : x{static_cast<int>(y)} { } // { dg-warning "member .R::y. is used uninitialized" }
+ R(int (*)[4]) : x{static_cast<int>(x)} { } // { dg-warning "member .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 "member .R::y. is used uninitialized" }
+ R(int (*)[16]) : x{1 << y} { } // { dg-warning "member .R::y. is used uninitialized" }
+ R(int (*)[17]) : x{this->y} { } // { dg-warning "member .R::y. is used uninitialized" }
+ R(int (*)[18]) : x{arr[y]} { } // { dg-warning "member .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} { } // "member .R::y. is used uninitialized" but too complex for the FE
+ R(int (*)[24]) : x{y += 10} { } // "member .R::y. is used uninitialized" but too complex for the FE
+ R(int (*)[25]) : x{y++} { } // { dg-warning "member .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 0000000..fb652f9
--- /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 0000000..a887d12
--- /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 0000000..24e6b9b
--- /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 0000000..7dbbf87
--- /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 "member .S::j. is used uninitialized" }
+ j(1),
+ k(l + 1), // { dg-warning "member .S::l. is used uninitialized" }
+ l(2) { }
+};
+
+struct A {
+ int a, b, c;
+ A() : a(b // { dg-warning "member .A::b. is used uninitialized" }
+ + c) { } // { dg-warning "member .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 "member .D::b. is used uninitialized" }
+};
+
+struct E {
+ int a = 1;
+ E() : a(a + 1) { } // { dg-warning "member .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 "member .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 0000000..bc74299
--- /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 "member .S::j. is used uninitialized" }
+ j{1},
+ k{l + 1}, // { dg-warning "member .S::l. is used uninitialized" }
+ l{2} { }
+};
+
+struct A {
+ int a, b, c;
+ A() : a{b // { dg-warning "member .A::b. is used uninitialized" }
+ + c} { } // { dg-warning "member .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 "member .D::b. is used uninitialized" }
+};
+
+struct E {
+ int a = 1;
+ E() : a{a + 1} { } // { dg-warning "member .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 "member .foo::second. is used uninitialized" }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-30.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-30.C
new file mode 100644
index 0000000..ba0f76e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-30.C
@@ -0,0 +1,13 @@
+// PR c++/19808
+// { dg-do compile }
+// { dg-options "-Wuninitialized" }
+
+class diagnostic_event {
+public:
+ virtual int get_stack_depth();
+};
+struct event_range {
+ event_range(diagnostic_event &initial_event)
+ : m_stack_depth(initial_event.get_stack_depth()) {}
+ int m_stack_depth;
+};
diff --git a/gcc/tree.c b/gcc/tree.c
index f2c829f..62d9d78 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;
}