> What about the other spots where we call gimple_call_fndecl, shouldn't we > call get_fdecl_from_gimple_stmt instead?
Good point. I've gone through and updated the necessary spots. New patch with all fixes is attached. -DeLesley -- DeLesley Hutchins | Software Engineer | deles...@google.com | 505-206-0315
Index: testsuite/g++.dg/thread-ann/thread_annot_lock-85.C =================================================================== --- testsuite/g++.dg/thread-ann/thread_annot_lock-85.C (revision 0) +++ testsuite/g++.dg/thread-ann/thread_annot_lock-85.C (revision 0) @@ -0,0 +1,22 @@ +// Regression test, handle trylock on virtual method. +// { dg-do compile } +// { dg-options "-Wthread-safety" } + +#include "thread_annot_common.h" + +class LOCKABLE Lock { + public: + virtual ~Lock() {} + virtual bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) { return true; } + void Unlock() UNLOCK_FUNCTION() {} +}; + + +void foo() { + Lock x; + Lock *p = &x; + if (p->TryLock()) { + p->Unlock(); + } +} + Index: tree-threadsafe-analyze.c =================================================================== --- tree-threadsafe-analyze.c (revision 181268) +++ tree-threadsafe-analyze.c (working copy) @@ -564,6 +564,38 @@ return false; } + +/* Get the function declaration from a gimple call stmt (CALL). This handles + both ordinary function calls and virtual methods. */ + +static tree +get_fdecl_from_gimple_stmt (gimple call) +{ + tree fdecl = gimple_call_fndecl (call); + /* If the callee fndecl is NULL, check if it is a virtual function, + and if so, try to get its decl through the reference object. */ + if (!fdecl) + { + tree callee = gimple_call_fn (call); + if (TREE_CODE (callee) == OBJ_TYPE_REF) + { + tree objtype = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (callee))); + /* Check to make sure objtype is a valid type. + OBJ_TYPE_REF_OBJECT does not always return the correct static type of the callee. + For example: Given foo(void* ptr) { ((Foo*) ptr)->doSomething(); } + objtype will be void, not Foo. Whether or not this happens depends on the details + of how a particular call is lowered to GIMPLE, and there is no easy fix that works + in all cases. For now, we simply rely on gcc's type information; if that information + is not accurate, then the analysis will be less precise. + */ + if (TREE_CODE (objtype) == RECORD_TYPE) + fdecl = lang_hooks.get_virtual_function_decl (callee, objtype); + } + } + return fdecl; +} + + /* Given a CALL gimple statment, check if its function decl is annotated with "lock_returned" attribute. If so, return the lock specified in the attribute. Otherise, return NULL_TREE. */ @@ -571,7 +603,7 @@ static tree get_lock_returned_by_call (gimple call) { - tree fdecl = gimple_call_fndecl (call); + tree fdecl = get_fdecl_from_gimple_stmt (call); tree attr = (fdecl ? lookup_attribute ("lock_returned", DECL_ATTRIBUTES (fdecl)) : NULL_TREE); @@ -828,7 +860,7 @@ } else if (is_gimple_call (def_stmt)) { - tree fdecl = gimple_call_fndecl (def_stmt); + tree fdecl = get_fdecl_from_gimple_stmt (def_stmt); tree real_lock = get_lock_returned_by_call (def_stmt); if (real_lock) { @@ -1661,6 +1693,7 @@ gcc_unreachable (); } + /* A helper function that adds the LOCKABLE, acquired by CALL, to the corresponding lock sets (LIVE_EXCL_LOCKS or LIVE_SHARED_LOCKS) depending on the boolean parameter IS_EXCLUSIVE_LOCK. If the CALL is a trylock call, @@ -1967,7 +2000,6 @@ } else if (TREE_CODE (get_leftmost_base_var (arg)) == PARM_DECL) { - tree fdecl = gimple_call_fndecl (call); tree new_base = get_actual_argument_from_parameter ( call, fdecl, get_leftmost_base_var (arg)); lockable = get_canonical_lock_expr (arg, NULL_TREE, false, new_base); @@ -2542,12 +2574,17 @@ return; } -/* The main routine that handles gimple call statements. */ +/* The main routine that handles gimple call statements. This will update + the set of held locks. + CALL -- the gimple call statement. + CURRENT_BB_INFO -- a pointer to the lockset structures for the current + basic block. +*/ static void handle_call_gs (gimple call, struct bb_threadsafe_info *current_bb_info) { - tree fdecl = gimple_call_fndecl (call); + tree fdecl = get_fdecl_from_gimple_stmt (call); int num_args = gimple_call_num_args (call); int arg_index = 0; tree arg_type = NULL_TREE; @@ -2560,27 +2597,6 @@ else locus = gimple_location (call); - /* If the callee fndecl is NULL, check if it is a virtual function, - and if so, try to get its decl through the reference object. */ - if (!fdecl) - { - tree callee = gimple_call_fn (call); - if (TREE_CODE (callee) == OBJ_TYPE_REF) - { - tree objtype = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (callee))); - /* Check to make sure objtype is a valid type. - OBJ_TYPE_REF_OBJECT does not always return the correct static type of the callee. - For example: Given foo(void* ptr) { ((Foo*) ptr)->doSomething(); } - objtype will be void, not Foo. Whether or not this happens depends on the details - of how a particular call is lowered to GIMPLE, and there is no easy fix that works - in all cases. For now, we simply rely on gcc's type information; if that information - is not accurate, then the analysis will be less precise. - */ - if (TREE_CODE (objtype) == RECORD_TYPE) - fdecl = lang_hooks.get_virtual_function_decl (callee, objtype); - } - } - /* The callee fndecl could be NULL, e.g., when the function is passed in as an argument. */ if (fdecl) @@ -2873,7 +2889,8 @@ } else if (is_gimple_call (gs)) { - tree fdecl = gimple_call_fndecl (gs); + tree fdecl = get_fdecl_from_gimple_stmt (gs); + /* The function decl could be null in some cases, e.g. a function pointer passed in as a parameter. */ if (fdecl