Index: testsuite/g++.dg/thread-ann/thread_annot_lock-82.C =================================================================== --- testsuite/g++.dg/thread-ann/thread_annot_lock-82.C (revision 180716) +++ testsuite/g++.dg/thread-ann/thread_annot_lock-82.C (working copy) @@ -1,7 +1,7 @@ -// Test template methods in the presence of cloned constructors. -// Regression test for bugfix. +// Regression tests: fix ICE issues when IPA-SRA deletes formal +// function parameters. // { dg-do compile } -// { dg-options "-Wthread-safety -O3" } +// { dg-options "-Wthread-safety -Wthread-warn-optimization -O3" } #include "thread_annot_common.h" @@ -10,6 +10,7 @@ void do_something(void* a); class Foo { Mutex mu_; + int a GUARDED_BY(mu_); // with optimization turned on, ipa-sra should eliminate the hidden // "this" argument, thus invalidating EXCLUSIVE_LOCKS_REQUIRED. @@ -18,6 +19,7 @@ class Foo { } void foo(Foo* f); + void bar(); }; void Foo::foo(Foo* f) { @@ -28,3 +30,17 @@ void Foo::foo(Foo* f) { mu_.Unlock(); } + +class SCOPED_LOCKABLE DummyMutexLock { +public: + // IPA-SRA should kill the parameters to these functions + explicit DummyMutexLock(Mutex* mutex) EXCLUSIVE_LOCK_FUNCTION(mutex) {} + ~DummyMutexLock() UNLOCK_FUNCTION() {} +}; + + +void Foo::bar() { + // Matches two warnings: + DummyMutexLock dlock(&mu_); // { dg-warning "attribute has been removed by optimization." } + a = 1; // warning here should be suppressed, due to errors handling dlock +} Index: common.opt =================================================================== --- common.opt (revision 180716) +++ common.opt (working copy) @@ -680,6 +680,10 @@ Wthread-attr-bind-param Common Var(warn_thread_attr_bind_param) Init(1) Warning Make the thread safety analysis try to bind the function parameters used in the attributes +Wthread-warn-optimization +Common Var(warn_thread_optimization) Init(0) Warning +Warn when optimizations invalidate the thread safety analysis. + Wtype-limits Common Var(warn_type_limits) Init(-1) Warning Warn if a comparison is always true or always false due to the limited range of the data type Index: tree-threadsafe-analyze.c =================================================================== --- tree-threadsafe-analyze.c (revision 180716) +++ tree-threadsafe-analyze.c (working copy) @@ -1594,7 +1594,10 @@ get_actual_argument_from_position (gimple call, tr lock_pos = TREE_INT_CST_LOW (pos_arg); - gcc_assert (lock_pos >= 1 && lock_pos <= num_args); + /* The ipa-sra optimization can occasionally delete arguments, thus + invalidating the index. */ + if (lock_pos < 1 || lock_pos > num_args) + return NULL_TREE; /* The lock position specified in the attributes is 1-based, so we need to subtract 1 from it when accessing the call arguments. */ @@ -1734,7 +1737,27 @@ handle_lock_primitive_attrs (gimple call, tree fde a formal parameter, we need to grab the corresponding actual argument of the call. */ else if (TREE_CODE (arg) == INTEGER_CST) - arg = get_actual_argument_from_position (call, arg); + { + arg = get_actual_argument_from_position (call, arg); + /* If ipa-sra has rewritten the call, then recover as gracefully as + possible. */ + if (!arg) + { + /* Add the universal lock to the lockset to suppress subsequent + errors. */ + if (is_exclusive_lock) + pointer_set_insert(live_excl_locks, error_mark_node); + else + pointer_set_insert(live_shared_locks, error_mark_node); + + if (warn_thread_optimization) + warning_at (*locus, OPT_Wthread_safety, + G_("Lock attribute has been removed by " + "optimization.")); + + return; + } + } else if (TREE_CODE (get_leftmost_base_var (arg)) == PARM_DECL) { tree new_base @@ -1890,7 +1913,18 @@ handle_unlock_primitive_attr (gimple call, tree fd a formal parameter, we need to grab the corresponding actual argument of the call. */ if (TREE_CODE (arg) == INTEGER_CST) - lockable = get_actual_argument_from_position (call, arg); + { + lockable = get_actual_argument_from_position (call, arg); + /* If ipa-sra has rewritten the call, then fail as gracefully as + possible -- just leave the lock in the lockset. */ + if (!lockable) { + if (warn_thread_optimization) + warning_at (*locus, OPT_Wthread_safety, + G_("Unlock attribute has been removed by " + "optimization.")); + return; + } + } else if (TREE_CODE (get_leftmost_base_var (arg)) == PARM_DECL) { tree fdecl = gimple_call_fndecl (call); @@ -1908,7 +1942,15 @@ handle_unlock_primitive_attr (gimple call, tree fd } else { - gcc_assert (base_obj); + /* If ipa-sra has killed arguments, then base_obj may be NULL. + Attempt to recover gracefully by leaving the lock in the lockset. */ + if (!base_obj) { + if (warn_thread_optimization) + warning_at (*locus, OPT_Wthread_safety, + G_("Unlock attribute has been removed by " + "optimization.")); + return; + } /* Check if the primitive is an unlock routine (e.g. the destructor or a release function) of a scoped_lock. If so, get the lock that is @@ -2099,6 +2141,9 @@ handle_function_lock_requirement (gimple call, tre else if (TREE_CODE (lock) == INTEGER_CST) { lock = get_actual_argument_from_position (call, lock); + /* Ignore attribute if ipa-sra has killed the argument. */ + if (!lock) + return; /* If the lock is a function argument, we don't want to prepend the base object to the lock name. Set the TMP_BASE_OBJ to NULL. */