diff options
author | David Malcolm <dmalcolm@redhat.com> | 2023-07-31 11:13:02 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2023-07-31 11:13:02 -0400 |
commit | 75d623946d4b6ea80a777b789b116d4b4a2298dc (patch) | |
tree | 09fd7297586bd0c2b71502e834430b9441d4e2ae /gcc | |
parent | a104e9ac0ae9a7e78ec2edd0b81074946646a87d (diff) | |
download | gcc-75d623946d4b6ea80a777b789b116d4b4a2298dc.zip gcc-75d623946d4b6ea80a777b789b116d4b4a2298dc.tar.gz gcc-75d623946d4b6ea80a777b789b116d4b4a2298dc.tar.bz2 |
SARIF and -ftime-report's output [PR109361]
This patch adds support for embeddding profiling information about the
compiler itself into the SARIF output.
Specifically, if SARIF diagnostic output is requested, via
-fdiagnostics-format=sarif-file or -fdiagnostics-format=sarif-stderr,
then any -ftime-report output is written in JSON form into the SARIF
output, rather than to stderr.
In earlier versions of this patch I extended -ftime-report so that
*as well* as writing to stderr, it would embed the information in any
SARIF output. This turned out to be awkward to use, in that I found
myself needing to get the data in JSON form without also having it
emitted on stderr (which was fouling my build scripts).
The timing information is written to the SARIF as a "gcc/timeReport"
property within a property bag of the "invocation" object.
Here's an example of the output:
"invocations": [
{
"executionSuccessful": true,
"toolExecutionNotifications": [],
"properties": {
"gcc/timeReport": {
"timevars": [
{
"name": "phase setup",
"elapsed": {
"user": 0.04,
"sys": 0,
"wall": 0.04,
"ggc_mem": 1863472
}
},
[...snip...]
{
"name": "analyzer: processing worklist",
"elapsed": {
"user": 0.06,
"sys": 0,
"wall": 0.06,
"ggc_mem": 48
}
},
{
"name": "analyzer: emitting diagnostics",
"elapsed": {
"user": 0.01,
"sys": 0,
"wall": 0.01,
"ggc_mem": 0
}
},
{
"name": "TOTAL",
"elapsed": {
"user": 0.21,
"sys": 0.03,
"wall": 0.24,
"ggc_mem": 3368736
}
}
],
"CHECKING_P": true,
"flag_checking": true
}
}
}
]
The documentation notes that the precise output format is subject
to change.
I have successfully used this in my analyzer integration tests to get
timing information about which source files get slowed down by the
analyzer. I've validated the generated .sarif files against the SARIF
schema.
gcc/ChangeLog:
PR analyzer/109361
* diagnostic-client-data-hooks.h (class sarif_object): New forward
decl.
(diagnostic_client_data_hooks::add_sarif_invocation_properties):
New vfunc.
* diagnostic-format-sarif.cc: Include "diagnostic-format-sarif.h".
(class sarif_invocation): Inherit from sarif_object rather than
json::object.
(class sarif_result): Likewise.
(class sarif_ice_notification): Likewise.
(sarif_object::get_or_create_properties): New.
(sarif_invocation::prepare_to_flush): Add "context" param. Use it
to call the context's add_sarif_invocation_properties hook.
(sarif_builder::flush_to_file): Pass m_context to
sarif_invocation::prepare_to_flush.
* diagnostic-format-sarif.h: New header.
* doc/invoke.texi (Developer Options): Clarify that -ftime-report
writes to stderr. Document that if SARIF diagnostic output is
requested then any timing information is written in JSON form as
part of the SARIF output, rather than to stderr.
* timevar.cc: Include "json.h".
(timer::named_items::m_hash_map): Split out type into...
(timer::named_items::hash_map_t): ...this new typedef.
(timer::named_items::make_json): New function.
(timevar_diff): New function.
(make_json_for_timevar_time_def): New function.
(timer::timevar_def::make_json): New function.
(timer::make_json): New function.
* timevar.h (class json::value): New forward decl.
(timer::make_json): New decl.
(timer::timevar_def::make_json): New decl.
* tree-diagnostic-client-data-hooks.cc: Include
"diagnostic-format-sarif.h" and "timevar.h".
(compiler_data_hooks::add_sarif_invocation_properties): New vfunc
implementation.
gcc/testsuite/ChangeLog:
PR analyzer/109361
* c-c++-common/diagnostic-format-sarif-file-timevars-1.c: New test.
* c-c++-common/diagnostic-format-sarif-file-timevars-2.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/diagnostic-client-data-hooks.h | 6 | ||||
-rw-r--r-- | gcc/diagnostic-format-sarif.cc | 45 | ||||
-rw-r--r-- | gcc/diagnostic-format-sarif.h | 45 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 12 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c | 18 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c | 21 | ||||
-rw-r--r-- | gcc/timevar.cc | 164 | ||||
-rw-r--r-- | gcc/timevar.h | 5 | ||||
-rw-r--r-- | gcc/tree-diagnostic-client-data-hooks.cc | 26 |
9 files changed, 326 insertions, 16 deletions
diff --git a/gcc/diagnostic-client-data-hooks.h b/gcc/diagnostic-client-data-hooks.h index 5f8b9a2..e3f2d05 100644 --- a/gcc/diagnostic-client-data-hooks.h +++ b/gcc/diagnostic-client-data-hooks.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H #define GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H +class sarif_object; class client_version_info; /* A bundle of additional metadata, owned by the diagnostic_context, @@ -41,6 +42,11 @@ class diagnostic_client_data_hooks See SARIF v2.1.0 Appendix J for suggested values. */ virtual const char * maybe_get_sarif_source_language (const char *filename) const = 0; + + /* Hook to allow client to populate a SARIF "invocation" object with + a custom property bag (see SARIF v2.1.0 section 3.8). */ + virtual void + add_sarif_invocation_properties (sarif_object &invocation_obj) const = 0; }; /* Factory function for making an instance of diagnostic_client_data_hooks diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 5e48398..1eff719 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -32,13 +32,14 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-client-data-hooks.h" #include "diagnostic-diagram.h" #include "text-art/canvas.h" +#include "diagnostic-format-sarif.h" class sarif_builder; /* Subclass of json::object for SARIF invocation objects (SARIF v2.1.0 section 3.20). */ -class sarif_invocation : public json::object +class sarif_invocation : public sarif_object { public: sarif_invocation () @@ -49,17 +50,17 @@ public: void add_notification_for_ice (diagnostic_context *context, diagnostic_info *diagnostic, sarif_builder *builder); - void prepare_to_flush (); + void prepare_to_flush (diagnostic_context *context); private: json::array *m_notifications_arr; bool m_success; }; -/* Subclass of json::object for SARIF result objects +/* Subclass of sarif_object for SARIF result objects (SARIF v2.1.0 section 3.27). */ -class sarif_result : public json::object +class sarif_result : public sarif_object { public: sarif_result () : m_related_locations_arr (NULL) {} @@ -79,13 +80,13 @@ private: json::array *m_related_locations_arr; }; -/* Subclass of json::object for SARIF notification objects +/* Subclass of sarif_object for SARIF notification objects (SARIF v2.1.0 section 3.58). This subclass is specifically for notifying when an internal compiler error occurs. */ -class sarif_ice_notification : public json::object +class sarif_ice_notification : public sarif_object { public: sarif_ice_notification (diagnostic_context *context, @@ -232,7 +233,24 @@ private: static sarif_builder *the_builder; -/* class sarif_invocation : public json::object. */ +/* class sarif_object : public json::object. */ + +sarif_property_bag & +sarif_object::get_or_create_properties () +{ + json::value *properties_val = get ("properties"); + if (properties_val) + { + if (properties_val->get_kind () == json::JSON_OBJECT) + return *static_cast <sarif_property_bag *> (properties_val); + } + + sarif_property_bag *bag = new sarif_property_bag (); + set ("properties", bag); + return *bag; +} + +/* class sarif_invocation : public sarif_object. */ /* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT. Add an object representing the ICE to the notifications array. */ @@ -250,16 +268,21 @@ sarif_invocation::add_notification_for_ice (diagnostic_context *context, } void -sarif_invocation::prepare_to_flush () +sarif_invocation::prepare_to_flush (diagnostic_context *context) { /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */ set ("executionSuccessful", new json::literal (m_success)); /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */ set ("toolExecutionNotifications", m_notifications_arr); + + /* Call client hook, allowing it to create a custom property bag for + this object (SARIF v2.1.0 section 3.8) e.g. for recording time vars. */ + if (context->m_client_data_hooks) + context->m_client_data_hooks->add_sarif_invocation_properties (*this); } -/* class sarif_result : public json::object. */ +/* class sarif_result : public sarif_object. */ /* Handle secondary diagnostics that occur within a diagnostic group. The closest SARIF seems to have to nested diagnostics is the @@ -319,7 +342,7 @@ sarif_result::add_related_location (json::object *location_obj) m_related_locations_arr->append (location_obj); } -/* class sarif_ice_notification : public json::object. */ +/* class sarif_ice_notification : public sarif_object. */ /* sarif_ice_notification's ctor. DIAGNOSTIC is an internal compiler error. */ @@ -415,7 +438,7 @@ sarif_builder::end_group () void sarif_builder::flush_to_file (FILE *outf) { - m_invocation_obj->prepare_to_flush (); + m_invocation_obj->prepare_to_flush (m_context); json::object *top = make_top_level_object (m_invocation_obj, m_results_array); top->dump (outf); m_invocation_obj = NULL; diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostic-format-sarif.h new file mode 100644 index 0000000..82ed9b9 --- /dev/null +++ b/gcc/diagnostic-format-sarif.h @@ -0,0 +1,45 @@ +/* SARIF output for diagnostics. + Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_DIAGNOSTIC_FORMAT_SARIF_H +#define GCC_DIAGNOSTIC_FORMAT_SARIF_H + +#include "json.h" + +/* Concrete subclass of json::object for SARIF property bags + (SARIF v2.1.0 section 3.8). */ + +class sarif_property_bag : public json::object +{ +}; + +/* Concrete subclass of json::object for SARIF objects that can + contain property bags (as per SARIF v2.1.0 section 3.8.1, which has: + "In addition to those properties that are explicitly documented, every + object defined in this document MAY contain a property named properties + whose value is a property bag.") */ + +class sarif_object : public json::object +{ +public: + sarif_property_bag &get_or_create_properties (); +}; + +#endif /* ! GCC_DIAGNOSTIC_FORMAT_SARIF_H */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 578b4c3..c43260f 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -19933,8 +19933,16 @@ print some statistics about each pass when it finishes. @opindex ftime-report @item -ftime-report -Makes the compiler print some statistics about the time consumed by each -pass when it finishes. +Makes the compiler print some statistics to stderr about the time consumed +by each pass when it finishes. + +If SARIF output of diagnostics was requested via +@option{-fdiagnostics-format=sarif-file} or +@option{-fdiagnostics-format=sarif-stderr} then the @option{-ftime-report} +information is instead emitted in JSON form as part of SARIF output. The +precise format of this JSON data is subject to change, and the values may +not exactly match those emitted to stderr due to being written out at a +slightly different place within the compiler. @opindex ftime-report-details @item -ftime-report-details diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c new file mode 100644 index 0000000..be6b1e7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file -ftime-report" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { verify-sarif-file } } */ + +/* We expect various properties. + The indentation here reflects the expected hierarchy, though these tests + don't check for that, merely the string fragments we expect. + + { dg-final { scan-sarif-file {"invocations": } } } + { dg-final { scan-sarif-file {"properties": } } } + { dg-final { scan-sarif-file {"gcc/timeReport": } } } + { dg-final { scan-sarif-file {"timevars": } } } + { dg-final { scan-sarif-file {"name": "TOTAL",} } } +*/ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c new file mode 100644 index 0000000..e9c2b5e0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c @@ -0,0 +1,21 @@ +/* As per diagnostic-format-sarif-file-timevars-1.c, but + adding -ftime-report-details. */ + +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file -ftime-report -ftime-report-details" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { verify-sarif-file } } */ + +/* We expect various properties. + The indentation here reflects the expected hierarchy, though these tests + don't check for that, merely the string fragments we expect. + + { dg-final { scan-sarif-file {"invocations": } } } + { dg-final { scan-sarif-file {"properties": } } } + { dg-final { scan-sarif-file {"gcc/timeReport": } } } + { dg-final { scan-sarif-file {"timevars": } } } + { dg-final { scan-sarif-file {"name": "TOTAL",} } } +*/ diff --git a/gcc/timevar.cc b/gcc/timevar.cc index d695297..5368ff0 100644 --- a/gcc/timevar.cc +++ b/gcc/timevar.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "timevar.h" #include "options.h" +#include "json.h" #ifndef HAVE_CLOCK_T typedef int clock_t; @@ -135,6 +136,8 @@ class timer::named_items void pop (); void print (FILE *fp, const timevar_time_def *total); + json::value *make_json () const; + private: /* Which timer instance does this relate to? */ timer *m_timer; @@ -143,7 +146,8 @@ class timer::named_items Note that currently we merely store/compare the raw string pointers provided by client code; we don't take a copy, or use strcmp. */ - hash_map <const char *, timer::timevar_def> m_hash_map; + typedef hash_map <const char *, timer::timevar_def> hash_map_t; + hash_map_t m_hash_map; /* The order in which items were originally inserted. */ auto_vec <const char *> m_names; @@ -207,6 +211,23 @@ timer::named_items::print (FILE *fp, const timevar_time_def *total) } } +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::value * +timer::named_items::make_json () const +{ + json::array *arr = new json::array (); + for (const char *item_name : m_names) + { + hash_map_t &mut_map = const_cast <hash_map_t &> (m_hash_map); + timer::timevar_def *def = mut_map.get (item_name); + gcc_assert (def); + arr->append (def->make_json ()); + } + return arr; +} + /* Fill the current times into TIME. The definition of this function also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and HAVE_WALL_TIME macros. */ @@ -251,6 +272,19 @@ timevar_accumulate (struct timevar_time_def *timer, timer->ggc_mem += stop_time->ggc_mem - start_time->ggc_mem; } +/* Get the difference between STOP_TIME and START_TIME. */ + +static void +timevar_diff (struct timevar_time_def *out, + const timevar_time_def &start_time, + const timevar_time_def &stop_time) +{ + out->user = stop_time.user - start_time.user; + out->sys = stop_time.sys - start_time.sys; + out->wall = stop_time.wall - start_time.wall; + out->ggc_mem = stop_time.ggc_mem - start_time.ggc_mem; +} + /* Class timer's constructor. */ timer::timer () : @@ -791,6 +825,134 @@ timer::print (FILE *fp) validate_phases (fp); } +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::object * +make_json_for_timevar_time_def (const timevar_time_def &ttd) +{ + json::object *obj = new json::object (); + obj->set ("user", new json::float_number (ttd.user)); + obj->set ("sys", new json::float_number (ttd.sys)); + obj->set ("wall", new json::float_number (ttd.wall)); + obj->set ("ggc_mem", new json::integer_number (ttd.ggc_mem)); + return obj; +} + +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::value * +timer::timevar_def::make_json () const +{ + json::object *timevar_obj = new json::object (); + timevar_obj->set ("name", new json::string (name)); + timevar_obj->set ("elapsed", make_json_for_timevar_time_def (elapsed)); + + if (children) + { + bool any_children_with_time = false; + for (auto i : *children) + if (!all_zero (i.second)) + { + any_children_with_time = true; + break; + } + if (any_children_with_time) + { + json::array *children_arr = new json::array (); + timevar_obj->set ("children", children_arr); + for (auto i : *children) + { + /* Don't emit timing variables if we're going to get a row of + zeroes. */ + if (all_zero (i.second)) + continue; + json::object *child_obj = new json::object; + children_arr->append (child_obj); + child_obj->set ("name", new json::string (i.first->name)); + child_obj->set ("elapsed", + make_json_for_timevar_time_def (i.second)); + } + } + } + + return timevar_obj; +} + +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::value * +timer::make_json () const +{ + /* Only generate stuff if we have some sort of time information. */ +#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME) + json::object *report_obj = new json::object (); + json::array *json_arr = new json::array (); + report_obj->set ("timevars", json_arr); + + for (unsigned id = 0; id < (unsigned int) TIMEVAR_LAST; ++id) + { + const timevar_def *tv = &m_timevars[(timevar_id_t) id]; + + /* Don't print the total execution time here; this isn't initialized + by the time the sarif output runs. */ + if ((timevar_id_t) id == TV_TOTAL) + continue; + + /* Don't emit timing variables that were never used. */ + if (!tv->used) + continue; + + bool any_children_with_time = false; + if (tv->children) + for (child_map_t::iterator i = tv->children->begin (); + i != tv->children->end (); ++i) + if (! all_zero ((*i).second)) + { + any_children_with_time = true; + break; + } + + /* Don't emit timing variables if we're going to get a row of + zeroes. Unless there are children with non-zero time. */ + if (! any_children_with_time + && all_zero (tv->elapsed)) + continue; + + json_arr->append (tv->make_json ()); + } + + /* Special-case for total. */ + { + /* Get our own total up till now, without affecting TV_TOTAL. */ + struct timevar_time_def total_now; + struct timevar_time_def total_elapsed; + get_time (&total_now); + timevar_diff (&total_elapsed, m_timevars[TV_TOTAL].start_time, total_now); + + json::object *total_obj = new json::object(); + json_arr->append (total_obj); + total_obj->set ("name", new json::string ("TOTAL")); + total_obj->set ("elapsed", make_json_for_timevar_time_def (total_elapsed)); + } + + if (m_jit_client_items) + report_obj->set ("client_items", m_jit_client_items->make_json ()); + + report_obj->set ("CHECKING_P", new json::literal ((bool)CHECKING_P)); + report_obj->set ("flag_checking", new json::literal ((bool)flag_checking)); + + return report_obj; + +#else /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) + || defined (HAVE_WALL_TIME) */ + return NULL; +#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) + || defined (HAVE_WALL_TIME) */ +} + /* Get the name of the topmost item. For use by jit for validating inputs to gcc_jit_timer_pop. */ const char * diff --git a/gcc/timevar.h b/gcc/timevar.h index ad46573..e359e9f 100644 --- a/gcc/timevar.h +++ b/gcc/timevar.h @@ -21,6 +21,8 @@ #ifndef GCC_TIMEVAR_H #define GCC_TIMEVAR_H +namespace json { class value; } + /* Timing variables are used to measure elapsed time in various portions of the compiler. Each measures elapsed user, system, and wall-clock time, as appropriate to and supported by the host @@ -119,6 +121,7 @@ class timer void pop_client_item (); void print (FILE *fp); + json::value *make_json () const; const char *get_topmost_item_name () const; @@ -140,6 +143,8 @@ class timer /* Private type: a timing variable. */ struct timevar_def { + json::value *make_json () const; + /* Elapsed time for this variable. */ struct timevar_time_def elapsed; diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc index 1a35f4c..fc972ce 100644 --- a/gcc/tree-diagnostic-client-data-hooks.cc +++ b/gcc/tree-diagnostic-client-data-hooks.cc @@ -1,5 +1,5 @@ /* Implementation of diagnostic_client_data_hooks for the compilers - (e.g. with knowledge of "tree" and lang_hooks). + (e.g. with knowledge of "tree", lang_hooks, and timevars). Copyright (C) 2022-2023 Free Software Foundation, Inc. Contributed by David Malcolm <dmalcolm@redhat.com>. @@ -27,8 +27,10 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "tree-logical-location.h" #include "diagnostic-client-data-hooks.h" +#include "diagnostic-format-sarif.h" #include "langhooks.h" #include "plugin.h" +#include "timevar.h" /* Concrete class for supplying a diagnostic_context with information about a specific plugin within the client, when the client is the @@ -111,7 +113,7 @@ private: }; /* Subclass of diagnostic_client_data_hooks for use by compilers proper - i.e. with knowledge of "tree", access to langhooks, etc. */ + i.e. with knowledge of "tree", access to langhooks, timevars etc. */ class compiler_data_hooks : public diagnostic_client_data_hooks { @@ -135,6 +137,26 @@ public: return lang_hooks.get_sarif_source_language (filename); } + void + add_sarif_invocation_properties (sarif_object &invocation_obj) + const final override + { + if (g_timer) + if (json::value *timereport_val = g_timer->make_json ()) + { + sarif_property_bag &bag_obj + = invocation_obj.get_or_create_properties (); + bag_obj.set ("gcc/timeReport", timereport_val); + + /* If the user requested SARIF output, then assume they want the + time report data in the SARIF output, and *not* later emitted on + stderr. + Implement this by cleaning up the global timer instance now. */ + delete g_timer; + g_timer = NULL; + } + } + private: compiler_version_info m_version_info; current_fndecl_logical_location m_current_fndecl_logical_loc; |