aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2025-05-06 09:26:17 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2025-05-06 09:26:17 -0400
commitbf6d85490a2a95d251b88812dbf6d239be54ac18 (patch)
tree6c4950e3b3eb97d210f16379568fb4c35061fcfe
parent4cd741dcbd3729863ab005d7ec61a890e0a193f1 (diff)
downloadgcc-bf6d85490a2a95d251b88812dbf6d239be54ac18.zip
gcc-bf6d85490a2a95d251b88812dbf6d239be54ac18.tar.gz
gcc-bf6d85490a2a95d251b88812dbf6d239be54ac18.tar.bz2
libgdiagnostics: add accessors for diagnostic_logical_location [LIBGDIAGNOSTICS_ABI_1]
For followup work I need to be able to get at data from a diagnostic_logical_location after creating it, hence the need to extend libgdiagnostics with accessor entrypoints. This is the first extension to libgdiagnostics since the initial release. The patch uses symbol versioning to add the new entrypoints in the same way that libgccjit does. gcc/ChangeLog: * doc/libgdiagnostics/topics/compatibility.rst: New file, based on gcc/jit/docs/topics/compatibility.rst. * doc/libgdiagnostics/topics/index.rst: Add compatibility.rst. * doc/libgdiagnostics/topics/logical-locations.rst (Accessors): New section. * libgdiagnostics++.h (logical_location::operator bool): New. (logical_location::operator==): New. (logical_location::operator!=): New. (logical_location::get_kind): New. (logical_location::get_parent): New. (logical_location::get_short_name): New. (logical_location::get_fully_qualified_name): New. (logical_location::get_decorated_name): New. * libgdiagnostics.cc (diagnostic_logical_location::get_fully_qualified_name): New. (diagnostic_logical_location_get_kind): New entrypoint. (diagnostic_logical_location_get_parent): New entrypoint. (diagnostic_logical_location_get_short_name): New entrypoint. (diagnostic_logical_location_get_fully_qualified_name): New entrypoint. (diagnostic_logical_location_get_decorated_name): New entrypoint. * libgdiagnostics.h (LIBDIAGNOSTICS_HAVE_LOGICAL_LOCATION_ACCESSORS): New define. (diagnostic_logical_location_get_kind): New entrypoint. (diagnostic_logical_location_get_parent): New entrypoint. (diagnostic_logical_location_get_short_name): New entrypoint. (diagnostic_logical_location_get_fully_qualified_name): New entrypoint. (diagnostic_logical_location_get_decorated_name): New entrypoint. * libgdiagnostics.map (LIBGDIAGNOSTICS_ABI_1): New. gcc/testsuite/ChangeLog: * libgdiagnostics.dg/test-logical-location.c: Include <string.h>. (main): Verify that the accessors work. * libgdiagnostics.dg/test-logical-location.cc: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
-rw-r--r--gcc/doc/libgdiagnostics/topics/compatibility.rst179
-rw-r--r--gcc/doc/libgdiagnostics/topics/index.rst1
-rw-r--r--gcc/doc/libgdiagnostics/topics/logical-locations.rst25
-rw-r--r--gcc/libgdiagnostics++.h64
-rw-r--r--gcc/libgdiagnostics.cc47
-rw-r--r--gcc/libgdiagnostics.h26
-rw-r--r--gcc/libgdiagnostics.map10
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-logical-location.c12
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-logical-location.cc91
9 files changed, 455 insertions, 0 deletions
diff --git a/gcc/doc/libgdiagnostics/topics/compatibility.rst b/gcc/doc/libgdiagnostics/topics/compatibility.rst
new file mode 100644
index 0000000..4df6850
--- /dev/null
+++ b/gcc/doc/libgdiagnostics/topics/compatibility.rst
@@ -0,0 +1,179 @@
+.. Copyright (C) 2015-2025 Free Software Foundation, Inc.
+ Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+ This 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see
+ <https://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+ABI and API compatibility
+=========================
+
+The libgdiagnostics developers strive for ABI and API backward-compatibility:
+programs built against libgdiagnostics.so stand a good chance of running
+without recompilation against newer versions of libgdiagnostics.so, and
+ought to recompile without modification against newer versions of
+libgdiagnostics.h.
+
+.. note:: The libgdiagnostics++.h C++ API is more experimental, and less
+ locked-down at this time.
+
+API compatibility is achieved by extending the API rather than changing
+it. For ABI compatiblity, we avoid bumping the SONAME, and instead use
+symbol versioning to tag each symbol, so that a binary linked against
+libgdiagnostics.so is tagged according to the symbols that it uses.
+
+For example, :func:`diagnostic_logical_location_get_kind` was added in
+``LIBGDIAGNOSTICS_ABI_1``. If a client program uses it, this can be detected
+from metadata by using ``objdump``:
+
+.. code-block:: bash
+
+ $ objdump -p testsuite/libgdiagnostics/test-logical-location.c.exe | tail -n 7
+
+ Version References:
+ required from libc.so.6:
+ 0x09691a75 0x00 04 GLIBC_2.2.5
+ required from libgdiagnostics.so.0:
+ 0x0ec567d1 0x00 03 LIBGDIAGNOSTICS_ABI_1
+ 0x0ec567d0 0x00 02 LIBGDIAGNOSTICS_ABI_0
+
+You can see the symbol tags provided by libgdiagnostics.so using ``objdump``:
+
+.. code-block:: bash
+
+ $ objdump -p libgdiagnostics.so | less
+ [...snip...]
+ Version definitions:
+ 1 0x01 0x099ea4b0 libgdiagnostics.so.0
+ 2 0x00 0x0ec567d0 LIBGDIAGNOSTICS_ABI_0
+ 3 0x00 0x0ec567d1 LIBGDIAGNOSTICS_ABI_1
+ LIBGDIAGNOSTICS_ABI_0
+ [...snip...]
+
+ABI symbol tags
+***************
+
+.. _LIBGDIAGNOSTICS_ABI_0:
+
+``LIBGDIAGNOSTICS_ABI_0``
+-------------------------
+
+All entrypoints in the initial release of libgdiagnostics (in GCC 15) are
+tagged with ``LIBGDIAGNOSTICS_ABI_0``; these entrypoints are:
+
+ * :func:`diagnostic_manager_new`
+
+ * :func:`diagnostic_manager_release`
+
+ * :func:`diagnostic_manager_set_tool_name`
+
+ * :func:`diagnostic_manager_set_full_name`
+
+ * :func:`diagnostic_manager_set_version_string`
+
+ * :func:`diagnostic_manager_set_version_url`
+
+ * :func:`diagnostic_manager_add_text_sink`
+
+ * :func:`diagnostic_text_sink_set_source_printing_enabled`
+
+ * :func:`diagnostic_text_sink_set_colorize`
+
+ * :func:`diagnostic_text_sink_set_labelled_source_colorization_enabled`
+
+ * :func:`diagnostic_manager_add_sarif_sink`
+
+ * :func:`diagnostic_manager_write_patch`
+
+ * :func:`diagnostic_manager_new_file`
+
+ * :func:`diagnostic_file_set_buffered_content`
+
+ * :func:`diagnostic_manager_debug_dump_file`
+
+ * :func:`diagnostic_manager_new_location_from_file_and_line`
+
+ * :func:`diagnostic_manager_new_location_from_file_line_column`
+
+ * :func:`diagnostic_manager_new_location_from_range`
+
+ * :func:`diagnostic_manager_debug_dump_location`
+
+ * :func:`diagnostic_manager_new_logical_location`
+
+ * :func:`diagnostic_manager_debug_dump_logical_location`
+
+ * :func:`diagnostic_manager_begin_group`
+
+ * :func:`diagnostic_manager_end_group`
+
+ * :func:`diagnostic_begin`
+
+ * :func:`diagnostic_set_cwe`
+
+ * :func:`diagnostic_add_rule`
+
+ * :func:`diagnostic_set_location`
+
+ * :func:`diagnostic_set_location_with_label`
+
+ * :func:`diagnostic_add_location`
+
+ * :func:`diagnostic_add_location_with_label`
+
+ * :func:`diagnostic_set_logical_location`
+
+ * :func:`diagnostic_add_fix_it_hint_insert_before`
+
+ * :func:`diagnostic_add_fix_it_hint_insert_after`
+
+ * :func:`diagnostic_add_fix_it_hint_replace`
+
+ * :func:`diagnostic_add_fix_it_hint_delete`
+
+ * :func:`diagnostic_add_execution_path`
+
+ * :func:`diagnostic_manager_new_execution_path`
+
+ * :func:`diagnostic_take_execution_path`
+
+ * :func:`diagnostic_execution_path_release`
+
+ * :func:`diagnostic_execution_path_add_event`
+
+ * :func:`diagnostic_execution_path_add_event_va`
+
+ * :func:`diagnostic_finish`
+
+ * :func:`diagnostic_finish_va`
+
+ * :func:`diagnostic_physical_location_get_file`
+
+.. _LIBGDIAGNOSTICS_ABI_1:
+
+``LIBGDIAGNOSTICS_ABI_1``
+-------------------------
+``LIBGDIAGNOSTICS_ABI_1`` covers the addition of these functions for
+acccessing values within a :type:`diagnostic_logical_location`:
+
+ * :func:`diagnostic_logical_location_get_kind`
+
+ * :func:`diagnostic_logical_location_get_parent`
+
+ * :func:`diagnostic_logical_location_get_short_name`
+
+ * :func:`diagnostic_logical_location_get_fully_qualified_name`
+
+ * :func:`diagnostic_logical_location_get_decorated_name`
diff --git a/gcc/doc/libgdiagnostics/topics/index.rst b/gcc/doc/libgdiagnostics/topics/index.rst
index 6e14c0f..6eb3ed6 100644
--- a/gcc/doc/libgdiagnostics/topics/index.rst
+++ b/gcc/doc/libgdiagnostics/topics/index.rst
@@ -36,3 +36,4 @@ Topic reference
text-output.rst
sarif.rst
ux.rst
+ compatibility.rst
diff --git a/gcc/doc/libgdiagnostics/topics/logical-locations.rst b/gcc/doc/libgdiagnostics/topics/logical-locations.rst
index 3fbee83..85f239d 100644
--- a/gcc/doc/libgdiagnostics/topics/logical-locations.rst
+++ b/gcc/doc/libgdiagnostics/topics/logical-locations.rst
@@ -113,3 +113,28 @@ Associating diagnostics with locations
Set the logical location of ``diag``.
``diag`` must be non-NULL; ``logical_loc`` can be NULL.
+
+Accessors
+*********
+
+The following functions can be used to access the data that was passed to a
+:type:`diagnostic_logical_location` when it was created. In each case, the
+``loc`` parameter must be non-NULL. :type:`const char *` values will point
+at copies of the original buffer.
+
+.. function:: enum diagnostic_logical_location_kind_t diagnostic_logical_location_get_kind (const diagnostic_logical_location *loc)
+
+.. function:: const diagnostic_logical_location *diagnostic_logical_location_get_parent (const diagnostic_logical_location *loc)
+
+.. function:: const char *diagnostic_logical_location_get_short_name (const diagnostic_logical_location *loc)
+
+.. function:: const char *diagnostic_logical_location_get_fully_qualified_name (const diagnostic_logical_location *loc)
+
+.. function:: const char *diagnostic_logical_location_get_decorated_name (const diagnostic_logical_location *loc)
+
+The above accessors were added in :ref:`LIBGDIAGNOSTICS_ABI_1`; you can
+test for their presence using
+
+ .. code-block:: c
+
+ #ifdef LIBDIAGNOSTICS_HAVE_LOGICAL_LOCATION_ACCESSORS
diff --git a/gcc/libgdiagnostics++.h b/gcc/libgdiagnostics++.h
index 39477a0..18a88a2 100644
--- a/gcc/libgdiagnostics++.h
+++ b/gcc/libgdiagnostics++.h
@@ -109,6 +109,25 @@ public:
: m_inner (logical_loc)
{}
+ operator bool() { return m_inner != nullptr; }
+
+ // Various accessors
+ enum diagnostic_logical_location_kind_t get_kind () const;
+ logical_location get_parent () const;
+ const char *get_short_name () const;
+ const char *get_fully_qualified_name () const;
+ const char *get_decorated_name () const;
+
+ bool operator== (const logical_location &other) const
+ {
+ return m_inner == other.m_inner;
+ }
+
+ bool operator!= (const logical_location &other) const
+ {
+ return m_inner != other.m_inner;
+ }
+
const diagnostic_logical_location *m_inner;
};
@@ -385,6 +404,51 @@ physical_location::get_file () const
return file (diagnostic_physical_location_get_file (m_inner));
}
+// class logical_location
+
+inline enum diagnostic_logical_location_kind_t
+logical_location::get_kind () const
+{
+ // m_inner must be non-null
+ return diagnostic_logical_location_get_kind (m_inner);
+}
+
+inline logical_location
+logical_location::get_parent () const
+{
+ if (m_inner)
+ return diagnostic_logical_location_get_parent (m_inner);
+ else
+ return nullptr;
+}
+
+inline const char *
+logical_location::get_short_name () const
+{
+ if (m_inner)
+ return diagnostic_logical_location_get_short_name (m_inner);
+ else
+ return nullptr;
+}
+
+inline const char *
+logical_location::get_fully_qualified_name () const
+{
+ if (m_inner)
+ return diagnostic_logical_location_get_fully_qualified_name (m_inner);
+ else
+ return nullptr;
+}
+
+inline const char *
+logical_location::get_decorated_name () const
+{
+ if (m_inner)
+ return diagnostic_logical_location_get_decorated_name (m_inner);
+ else
+ return nullptr;
+}
+
// class execution_path
inline diagnostic_event_id
diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc
index c2eb975..8a4a159 100644
--- a/gcc/libgdiagnostics.cc
+++ b/gcc/libgdiagnostics.cc
@@ -221,6 +221,11 @@ struct diagnostic_logical_location : public logical_location
const diagnostic_logical_location *get_parent () const { return m_parent; }
+ const char *get_fully_qualified_name () const
+ {
+ return m_fully_qualified_name.get_str ();
+ }
+
label_text get_name_for_path_output () const
{
return label_text::borrow (m_short_name.get_str ());
@@ -1788,3 +1793,45 @@ diagnostic_physical_location_get_file (const diagnostic_physical_location *physi
return physical_loc->get_file ();
}
+
+/* Public entrypoints for accessing logical location data. */
+
+enum diagnostic_logical_location_kind_t
+diagnostic_logical_location_get_kind (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->get_external_kind ();
+}
+
+const diagnostic_logical_location *
+diagnostic_logical_location_get_parent (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->get_parent ();
+}
+
+const char *
+diagnostic_logical_location_get_short_name (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->get_short_name ();
+}
+
+const char *
+diagnostic_logical_location_get_fully_qualified_name (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->get_fully_qualified_name ();
+}
+
+const char *
+diagnostic_logical_location_get_decorated_name (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->get_internal_name ();
+}
diff --git a/gcc/libgdiagnostics.h b/gcc/libgdiagnostics.h
index 2ce0f4c..14567a5 100644
--- a/gcc/libgdiagnostics.h
+++ b/gcc/libgdiagnostics.h
@@ -487,6 +487,32 @@ diagnostic_manager_debug_dump_logical_location (const diagnostic_manager *diag_m
LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+/* Accessors for logical locations (added in LIBGDIAGNOSTICS_ABI_1;
+ you can test for their presence using
+ #ifdef LIBDIAGNOSTICS_HAVE_LOGICAL_LOCATION_ACCESSORS
+*/
+#define LIBDIAGNOSTICS_HAVE_LOGICAL_LOCATION_ACCESSORS
+
+extern enum diagnostic_logical_location_kind_t
+diagnostic_logical_location_get_kind (const diagnostic_logical_location *loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+extern const diagnostic_logical_location *
+diagnostic_logical_location_get_parent (const diagnostic_logical_location *loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+extern const char *
+diagnostic_logical_location_get_short_name (const diagnostic_logical_location *loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+extern const char *
+diagnostic_logical_location_get_fully_qualified_name (const diagnostic_logical_location *loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+extern const char *
+diagnostic_logical_location_get_decorated_name (const diagnostic_logical_location *loc)
+ LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
/* Diagnostic groups. */
/* Begin a diagnostic group. All diagnostics emitted within
diff --git a/gcc/libgdiagnostics.map b/gcc/libgdiagnostics.map
index 5958cfe..4233cf8 100644
--- a/gcc/libgdiagnostics.map
+++ b/gcc/libgdiagnostics.map
@@ -73,3 +73,13 @@ LIBGDIAGNOSTICS_ABI_0
local: *;
};
+
+# Add accessors for diagnostic_logical_location.
+LIBGDIAGNOSTICS_ABI_1 {
+ global:
+ diagnostic_logical_location_get_kind;
+ diagnostic_logical_location_get_parent;
+ diagnostic_logical_location_get_short_name;
+ diagnostic_logical_location_get_fully_qualified_name;
+ diagnostic_logical_location_get_decorated_name;
+} LIBGDIAGNOSTICS_ABI_0;
diff --git a/gcc/testsuite/libgdiagnostics.dg/test-logical-location.c b/gcc/testsuite/libgdiagnostics.dg/test-logical-location.c
index 1408919..b59ece4 100644
--- a/gcc/testsuite/libgdiagnostics.dg/test-logical-location.c
+++ b/gcc/testsuite/libgdiagnostics.dg/test-logical-location.c
@@ -20,6 +20,7 @@ PRINT "hello world!";
const int line_num = __LINE__ - 2;
#include <assert.h>
+#include <string.h>
int
main ()
@@ -62,6 +63,17 @@ main ()
diagnostic_finish (d, "can't find %qs", "foo");
/* end quoted source */
+ /* Verify that the accessors work. */
+ assert (diagnostic_logical_location_get_kind (logical_loc)
+ == DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION);
+ assert (!diagnostic_logical_location_get_parent (logical_loc));
+ assert (!strcmp (diagnostic_logical_location_get_short_name (logical_loc),
+ "test_short_name"));
+ assert (!strcmp (diagnostic_logical_location_get_fully_qualified_name (logical_loc),
+ "test_qualified_name"));
+ assert (!strcmp (diagnostic_logical_location_get_decorated_name (logical_loc),
+ "test_decorated_name"));
+
/* Verify that creating a diagnostic_logical_location with equal values
yields the same instance. */
const diagnostic_logical_location *dup
diff --git a/gcc/testsuite/libgdiagnostics.dg/test-logical-location.cc b/gcc/testsuite/libgdiagnostics.dg/test-logical-location.cc
new file mode 100644
index 0000000..3080ade
--- /dev/null
+++ b/gcc/testsuite/libgdiagnostics.dg/test-logical-location.cc
@@ -0,0 +1,91 @@
+/* C++ example of using a logical location.
+
+ Intended output is similar to:
+
+In function 'test_qualified_name':
+PATH/test-error-with-note.cc:17:8: error: can't find 'foo'
+ 17 | PRINT "hello world!";
+ | ^~~~~~~~~~~~
+
+ along with the equivalent in SARIF. */
+
+#include "libgdiagnostics++.h"
+
+/* Placeholder source:
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+#include <assert.h>
+#include <string.h>
+
+int
+main ()
+{
+ libgdiagnostics::manager mgr;
+
+ auto file = mgr.new_file (__FILE__, "c");
+
+ mgr.add_text_sink (stderr, DIAGNOSTIC_COLORIZE_IF_TTY);
+
+ auto loc_start = mgr.new_location_from_file_line_column (file, line_num, 8);
+ auto loc_end = mgr.new_location_from_file_line_column (file, line_num, 19);
+ auto loc_range = mgr.new_location_from_range (loc_start, loc_start, loc_end);
+
+ auto err (mgr.begin_diagnostic (DIAGNOSTIC_LEVEL_ERROR));
+ err.set_location (loc_range);
+
+ libgdiagnostics::logical_location logical_loc
+ = mgr.new_logical_location (DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ NULL, /* parent */
+ "test_short_name",
+ "test_qualified_name",
+ "test_decorated_name");
+ err.set_logical_location (logical_loc);
+
+ err.finish ("can't find %qs", "foo");
+
+ /* Verify that the accessors work. */
+ assert (logical_loc.get_kind ()
+ == DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION);
+ assert (logical_loc.get_parent ().m_inner == nullptr);
+ assert (!strcmp (logical_loc.get_short_name (),
+ "test_short_name"));
+ assert (!strcmp (logical_loc.get_fully_qualified_name (),
+ "test_qualified_name"));
+ assert (!strcmp (logical_loc.get_decorated_name (),
+ "test_decorated_name"));
+
+ /* Verify that libgdiagnostic::logical_location instances created with
+ equal values compare as equal. */
+ libgdiagnostics::logical_location dup
+ = mgr.new_logical_location (DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ NULL, /* parent */
+ "test_short_name",
+ "test_qualified_name",
+ "test_decorated_name");
+ assert (dup == logical_loc);
+
+ /* Verify that libgdiagnostic::logical_location instances created with
+ differing values compare as non-equal. */
+ libgdiagnostics::logical_location other
+ = mgr.new_logical_location (DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ NULL, /* parent */
+ "something_else",
+ NULL, NULL);
+ assert (other != logical_loc);
+
+ return 0;
+}
+
+/* Check the output from the text sink. */
+/* { dg-begin-multiline-output "" }
+In function 'test_qualified_name':
+ { dg-end-multiline-output "" } */
+/* { dg-regexp "\[^\n\r\]+test-logical-location.cc:17:8: error: can't find 'foo'" } */
+/* { dg-begin-multiline-output "" }
+ 17 | PRINT "hello world!";
+ | ^~~~~~~~~~~~
+ { dg-end-multiline-output "" } */