This patch adds support for array indexing (i.e. operator []) in lock expressions. The current version of gcc seems to emit these as expressions involving pointer arithmetic, so we update get_canonical_lock_expr() to handle such expressions.
Bootstrapped and passed gcc regression testsuite on x86_64-unknown-linux-gnu. Okay for google/gcc-4_6? -DeLesley Changelog.google-4_6: 2011-11-03 DeLesley Hutchins <deles...@google.com> * tree-threadsafe-analyze.c (get_canonical_lock_expr): Add support for pointer arithmetic operations testsuite/Changelog.google-4_6: 2011-11-02 DeLesley Hutchins <deles...@google.com> * g++.dg/thread-ann/thread_annot_lock-84.C: New regression test. -- DeLesley Hutchins | Software Engineer | deles...@google.com | 505-206-0315
Index: testsuite/g++.dg/thread-ann/thread_annot_lock-84.C =================================================================== --- testsuite/g++.dg/thread-ann/thread_annot_lock-84.C (revision 0) +++ testsuite/g++.dg/thread-ann/thread_annot_lock-84.C (revision 0) @@ -0,0 +1,29 @@ +// Test lock expressions involving array elements. +// { dg-do compile } +// { dg-options "-Wthread-safety" } + +#include "thread_annot_common.h" + +struct Foo { + Mutex mu_; + int a GUARDED_BY(mu_); + + static void foo1(Foo* foos, int n); + static void foo2(Foo* foos, int n); +}; + +void Foo::foo1(Foo* foos, int n) { + for (int i = 0; i < n; ++i) { + foos[i].mu_.Lock(); + foos[i].a = 0; + foos[i].mu_.Unlock(); + } +} + +void Foo::foo2(Foo* foos, int n) { + for (int i = 0; i < n-1; ++i) { + foos[i].mu_.Lock(); + foos[i+1].a = 0; // { dg-warning "Writing to variable" } + foos[i].mu_.Unlock(); + } +} Index: tree-threadsafe-analyze.c =================================================================== --- tree-threadsafe-analyze.c (revision 180716) +++ tree-threadsafe-analyze.c (working copy) @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "gimple.h" #include "c-family/c-common.h" #include "toplev.h" #include "input.h" @@ -804,12 +805,27 @@ get_canonical_lock_expr (tree lock, tree && !gimple_nop_p (SSA_NAME_DEF_STMT (lock))) { gimple def_stmt = SSA_NAME_DEF_STMT (lock); - if (is_gimple_assign (def_stmt) - && (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt)) - == GIMPLE_SINGLE_RHS)) - return get_canonical_lock_expr (gimple_assign_rhs1 (def_stmt), - base_obj, is_temp_expr, - NULL_TREE); + if (is_gimple_assign (def_stmt)) + { + enum gimple_rhs_class gcls = + get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt)); + tree rhs = 0; + + if (gcls == GIMPLE_SINGLE_RHS) + rhs = gimple_assign_rhs1 (def_stmt); + else if (gcls == GIMPLE_UNARY_RHS) + rhs = build1 (gimple_assign_rhs_code (def_stmt), + TREE_TYPE (gimple_assign_lhs (def_stmt)), + gimple_assign_rhs1 (def_stmt)); + else if (gcls == GIMPLE_BINARY_RHS) + rhs = build2 (gimple_assign_rhs_code (def_stmt), + TREE_TYPE (gimple_assign_lhs (def_stmt)), + gimple_assign_rhs1 (def_stmt), + gimple_assign_rhs2 (def_stmt)); + if (rhs) + return get_canonical_lock_expr (rhs, base_obj, + is_temp_expr, NULL_TREE); + } else if (is_gimple_call (def_stmt)) { tree fdecl = gimple_call_fndecl (def_stmt); @@ -981,6 +997,24 @@ get_canonical_lock_expr (tree lock, tree TREE_TYPE (TREE_TYPE (canon_base)), canon_base); break; } + case PLUS_EXPR: + case POINTER_PLUS_EXPR: + case MULT_EXPR: + { + tree left = TREE_OPERAND (lock, 0); + tree canon_left = get_canonical_lock_expr (left, base_obj, + true /* is_temp_expr */, + NULL_TREE); + + tree right = TREE_OPERAND (lock, 1); + tree canon_right = get_canonical_lock_expr (right, base_obj, + true /* is_temp_expr */, + NULL_TREE); + if (left != canon_left || right != canon_right) + lock = build2 (TREE_CODE(lock), TREE_TYPE(lock), + canon_left, canon_right); + break; + } default: break; }