diff options
author | Jason Merrill <jason@redhat.com> | 2023-04-14 13:37:16 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2023-04-14 21:34:14 -0400 |
commit | 9964df74a9e99e850bf9b0b6ff5c47133f846db8 (patch) | |
tree | 44bb6e88aecdd16b93b79a03cdc89149e5aaf76f /gcc | |
parent | 1aee19f9b57caef2a600968807ecaa13bac2d2f8 (diff) | |
download | gcc-9964df74a9e99e850bf9b0b6ff5c47133f846db8.zip gcc-9964df74a9e99e850bf9b0b6ff5c47133f846db8.tar.gz gcc-9964df74a9e99e850bf9b0b6ff5c47133f846db8.tar.bz2 |
-Wdangling-pointer: fix MEM_REF handling [PR109514]
Here we hit the MEM_REF case, with its arg an ADDR_EXPR, but had no handling
for that and wrongly assumed it would be a reference to a local variable.
This patch overhauls the logic for deciding whether the target is something
to warn about so that we only warn if we specifically recognize the target
as non-local. None of the existing tests regress as a result.
PR c++/109514
gcc/ChangeLog:
* gimple-ssa-warn-access.cc (pass_waccess::check_dangling_stores):
Overhaul lhs_ref.ref analysis.
gcc/testsuite/ChangeLog:
* g++.dg/warn/Wdangling-pointer-6.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/gimple-ssa-warn-access.cc | 50 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wdangling-pointer-6.C | 30 |
2 files changed, 50 insertions, 30 deletions
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index b3de4b7..d0d2148 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -4528,39 +4528,34 @@ pass_waccess::check_dangling_stores (basic_block bb, if (!m_ptr_qry.get_ref (lhs, stmt, &lhs_ref, 0)) continue; - if (auto_var_p (lhs_ref.ref)) - continue; - - if (DECL_P (lhs_ref.ref)) + if (TREE_CODE (lhs_ref.ref) == MEM_REF) { - if (!POINTER_TYPE_P (TREE_TYPE (lhs_ref.ref)) - || lhs_ref.deref > 0) - continue; + lhs_ref.ref = TREE_OPERAND (lhs_ref.ref, 0); + ++lhs_ref.deref; } - else if (TREE_CODE (lhs_ref.ref) == SSA_NAME) + if (TREE_CODE (lhs_ref.ref) == ADDR_EXPR) + { + lhs_ref.ref = TREE_OPERAND (lhs_ref.ref, 0); + --lhs_ref.deref; + } + if (TREE_CODE (lhs_ref.ref) == SSA_NAME) { gimple *def_stmt = SSA_NAME_DEF_STMT (lhs_ref.ref); if (!gimple_nop_p (def_stmt)) /* Avoid looking at or before stores into unknown objects. */ return; - tree var = SSA_NAME_VAR (lhs_ref.ref); - if (TREE_CODE (var) == PARM_DECL && DECL_BY_REFERENCE (var)) - /* Avoid by-value arguments transformed into by-reference. */ - continue; - - } - else if (TREE_CODE (lhs_ref.ref) == MEM_REF) - { - tree arg = TREE_OPERAND (lhs_ref.ref, 0); - if (TREE_CODE (arg) == SSA_NAME) - { - gimple *def_stmt = SSA_NAME_DEF_STMT (arg); - if (!gimple_nop_p (def_stmt)) - return; - } + lhs_ref.ref = SSA_NAME_VAR (lhs_ref.ref); } + + if (TREE_CODE (lhs_ref.ref) == PARM_DECL + && (lhs_ref.deref - DECL_BY_REFERENCE (lhs_ref.ref)) > 0) + /* Assignment through a (real) pointer/reference parameter. */; + else if (TREE_CODE (lhs_ref.ref) == VAR_DECL + && !auto_var_p (lhs_ref.ref)) + /* Assignment to/through a non-local variable. */; else + /* Something else, don't warn. */ continue; if (stores.add (lhs_ref.ref)) @@ -4587,13 +4582,8 @@ pass_waccess::check_dangling_stores (basic_block bb, location_t loc = DECL_SOURCE_LOCATION (rhs_ref.ref); inform (loc, "%qD declared here", rhs_ref.ref); - if (DECL_P (lhs_ref.ref)) - loc = DECL_SOURCE_LOCATION (lhs_ref.ref); - else if (EXPR_HAS_LOCATION (lhs_ref.ref)) - loc = EXPR_LOCATION (lhs_ref.ref); - - if (loc != UNKNOWN_LOCATION) - inform (loc, "%qE declared here", lhs_ref.ref); + loc = DECL_SOURCE_LOCATION (lhs_ref.ref); + inform (loc, "%qD declared here", lhs_ref.ref); } } diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-pointer-6.C b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-6.C new file mode 100644 index 0000000..20d47ed --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-6.C @@ -0,0 +1,30 @@ +// PR c++/109514 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-O2 -Werror=dangling-pointer" } + +struct _Rb_tree_node_base { + _Rb_tree_node_base *_M_parent; +}; +struct _Rb_tree_header { + _Rb_tree_node_base _M_header; + void _M_move_data() { _M_header._M_parent->_M_parent = &_M_header; } +}; +struct _Rb_tree { + _Rb_tree_header _M_impl; + _Rb_tree_node_base *&_M_root() { return _M_impl._M_header._M_parent; } + _Rb_tree(); + _Rb_tree &operator=(_Rb_tree &&); +}; +_Rb_tree &_Rb_tree::operator=(_Rb_tree &&) { + if (_M_root()) + _M_impl._M_move_data(); + return *this; +} +struct set { + _Rb_tree _M_t; +}; +set FilterRs(); +void f() { + set rs; + rs = FilterRs(); +}; |