A C++ coroutine is rewritten by the compiler to be three functions: a ramp function that generates the coroutine state, an actor function that is is generated from the coroutine's body, and a destroy function to clean up the coroutine state. All three of these functions are marked as "atrificial" by gcc, since they involve the compiler creating or rewriting parts of each function. Gcov ignores artificial functions. The bulk of the actor function, however, consists of code written by the user, and as such getting count information for that function would be useful. This patch teaches gcov how to not ignore these functions.
2025-03-24 Michael Welsh Duggan (m...@md5i.com) Teach gcov to not ignore coroutine actor functions (Bug#110827) * gcc/gcov.cc (function_info::is_coroutine_actor): Add method. (function_info::is_artificial) Use is_coroutine_actor. (process_all_functions): Use is_artificial. Signed-off-by: Michael Welsh Duggan <m...@md5i.com> --- gcc/gcov.cc | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/gcc/gcov.cc b/gcc/gcov.cc index 3e6f2e4212a..a544da6a61c 100644 --- a/gcc/gcov.cc +++ b/gcc/gcov.cc @@ -283,12 +283,16 @@ public: The line must be defined in body of the function, can't be inlined. */ bool group_line_p (unsigned n, unsigned src_idx); + /* Function filter based on coroutine actor function name. */ + + static bool is_coroutine_actor (function_info *fn); + /* Function filter based on function_info::artificial variable. */ static inline bool is_artificial (function_info *fn) { - return fn->artificial; + return fn->artificial && !is_coroutine_actor (fn); } /* Name of function. */ @@ -796,6 +800,34 @@ function_info::~function_info () free (m_name); } +bool function_info::is_coroutine_actor (function_info *fn) +{ +#ifndef NO_DOT_IN_LABEL +#define FI_ICA_JOINER '.' +#else // NO_DOT_IN_LABEL +#ifndef NO_DOLLAR_IN_LABEL +#define FI_ICA_JOINER '$' +#else // NO_DOLLAR_IN_LABEL +#define FI_ICA_JOINER '_' +#endif // NO_DOLLAR_IN_LABEL +#endif // NO_DOT_IN_LABEL + + static char const actor[] = { + FI_ICA_JOINER, 'F', 'r', 'a', 'm', 'e', + FI_ICA_JOINER, 'a', 'c', 't', 'o', 'r' + }; + size_t len = strlen(fn->m_name); + if (len <= sizeof(actor)) + return false; + size_t start = len - sizeof(actor); + for (size_t i = 0; i < sizeof(actor); ++i) + { + if (fn->m_name[start + i] != actor[i]) + return false; + } + return true; +} + bool function_info::group_line_p (unsigned n, unsigned src_idx) { return is_group && src == src_idx && start_line <= n && n <= end_line; @@ -1549,7 +1581,7 @@ process_all_functions (void) /* Identify group functions. */ for (vector<function_info *>::iterator it = functions.begin (); it != functions.end (); it++) - if (!(*it)->artificial) + if (!function_info::is_artificial (*it)) { function_start needle; needle.source_file_idx = (*it)->src; -- 2.47.2