Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
gcc/cp/ChangeLog:
PR c++/19808
PR c++/96121
* init.c (perform_member_init): Remove a forward declaration.
Walk the initializer using find_uninit_fields_r. New parameter
to track uninitialized fields. If a member is initialized,
remove it from the hash set.
(perform_target_ctor): Return the initializer.
(struct find_uninit_data): New class.
(find_uninit_fields_r): New function.
(emit_mem_initializers): Keep and initialize a set holding fields
that are not initialized. When handling delegating constructors,
walk the constructor tree using find_uninit_fields_r. Also when
initializing base clases. Pass uninitialized down to
perform_member_init.
gcc/ChangeLog:
PR c++/19808
PR c++/96121
* doc/invoke.texi: Update documentation for -Wuninitialized.
* tree.c (stabilize_reference): Set location.
gcc/testsuite/ChangeLog:
PR c++/19808
PR c++/96121
* g++.dg/warn/Wuninitialized-12.C: New test.
* g++.dg/warn/Wuninitialized-13.C: New test.
* g++.dg/warn/Wuninitialized-14.C: New test.
* g++.dg/warn/Wuninitialized-15.C: New test.
* g++.dg/warn/Wuninitialized-16.C: New test.
* g++.dg/warn/Wuninitialized-17.C: New test.
* g++.dg/warn/Wuninitialized-18.C: New test.
* g++.dg/warn/Wuninitialized-19.C: New test.
* g++.dg/warn/Wuninitialized-20.C: New test.
* g++.dg/warn/Wuninitialized-21.C: New test.
* g++.dg/warn/Wuninitialized-22.C: New test.
* g++.dg/warn/Wuninitialized-23.C: New test.
* g++.dg/warn/Wuninitialized-24.C: New test.
* g++.dg/warn/Wuninitialized-25.C: New test.
* g++.dg/warn/Wuninitialized-26.C: New test.
* g++.dg/warn/Wuninitialized-27.C: New test.
---
gcc/cp/init.c | 235 +++++++++++++++++-
gcc/doc/invoke.texi | 12 +
gcc/testsuite/g++.dg/warn/Wuninitialized-12.C | 59 +++++
gcc/testsuite/g++.dg/warn/Wuninitialized-13.C | 49 ++++
gcc/testsuite/g++.dg/warn/Wuninitialized-14.C | 22 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-15.C | 118 +++++++++
gcc/testsuite/g++.dg/warn/Wuninitialized-16.C | 12 +
gcc/testsuite/g++.dg/warn/Wuninitialized-17.C | 146 +++++++++++
gcc/testsuite/g++.dg/warn/Wuninitialized-18.C | 22 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-19.C | 50 ++++
gcc/testsuite/g++.dg/warn/Wuninitialized-20.C | 16 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-21.C | 20 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-22.C | 37 +++
gcc/testsuite/g++.dg/warn/Wuninitialized-23.C | 24 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-24.C | 14 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-25.C | 12 +
gcc/testsuite/g++.dg/warn/Wuninitialized-26.C | 22 ++
gcc/testsuite/g++.dg/warn/Wuninitialized-27.C | 20 ++
gcc/tree.c | 1 +
19 files changed, 878 insertions(+), 13 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-12.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-13.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-14.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-15.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-16.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-17.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-18.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-19.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-20.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-21.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-22.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-23.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-24.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-25.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-26.C
create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-27.C
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ffb84ea5b09..92dcdc7bc02 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 void expand_aggr_init_1 (tree, tree, tree, tree, int,
tsubst_flags_t);
static void 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);
@@ -521,19 +520,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,
@@ -546,6 +545,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. */
@@ -757,12 +757,175 @@ 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;
+ /* A vector to track initialized fields in an initializer-list. */
+ vec<tree, va_gc> *list_inits;
+};
+
+/* 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;
+
+ /* No need to look into types. */
+ if (TYPE_P (init))
+ {
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+
+ switch (TREE_CODE (init))
+ {
+ /* If we're just taking the address of an object, it doesn't matter
+ if it's been initialized. */
+ case ADDR_EXPR:
+ /* Unevaluated operands. */
+ case ALIGNOF_EXPR:
+ case SIZEOF_EXPR:
+ case NOEXCEPT_EXPR:
+ *walk_subtrees = false;
+ return NULL_TREE;
+ default:
+ break;
+ }
+
+ /* Handle cases like S() : a((b = 42)), c(b) { } where the
initializer
+ for a surreptitiously initializes b. */
+ bool write_p = false;
+ if (TREE_CODE (init) == MODIFY_EXPR)
+ {
+ /* First recurse on the RHS to detect (b += 10). */
+ cp_walk_tree_without_duplicates (&TREE_OPERAND (init, 1),
+ find_uninit_fields_r, data);
+ init = TREE_OPERAND (init, 0);
+ /* Don't get tricked by a(((c, b) = 42)). */
+ while (TREE_CODE (init) == COMPOUND_EXPR)
+ init = TREE_OPERAND (init, 1);
+ /* The LHS might be something like this->a.b. Get this->a, so
that
+ we can remove the member 'a' from the uninitialized set. We treat
+ even partial initialization as initializing the whole object. */
+ while (TREE_CODE (init) == COMPONENT_REF)
+ if (TREE_CODE (TREE_OPERAND (init, 0)) == COMPONENT_REF)
+ init = TREE_OPERAND (init, 0);
+ else
+ break;
+ write_p = true;
+ }
+ /* Warn about uninitialized 'this'. */
+ else if (TREE_CODE (init) == 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);
+ }
+ }
+ else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ {
+ tree ctor = init;
+ if (!d->list_inits)
+ {
+ /* Reshape the outermost { }; this will fill the .index
fields. */
+ tree type = TYPE_P (d->member) ? d->member : TREE_TYPE
(d->member);
+ ctor = reshape_init (type, ctor, tf_none);
+ d->list_inits = make_tree_vector ();
+ }
+ if (TREE_CODE (ctor) == CONSTRUCTOR && CONSTRUCTOR_NELTS
(ctor) > 0)
+ {
+ for (constructor_elt &elt : *CONSTRUCTOR_ELTS (ctor))
+ {
+ temp_override<tree> ovr (d->member);
+ /* Build up the path to the element we're initializing,
+ if we're initializing a class member. */
+ if (TREE_CODE (elt.index) == FIELD_DECL
+ && TREE_CODE (d->member) == COMPONENT_REF)
+ d->member = build_class_member_access_expr (d->member,
+ elt.index,
+ NULL_TREE,
+ /*ref=*/true,
+ tf_none);
+ cp_walk_tree_without_duplicates (&elt.value,
+ find_uninit_fields_r, data);
+ vec_safe_push (d->list_inits, d->member);
+ }
+ /* We've processed this initializer-list, clean up. */
+ release_tree_vector (d->list_inits);
+ d->list_inits = nullptr;
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+ /* Reshaping might have unwrapped { X } to X; carry on. */
+ }
+
+ /* If we find FIELD in the uninitialized set and we're not writing
into
+ it, we warn. */
+ if (TREE_CODE (init) == COMPONENT_REF)
+ {
+ unsigned int ix;
+ tree t;
+ FOR_EACH_VEC_SAFE_ELT (d->list_inits, ix, t)
+ if (cp_tree_equal (init, t))
+ {
+ /* This field was already initialized by a prior element in the
+ initializer-list. */
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+
+ 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 we're not reading but writing into a member in this
initializer
+ (this is the LHS of an assignment), remember not to warn
about this
+ member later. */
+ if (write_p)
+ uninitialized->remove (field);
+ else 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);
+ /* We can't clear *walk_subtrees here to handle bogosities
such as
+ ((c++, b) = 42). */
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* 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);
@@ -790,7 +953,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);
@@ -802,6 +967,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, nullptr };
+ cp_walk_tree_without_duplicates (&val, find_uninit_fields_r,
+ &data);
+ }
}
if (array_of_unknown_bound_p (type))
@@ -830,6 +1001,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. */
@@ -970,6 +1144,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);
@@ -980,6 +1157,9 @@ perform_member_init (tree member, tree init)
tf_warning_or_error));
}
+ if (member_initialized_p && warn_uninitialized)
+ uninitialized.remove (member);
+
if (type_build_dtor_call (type))
{
tree expr;
@@ -1293,13 +1473,31 @@ 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,
+ nullptr };
+ cp_walk_tree_without_duplicates (&ctor,
+ find_uninit_fields_r,
+ &data);
+ }
return;
}
@@ -1360,6 +1558,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),
+ nullptr };
+ 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
@@ -1387,7 +1594,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 b3a2c7ce51d..cfd5c7e00a2 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6688,6 +6688,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-12.C
b/gcc/testsuite/g++.dg/warn/Wuninitialized-12.C
new file mode 100644
index 00000000000..4e51b4b09f2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-12.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-13.C
b/gcc/testsuite/g++.dg/warn/Wuninitialized-13.C
new file mode 100644
index 00000000000..9c631f22fbc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-13.C
@@ -0,0 +1,49 @@
+// 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)) { } // { dg-warning "field .S::x. is
used uninitialized" }
+ S(int (*)[6]) : x(fint(y)) { } // { dg-warning "field .S::y. is
used uninitialized" }
+
+ 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) { } // { dg-warning "field
.S::y. is used uninitialized" }
+ S(int (*)[14]) : x(0), y(1 + (x ? y : y)) { } // { dg-warning
"field .S::y. is used uninitialized" }
+ 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) { } // { dg-warning "field
.S::y. is used uninitialized" }
+ S(int (*)[20]) : x(0), y(y ? x : y) { } // { dg-warning "field
.S::y. is used uninitialized" }
+ S(int (*)[21]) : x(0), y(y ? x : x) { } // { dg-warning "field
.S::y. is used uninitialized" }
+ S(int (*)[22]) : x(0), y((fint(y), x)) { } // { dg-warning "field
.S::y. is used uninitialized" }
+ S(int (*)[23]) : x(0), y(x += y) { } // { dg-warning "field .S::y.
is used uninitialized" }
+ S(int (*)[24]) : x(y += 10) { } // { dg-warning "field .S::y. is
used uninitialized" }
+ S(int (*)[25]) : x(y++) { } // { dg-warning "field .S::y. is used
uninitialized" }
+};
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..6bef85e4659
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C
@@ -0,0 +1,22 @@
+// PR c++/19808
+// { dg-do compile }
+// { 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) {}
+};
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..ed62758a984
--- /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), // { dg-warning "reference .Q::c. is not yet bound" }
+ b(c), // { dg-warning "reference .Q::c. is not yet bound" }
+ 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..bb47a340f18
--- /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) { } // { dg-warning "field
.S::c. is used uninitialized" }
+};
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..f18ed9e2251
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C
@@ -0,0 +1,146 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized -Winit-self" }
+// Test we warn with initializer-lists.
+
+int num = 5;
+
+struct A {
+ int a;
+ int b;
+};
+
+struct B {
+ A a1;
+ A a2;
+};
+
+struct S {
+ A a;
+ int x;
+ int y;
+ S() : a{1, y} { } // { dg-warning "field .S::y. is used
uninitialized" }
+};
+
+struct R {
+ A a1;
+ A a2;
+ A a3;
+ A a4;
+ R() :
+ a1{1, 2},
+ a2{a2.a + 2}, // { dg-warning "field .R::a2. is used
uninitialized" }
+ a3{a3.a + 2}, // { dg-warning "field .R::a3. is used
uninitialized" }
+ a4{a4.b + 2} // { dg-warning "field .R::a4. is used
uninitialized" }
+ { }
+};
+
+struct Q {
+ B b1;
+ B b2;
+ B b3;
+ B b4;
+ B b5;
+ B b6;
+ B b7;
+ B b8;
+ B b9;
+ B b10;
+ B b11;
+ B b12;
+ B b13;
+ B b14;
+ B b15;
+ B b16;
+ B b17;
+ B b18;
+ B b19;
+ B b20;
+ B b21;
+ B b22;
+ Q() :
+ b1{ {}, {} },
+ b2{ {}, b2.a1 },
+ b3{ b3.a1 }, // { dg-warning "field .Q::b3. is used
uninitialized" }
+ b4{ {}, b4.a2}, // { dg-warning "field .Q::b4. is used
uninitialized" }
+ b5{ b5.a2 }, // { dg-warning "field .Q::b5. is used
uninitialized" }
+ b6{ {b6.a1.a} }, // { dg-warning "field .Q::b6. is used
uninitialized" }
+ b7{ {0, b7.a1.a} },
+ b8{ {}, {b8.a1.a} },
+ b9{ {}, {0, b9.a1.a} },
+ b10{ {b10.a1.b} }, // { dg-warning "field .Q::b10. is used
uninitialized" }
+ b11{ {0, b11.a1.b} }, // { dg-warning "field .Q::b11. is used
uninitialized" }
+ b12{ {}, {b12.a1.b} },
+ b13{ {}, {0, b13.a1.b} },
+ b14{ {b14.a2.a} }, // { dg-warning "field .Q::b14. is used
uninitialized" }
+ b15{ {0, b15.a2.a} }, // { dg-warning "field .Q::b15. is used
uninitialized" }
+ b16{ {}, {b16.a2.a} }, // { dg-warning "field .Q::b16. is used
uninitialized" }
+ b17{ {}, {0, b17.a2.a} },
+ b18{ {b18.a2.b} }, // { dg-warning "field .Q::b18. is used
uninitialized" }
+ b19{ {0, b19.a2.b} }, // { dg-warning "field .Q::b19. is used
uninitialized" }
+ b20{ {}, {b20.a2.b} }, // { dg-warning "field .Q::b20. is used
uninitialized" }
+ b21{ {}, {0, b21.a2.b} }, // { dg-warning "field .Q::b21. is
used uninitialized" }
+ b22{ {b18.a2.b + 5} }
+ { }
+};
+
+struct C {
+ int a;
+ int &b;
+ int c;
+};
+
+struct P {
+ C c1;
+ C c2;
+ C c3;
+ C c4;
+ C c5;
+ C c6;
+ C c7;
+ P() :
+ c1{ 0, num, 0 },
+ c2{ 1, num, c2.b },
+ c3{ c3.b, num }, // { dg-warning "field .P::c3. is used
uninitialized" }
+ c4{ 0, c4.b, 0 }, // { dg-warning ".C::b. is initialized with
itself" }
+ /* c5.c is binding to a reference, don't warn. */
+ c5{ 0, c5.c, 0 },
+ c6{ c6.b, num, 0 }, // { dg-warning "field .P::c6. is used
uninitialized" }
+ c7{ 0, c7.a, 0 }
+ { }
+};
+
+struct D {
+ int &a;
+ int &b;
+};
+
+struct M {
+ D d1;
+ D d2;
+ D d3;
+ M() :
+ d1{ num, num },
+ d2{ num, d2.a },
+ // Not a FE warning.
+ d3{ d3.b, num } // { dg-warning "is used uninitialized" }
+ { }
+};
+
+M m;
+
+struct E {
+ E();
+ E foo();
+ E* operator->();
+};
+
+struct F {
+ F(E);
+};
+
+struct G {
+ F f;
+ E e;
+ G() : f{ e->foo() }, e() { } // { dg-warning "field .G::e. is used
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..bd980d61118
--- /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 ".R::r. is initialized with
itself" }
+};
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..c0a88631fb4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C
@@ -0,0 +1,14 @@
+// PR c++/19808
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuninitialized" }
+
+struct S { int x, y; };
+
+struct A {
+ S a1[2];
+ int i;
+ A(int (*)[1]) : a1{{1}} { }
+ A(int (*)[2]) : a1{ {1, 2} } { }
+ A(int (*)[3]) : a1{{i}} { } // { dg-warning "field .A::i. is used
uninitialized" }
+ A(int (*)[4]) : a1{ {1, i} } { } // { dg-warning "field .A::i. 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/tree.c b/gcc/tree.c
index 1ad4ad5a5f7..1ad884120b0 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4638,6 +4638,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;
}
base-commit: 6403e02510fe84c72c515247a9dfdb6e05d977fe