diff options
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; +}; @@ -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; } |