aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/analyzer/checker-event.cc25
-rw-r--r--gcc/analyzer/checker-event.h15
-rw-r--r--gcc/analyzer/checker-path.h5
-rw-r--r--gcc/analyzer/diagnostic-manager.cc12
-rw-r--r--gcc/analyzer/diagnostic-manager.h3
-rw-r--r--gcc/cgraph.h19
-rw-r--r--gcc/cgraphclones.cc24
-rw-r--r--gcc/config/riscv/autovec-opt.md23
-rw-r--r--gcc/config/riscv/bitmanip.md74
-rw-r--r--gcc/config/riscv/predicates.md4
-rw-r--r--gcc/config/riscv/riscv-opts.h2
-rw-r--r--gcc/config/riscv/riscv-protos.h1
-rw-r--r--gcc/config/riscv/riscv-vector-costs.cc2
-rw-r--r--gcc/config/riscv/riscv.cc54
-rw-r--r--gcc/config/riscv/riscv.opt4
-rw-r--r--gcc/config/riscv/vector-iterators.md4
-rw-r--r--gcc/diagnostic-client-data-hooks.h11
-rw-r--r--gcc/diagnostic-format-json.cc13
-rw-r--r--gcc/diagnostic-format-sarif.cc303
-rw-r--r--gcc/diagnostic-format-sarif.h19
-rw-r--r--gcc/diagnostic-path.cc32
-rw-r--r--gcc/diagnostic-path.h22
-rw-r--r--gcc/diagnostic.cc14
-rw-r--r--gcc/diagnostic.h5
-rw-r--r--gcc/doc/invoke.texi87
-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.rst53
-rw-r--r--gcc/fortran/check.cc42
-rw-r--r--gcc/fortran/interface.cc135
-rw-r--r--gcc/gimple-fold.cc6
-rw-r--r--gcc/ipa-inline-transform.cc2
-rw-r--r--gcc/ipa-inline.cc2
-rw-r--r--gcc/json.cc375
-rw-r--r--gcc/json.h55
-rw-r--r--gcc/lazy-diagnostic-path.cc8
-rw-r--r--gcc/lazy-diagnostic-path.h6
-rw-r--r--gcc/libgdiagnostics++.h64
-rw-r--r--gcc/libgdiagnostics.cc357
-rw-r--r--gcc/libgdiagnostics.h44
-rw-r--r--gcc/libgdiagnostics.map10
-rw-r--r--gcc/libsarifreplay.cc106
-rw-r--r--gcc/logical-location.h135
-rw-r--r--gcc/lto-cgraph.cc2
-rw-r--r--gcc/selftest-diagnostic-path.cc39
-rw-r--r--gcc/selftest-diagnostic-path.h22
-rw-r--r--gcc/selftest-diagnostic.cc2
-rw-r--r--gcc/selftest-diagnostic.h2
-rw-r--r--gcc/selftest-logical-location.cc77
-rw-r--r--gcc/selftest-logical-location.h55
-rw-r--r--gcc/selftest-run-tests.cc1
-rw-r--r--gcc/selftest.h1
-rw-r--r--gcc/simple-diagnostic-path.cc13
-rw-r--r--gcc/simple-diagnostic-path.h12
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/logical-locations-1.C27
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/logical-locations-1.py79
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/logical-locations-2.C69
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/logical-locations-2.py90
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/logical-locations-3.C85
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/logical-locations-3.py61
-rw-r--r--gcc/testsuite/g++.dg/sarif-output/sarif-output.exp31
-rw-r--r--gcc/testsuite/gcc.dg/ipa/pr119852.c50
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc10
-rw-r--r--gcc/testsuite/gcc.dg/pr120074.c20
-rw-r--r--gcc/testsuite/gcc.dg/vect/bb-slp-pr115777.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/pr114512.c109
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h401
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_run.h26
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i16.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i32.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i64.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i8.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u16.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u32.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u64.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u8.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i16.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i32.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i64.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i8.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u16.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u32.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u64.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u8.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i16.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i32.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i64.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i8.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u16.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u32.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u64.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u8.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i16.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i32.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i64.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i8.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u16.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u32.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u64.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u8.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/rvv.exp2
-rw-r--r--gcc/testsuite/gfortran.dg/interface_60.f9070
-rw-r--r--gcc/testsuite/gfortran.dg/pr120049_a.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/pr120049_b.f908
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-logical-location-c.py9
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-logical-location.c12
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-logical-location.cc91
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json-c.py79
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json.c165
-rw-r--r--gcc/testsuite/libgdiagnostics.dg/test-warning-with-path-c.py14
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.1-not-an-object.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-missing-arguments-for-placeholders.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-not-enough-arguments-for-placeholders.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.5-unescaped-braces.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-no-version.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-version-not-a-string.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-bad-runs.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-no-runs.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-non-object-in-runs.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.27.10-bad-level.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.33.3-index-out-of-range.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-unhandled/3.27.10-none-level.sarif3
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-json-example.sarif83
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-xml-example.sarif77
-rw-r--r--gcc/tree-diagnostic-client-data-hooks.cc14
-rw-r--r--gcc/tree-logical-location.cc188
-rw-r--r--gcc/tree-logical-location.h62
-rw-r--r--gcc/tree-vect-data-refs.cc91
-rw-r--r--gcc/tree-vect-slp.cc4
-rw-r--r--gcc/tree-vect-stmts.cc8
-rw-r--r--gcc/tree-vectorizer.h3
132 files changed, 4493 insertions, 515 deletions
diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index 958cdbf..e041778 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -112,7 +112,8 @@ checker_event::checker_event (enum event_kind kind,
m_original_depth (loc_info.m_depth),
m_effective_depth (loc_info.m_depth),
m_pending_diagnostic (NULL), m_emission_id (),
- m_logical_loc (loc_info.m_fndecl)
+ m_logical_loc
+ (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
{
/* Update effective fndecl and depth if inlining has been recorded. */
if (flag_analyzer_undo_inlining)
@@ -122,7 +123,8 @@ checker_event::checker_event (enum event_kind kind,
{
m_effective_fndecl = info.get_inner_fndecl ();
m_effective_depth += info.get_extra_frames ();
- m_logical_loc = tree_logical_location (m_effective_fndecl);
+ m_logical_loc
+ = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
}
}
}
@@ -141,7 +143,8 @@ checker_event::get_meaning () const
void
checker_event::
-maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const
+maybe_add_sarif_properties (sarif_builder &builder,
+ sarif_object &thread_flow_loc_obj) const
{
sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
@@ -150,12 +153,11 @@ maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const
props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
if (m_original_fndecl != m_effective_fndecl)
- {
- tree_logical_location logical_loc (m_original_fndecl);
- props.set<sarif_logical_location>
- (PROPERTY_PREFIX "original_fndecl",
- make_sarif_logical_location_object (logical_loc));
- }
+ props.set_logical_location
+ (PROPERTY_PREFIX "original_fndecl",
+ builder,
+ tree_logical_location_manager::key_from_tree (m_original_fndecl));
+
if (m_original_depth != m_effective_depth)
props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
#undef PROPERTY_PREFIX
@@ -502,10 +504,11 @@ state_change_event::get_meaning () const
for superedge_event. */
void
-superedge_event::maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
+superedge_event::maybe_add_sarif_properties (sarif_builder &builder,
+ sarif_object &thread_flow_loc_obj)
const
{
- checker_event::maybe_add_sarif_properties (thread_flow_loc_obj);
+ checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
if (m_sedge)
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index f3ab899..2f26b8d 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -100,12 +100,9 @@ public:
location_t get_location () const final override { return m_loc; }
int get_stack_depth () const final override { return m_effective_depth; }
- const logical_location *get_logical_location () const final override
+ logical_location get_logical_location () const final override
{
- if (m_effective_fndecl)
- return &m_logical_loc;
- else
- return NULL;
+ return m_logical_loc;
}
meaning get_meaning () const override;
bool connect_to_next_event_p () const override { return false; }
@@ -115,7 +112,8 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const override;
+ maybe_add_sarif_properties (sarif_builder &,
+ sarif_object &thread_flow_loc_obj) const override;
/* Additional functionality. */
tree get_fndecl () const { return m_effective_fndecl; }
@@ -154,7 +152,7 @@ protected:
int m_effective_depth;
pending_diagnostic *m_pending_diagnostic;
diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
- tree_logical_location m_logical_loc;
+ logical_location m_logical_loc;
};
/* A concrete event subclass for a purely textual event, for use in
@@ -391,7 +389,8 @@ public:
class superedge_event : public checker_event
{
public:
- void maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
+ void maybe_add_sarif_properties (sarif_builder &,
+ sarif_object &thread_flow_loc_obj)
const override;
/* Mark this edge event as being either an interprocedural call or
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index dfc782d..80c975c 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -31,8 +31,9 @@ namespace ana {
class checker_path : public diagnostic_path
{
public:
- checker_path (logger *logger)
- : diagnostic_path (),
+ checker_path (const logical_location_manager &logical_loc_mgr,
+ logger *logger)
+ : diagnostic_path (logical_loc_mgr),
m_thread ("main"),
m_logger (logger)
{}
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 7575b16..e5d1a25 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -1580,7 +1580,8 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
/* This is the diagnostic_path subclass that will be built for
the diagnostic. */
- checker_path emission_path (get_logger ());
+ checker_path emission_path (get_logical_location_manager (),
+ get_logger ());
/* Populate emission_path with a full description of EPATH. */
build_emission_path (pb, *epath, &emission_path);
@@ -1656,6 +1657,15 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
}
}
+const logical_location_manager &
+diagnostic_manager::get_logical_location_manager () const
+{
+ gcc_assert (global_dc);
+ auto mgr = global_dc->get_logical_location_manager ();
+ gcc_assert (mgr);
+ return *mgr;
+}
+
/* Emit a "path" of events to EMISSION_PATH describing the exploded path
EPATH within EG. */
diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index b62fc7a..aa0bd79 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -191,6 +191,9 @@ public:
}
private:
+ const logical_location_manager &
+ get_logical_location_manager () const;
+
void build_emission_path (const path_builder &pb,
const exploded_path &epath,
checker_path *emission_path) const;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index f7b67ed..f4ee29e 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -965,15 +965,19 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
If the new node is being inlined into another one, NEW_INLINED_TO should be
the outline function the new one is (even indirectly) inlined to.
All hooks will see this in node's inlined_to, when invoked.
- Can be NULL if the node is not inlined. SUFFIX is string that is appended
- to the original name. */
+ Should be NULL if the node is not inlined.
+
+ SUFFIX is string that is appended to the original name, it should only be
+ NULL if NEW_INLINED_TO is not NULL or if the clone being created is
+ temporary and a record about it should not be added into the ipa-clones
+ dump file. */
cgraph_node *create_clone (tree decl, profile_count count,
bool update_original,
vec<cgraph_edge *> redirect_callers,
bool call_duplication_hook,
cgraph_node *new_inlined_to,
ipa_param_adjustments *param_adjustments,
- const char *suffix = NULL);
+ const char *suffix);
/* Create callgraph node clone with new declaration. The actual body will be
copied later at compilation stage. The name of the new clone will be
@@ -1020,11 +1024,12 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
TREE_MAP is a mapping of tree nodes we want to replace with
new ones (according to results of prior analysis).
- If non-NULL ARGS_TO_SKIP determine function parameters to remove
- from new version.
- If SKIP_RETURN is true, the new version will return void.
+ If non-NULL PARAM_ADJUSTMENTS determine how function formal parameters
+ should be modified in the new version and if it should return void.
If non-NULL BLOCK_TO_COPY determine what basic blocks to copy.
If non_NULL NEW_ENTRY determine new entry BB of the clone.
+ SUFFIX is a string that will be used to create a new name for the new
+ function.
If TARGET_ATTRIBUTES is non-null, when creating a new declaration,
add the attributes to DECL_ATTRIBUTES. And call valid_attribute_p
@@ -1039,7 +1044,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
(vec<cgraph_edge *> redirect_callers,
vec<ipa_replace_map *, va_gc> *tree_map,
ipa_param_adjustments *param_adjustments,
- bitmap bbs_to_copy, basic_block new_entry_block, const char *clone_name,
+ bitmap bbs_to_copy, basic_block new_entry_block, const char *suffix,
tree target_attributes = NULL_TREE, bool version_decl = true);
/* Insert a new cgraph_function_version_info node into cgraph_fnver_htab
diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc
index e6223fa..b45ac49 100644
--- a/gcc/cgraphclones.cc
+++ b/gcc/cgraphclones.cc
@@ -307,12 +307,20 @@ cgraph_node::expand_all_artificial_thunks ()
e = e->next_caller;
}
+/* Dump information about creation of a call graph node clone to the dump file
+ created by the -fdump-ipa-clones option. ORIGINAL is the function being
+ cloned, CLONE is the new clone. SUFFIX is a string that helps identify the
+ reason for cloning, often it is the suffix used by a particular IPA pass to
+ create unique function names. SUFFIX can be NULL and in that case the
+ dumping will not take place, which must be the case only for helper clones
+ which will never be emitted to the output. */
+
void
dump_callgraph_transformation (const cgraph_node *original,
const cgraph_node *clone,
const char *suffix)
{
- if (symtab->ipa_clones_dump_file)
+ if (suffix && symtab->ipa_clones_dump_file)
{
fprintf (symtab->ipa_clones_dump_file,
"Callgraph clone;%s;%d;%s;%d;%d;%s;%d;%s;%d;%d;%s\n",
@@ -358,9 +366,14 @@ localize_profile (cgraph_node *n)
If the new node is being inlined into another one, NEW_INLINED_TO should be
the outline function the new one is (even indirectly) inlined to. All hooks
- will see this in node's inlined_to, when invoked. Can be NULL if the
+ will see this in node's inlined_to, when invoked. Should be NULL if the
node is not inlined.
+ SUFFIX is string that is appended to the original name, it should only be
+ NULL if NEW_INLINED_TO is not NULL or if the clone being created is
+ temporary and a record about it should not be added into the ipa-clones dump
+ file.
+
If PARAM_ADJUSTMENTS is non-NULL, the parameter manipulation information
will be overwritten by the new structure. Otherwise the new node will
share parameter manipulation information with the original node. */
@@ -994,11 +1007,12 @@ cgraph_node::create_version_clone (tree new_decl,
TREE_MAP is a mapping of tree nodes we want to replace with
new ones (according to results of prior analysis).
- If non-NULL ARGS_TO_SKIP determine function parameters to remove
- from new version.
- If SKIP_RETURN is true, the new version will return void.
+ If non-NULL PARAM_ADJUSTMENTS determine how function formal parameters
+ should be modified in the new version and if it should return void.
If non-NULL BLOCK_TO_COPY determine what basic blocks to copy.
If non_NULL NEW_ENTRY determine new entry BB of the clone.
+ SUFFIX is a string that will be used to create a new name for the new
+ function.
If TARGET_ATTRIBUTES is non-null, when creating a new declaration,
add the attributes to DECL_ATTRIBUTES. And call valid_attribute_p
diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md
index 0c3b0cc..7cf7e8a 100644
--- a/gcc/config/riscv/autovec-opt.md
+++ b/gcc/config/riscv/autovec-opt.md
@@ -1673,3 +1673,26 @@
DONE;
}
[(set_attr "type" "vandn")])
+
+
+;; =============================================================================
+;; Combine vec_duplicate + op.vv to op.vx
+;; Include
+;; - vadd.vx
+;; =============================================================================
+(define_insn_and_split "*<optab>_vx_<mode>"
+ [(set (match_operand:V_VLSI 0 "register_operand")
+ (any_int_binop_no_shift_vx:V_VLSI
+ (vec_duplicate:V_VLSI
+ (match_operand:<VEL> 1 "register_operand"))
+ (match_operand:V_VLSI 2 "<binop_rhs2_predicate>")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[2], operands[1]};
+ riscv_vector::emit_vlmax_insn (code_for_pred_scalar (<CODE>, <MODE>mode),
+ riscv_vector::BINARY_OP, ops);
+ }
+ [(set_attr "type" "vialu")])
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 20d03dc..95df533 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1302,3 +1302,77 @@
}
DONE;
})
+
+;; More forms of single bit extraction. The RISC-V port does not
+;; define SHIFT_COUNT_TRUNCATED so we need forms where the bit position
+;; is masked.
+;;
+;; We could in theory use this for rv32 as well, but it probably does
+;; not occur in practice. The bit position would need to be QI/HI mode,
+;; otherwise we would not need the zero extension.
+;;
+;; One could also argue that the zero extension is redundant and should
+;; have been optimized away during RTL simplification.
+(define_insn "*bextdi_position_ze_masked"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extract:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 1)
+ (zero_extend:DI
+ (and:SI (match_operand:SI 2 "register_operand" "r")
+ (const_int 63)))))]
+ "TARGET_64BIT && TARGET_ZBS"
+ "bext\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+;; Same as above, but without the extraneous zero_extend.
+(define_insn "*bextdi_position_ze_masked"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (zero_extract:X
+ (match_operand:X 1 "register_operand" "r")
+ (const_int 1)
+ (and:X (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "bitpos_mask_operand" "n"))))]
+ "TARGET_64BIT && TARGET_ZBS"
+ "bext\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+
+;; Single bit extraction by first shifting it into the sign bit, then
+;; shifting it down to the low bit.
+(define_insn "*bext<mode>_position_masked"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (lshiftrt:X (ashift:X (match_operand:X 1 "register_operand" "r")
+ (match_operand:QI 2 "register_operand" "r"))
+ (match_operand:X 3 "bitpos_mask_operand" "n")))]
+ "TARGET_ZBS"
+ "bext\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+;; Single bit extraction by shifting into the low bit, but with the
+;; position formed with a subreg of a mask.
+(define_insn "*bext<mode>_position_masked_subreg"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (lshiftrt:X
+ (ashift:X (match_operand:X 1 "register_operand" "r")
+ (subreg:QI
+ (and:X (match_operand:X 2 "register_operand" "r")
+ (match_operand:X 3 "bitpos_mask_operand" "n")) 0))
+ (match_operand:X 4 "bitpos_mask_operand" "n")))]
+ "TARGET_ZBS"
+ "bext\t%0,%1,%2"
+ [(set_attr "type" "bitmanip")])
+
+;; This has shown up in testing. In particular we end up with an
+;; immediate input. We can load that into a register and target
+;; one of the above bext patterns.
+(define_split
+ [(set (match_operand:X 0 "register_operand")
+ (and:X (lshiftrt:X (match_operand 1 "immediate_operand")
+ (match_operand:QI 2 "register_operand"))
+ (const_int 1)))
+ (clobber (match_operand:X 3 "register_operand"))]
+ ""
+ [(set (match_dup 3) (match_dup 1))
+ (set (match_dup 0) (zero_extract:X (match_dup 3)
+ (const_int 1)
+ (zero_extend:X (match_dup 2))))])
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index f26bafc..c9a638c 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -685,3 +685,7 @@
(and (match_operand 0 "register_operand")
(match_test "REGNO (op) == RETURN_ADDR_REGNUM
|| REGNO (op) == T0_REGNUM")))
+
+(define_predicate "bitpos_mask_operand"
+ (and (match_code "const_int")
+ (match_test "TARGET_64BIT ? INTVAL (op) == 63 : INTVAL (op) == 31")))
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 26fe228..9766b89 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -162,4 +162,6 @@ enum riscv_tls_type {
#define TARGET_VECTOR_AUTOVEC_SEGMENT \
(TARGET_VECTOR && riscv_mautovec_segment)
+#define GPR2VR_COST_UNPROVIDED -1
+
#endif /* ! GCC_RISCV_OPTS_H */
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 2e88990..b0d5bbb 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -836,6 +836,7 @@ struct riscv_tune_info {
const struct riscv_tune_info *
riscv_parse_tune (const char *, bool);
const cpu_vector_cost *get_vector_costs ();
+int get_gr2vr_cost ();
enum
{
diff --git a/gcc/config/riscv/riscv-vector-costs.cc b/gcc/config/riscv/riscv-vector-costs.cc
index 167375c..c28eecd 100644
--- a/gcc/config/riscv/riscv-vector-costs.cc
+++ b/gcc/config/riscv/riscv-vector-costs.cc
@@ -1121,7 +1121,7 @@ costs::adjust_stmt_cost (enum vect_cost_for_stmt kind, loop_vec_info loop,
{
case scalar_to_vec:
stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->FR2VR
- : costs->regmove->GR2VR);
+ : get_gr2vr_cost ());
break;
case vec_to_scalar:
stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->VR2FR
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a065732..3ee88db 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3863,7 +3863,40 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
Cost Model need to be well analyzed and supported in the future. */
if (riscv_v_ext_mode_p (mode))
{
- *total = COSTS_N_INSNS (1);
+ int gr2vr_cost = get_gr2vr_cost ();
+
+ switch (outer_code)
+ {
+ case SET:
+ {
+ switch (GET_CODE (x))
+ {
+ case VEC_DUPLICATE:
+ *total = gr2vr_cost * COSTS_N_INSNS (1);
+ break;
+ case PLUS:
+ {
+ rtx op_0 = XEXP (x, 0);
+ rtx op_1 = XEXP (x, 1);
+
+ if (GET_CODE (op_0) == VEC_DUPLICATE
+ || GET_CODE (op_1) == VEC_DUPLICATE)
+ *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ break;
+ default:
+ *total = COSTS_N_INSNS (1);
+ break;
+ }
+ }
+ break;
+ default:
+ *total = COSTS_N_INSNS (1);
+ break;
+ }
+
return true;
}
@@ -9690,7 +9723,7 @@ riscv_register_move_cost (machine_mode mode,
if (to == V_REGS)
{
if (from_is_gpr)
- return get_vector_costs ()->regmove->GR2VR;
+ return get_gr2vr_cost ();
else if (from_is_fpr)
return get_vector_costs ()->regmove->FR2VR;
}
@@ -12540,6 +12573,21 @@ get_vector_costs ()
return costs;
}
+/* Return the cost of operation that move from gpr to vr.
+ It will take the value of --param=gpr2vr_cost if it is provided.
+ Or the default regmove->GR2VR will be returned. */
+
+int
+get_gr2vr_cost ()
+{
+ int cost = get_vector_costs ()->regmove->GR2VR;
+
+ if (gpr2vr_cost != GPR2VR_COST_UNPROVIDED)
+ cost = gpr2vr_cost;
+
+ return cost;
+}
+
/* Implement targetm.vectorize.builtin_vectorization_cost. */
static int
@@ -12606,7 +12654,7 @@ riscv_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
{
/* TODO: This is too pessimistic in case we can splat. */
int regmove_cost = fp ? costs->regmove->FR2VR
- : costs->regmove->GR2VR;
+ : get_gr2vr_cost ();
return (regmove_cost + common_costs->scalar_to_vec_cost)
* estimated_poly_value (TYPE_VECTOR_SUBPARTS (vectype));
}
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 7515c8e..7102480 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -579,6 +579,10 @@ Inline strlen calls if possible.
Target RejectNegative Joined UInteger Var(riscv_strcmp_inline_limit) Init(64)
Max number of bytes to compare as part of inlined strcmp/strncmp routines (default: 64).
+-param=gpr2vr-cost=
+Target RejectNegative Joined UInteger Var(gpr2vr_cost) Init(GPR2VR_COST_UNPROVIDED)
+Set the cost value of the rvv instruction when operate from GPR to VR.
+
Enum
Name(rvv_max_lmul) Type(enum rvv_max_lmul_enum)
The RVV possible LMUL (-mrvv-max-lmul=):
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index b4c86909..eae3340 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -4041,6 +4041,10 @@
smax umax smin umin mult div udiv mod umod
])
+(define_code_iterator any_int_binop_no_shift_vx [
+ plus
+])
+
(define_code_iterator any_int_unop [neg not])
(define_code_iterator any_commutative_binop [plus and ior xor
diff --git a/gcc/diagnostic-client-data-hooks.h b/gcc/diagnostic-client-data-hooks.h
index 0057b80..9909172 100644
--- a/gcc/diagnostic-client-data-hooks.h
+++ b/gcc/diagnostic-client-data-hooks.h
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H
#define GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H
+#include "logical-location.h"
+
class sarif_object;
class client_version_info;
@@ -35,8 +37,13 @@ class diagnostic_client_data_hooks
/* Get version info for this client, or NULL. */
virtual const client_version_info *get_any_version_info () const = 0;
- /* Get the current logical_location for this client, or NULL. */
- virtual const logical_location *get_current_logical_location () const = 0;
+ /* Get the current logical_location_manager for this client, or NULL. */
+ virtual const logical_location_manager *get_logical_location_manager () const = 0;
+
+ /* Get the current logical_location, or null.
+ If this returns a non-null logical_location, then
+ get_logical_location_manager must return non-NULL. */
+ virtual logical_location get_current_logical_location () const = 0;
/* Get a sourceLanguage value for FILENAME, or return NULL.
See SARIF v2.1.0 Appendix J for suggested values. */
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index c28804e..205678d 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-buffer.h"
#include "json.h"
#include "selftest.h"
+#include "diagnostic-client-data-hooks.h"
#include "logical-location.h"
class json_output_format;
@@ -272,11 +273,13 @@ make_json_for_path (diagnostic_context &context,
auto pp = ref_pp->clone ();
event.print_desc (*pp.get ());
event_obj->set_string ("description", pp_formatted_text (pp.get ()));
- if (const logical_location *logical_loc = event.get_logical_location ())
- {
- label_text name (logical_loc->get_name_for_path_output ());
- event_obj->set_string ("function", name.get ());
- }
+ if (logical_location logical_loc = event.get_logical_location ())
+ if (auto hooks = context.get_client_data_hooks ())
+ if (auto mgr = hooks->get_logical_location_manager ())
+ {
+ label_text name (mgr->get_name_for_path_output (logical_loc));
+ event_obj->set_string ("function", name.get ());
+ }
event_obj->set_integer ("depth", event.get_stack_depth ());
path_array->append (std::move (event_obj));
}
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index bc6abdf..454eaae 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -51,6 +51,52 @@ along with GCC; see the file COPYING3. If not see
#include "demangle.h"
#include "backtrace.h"
+/* A json::array where the values are "unique" as per
+ SARIF v2.1.0 section 3.7.3 ("Array properties with unique values"). */
+
+template <typename JsonElementType>
+class sarif_array_of_unique : public json::array
+{
+ public:
+ size_t append_uniquely (std::unique_ptr<JsonElementType> val)
+ {
+ /* This should be O(log(n)) due to the std::map. */
+ auto search = m_index_by_value.find (val.get ());
+ if (search != m_index_by_value.end())
+ return (*search).second;
+
+ const size_t insertion_idx = size ();
+ m_index_by_value.insert ({val.get (), insertion_idx});
+ append (std::move (val));
+ return insertion_idx;
+ }
+
+ /* For ease of reading output, add "index": idx to all
+ objects in the array.
+ We don't do this until we've added everything, since
+ the "index" property would otherwise confuse the
+ comparison against new elements. */
+ void add_explicit_index_values ()
+ {
+ for (size_t idx = 0; idx < length (); ++idx)
+ if (json::object *obj = get (idx)->dyn_cast_object ())
+ obj->set_integer ("index", idx);
+ }
+
+private:
+ struct comparator_t {
+ bool operator () (const json::value *a, const json::value *b) const
+ {
+ gcc_assert (a);
+ gcc_assert (b);
+ return json::value::compare (*a, *b) < 0;
+ }
+ };
+
+ // json::value * here is borrowed from m_elements
+ std::map<json::value *, int, comparator_t> m_index_by_value;
+};
+
/* Forward decls. */
class sarif_builder;
class content_renderer;
@@ -446,6 +492,13 @@ class sarif_physical_location : public sarif_object {};
class sarif_region : public sarif_object {};
+/* Subclass of sarif_object for SARIF "logicalLocation" objects
+ (SARIF v2.1.0 section 3.33). */
+
+class sarif_logical_location : public sarif_object
+{
+};
+
/* Subclass of sarif_object for SARIF "locationRelationship" objects
(SARIF v2.1.0 section 3.34). */
@@ -708,6 +761,12 @@ public:
m_printer = &printer;
}
+ const logical_location_manager *
+ get_logical_location_manager () const
+ {
+ return m_logical_loc_mgr;
+ }
+
void on_report_diagnostic (const diagnostic_info &diagnostic,
diagnostic_t orig_diag_kind,
diagnostic_sarif_format_buffer *buffer);
@@ -729,7 +788,7 @@ public:
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
const rich_location &rich_loc,
- const logical_location *logical_loc,
+ logical_location logical_loc,
enum diagnostic_artifact_role role);
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
@@ -766,6 +825,9 @@ public:
const sarif_generation_options &get_opts () const { return m_sarif_gen_opts; }
+ std::unique_ptr<sarif_logical_location>
+ make_minimal_sarif_logical_location (logical_location);
+
private:
class sarif_token_printer : public token_printer
{
@@ -790,7 +852,7 @@ private:
location_t where);
void
set_any_logical_locs_arr (sarif_location &location_obj,
- const logical_location *logical_loc);
+ logical_location logical_loc);
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
const diagnostic_event &event,
@@ -823,6 +885,10 @@ private:
const content_renderer *snippet_renderer) const;
std::unique_ptr<sarif_region>
make_region_object_for_hint (const fixit_hint &hint) const;
+
+ int
+ ensure_sarif_logical_location_for (logical_location k);
+
std::unique_ptr<sarif_multiformat_message_string>
make_multiformat_message_string (const char *msg) const;
std::unique_ptr<sarif_log>
@@ -879,6 +945,8 @@ private:
const line_maps *m_line_maps;
sarif_token_printer m_token_printer;
+ const logical_location_manager *m_logical_loc_mgr;
+
/* The JSON object for the invocation object. */
std::unique_ptr<sarif_invocation> m_invocation_obj;
@@ -901,6 +969,8 @@ private:
/* The set of all CWE IDs we've seen, if any. */
hash_set <int_hash <int, 0, 1> > m_cwe_id_set;
+ std::unique_ptr<sarif_array_of_unique<sarif_logical_location>> m_cached_logical_locs;
+
int m_tabstop;
std::unique_ptr<sarif_serialization_format> m_serialization_format;
@@ -1232,7 +1302,8 @@ sarif_result::on_nested_diagnostic (const diagnostic_info &diagnostic,
sometimes these will related to current_function_decl, but
often they won't. */
auto location_obj
- = builder.make_location_object (*this, *diagnostic.richloc, nullptr,
+ = builder.make_location_object (*this, *diagnostic.richloc,
+ logical_location (),
diagnostic_artifact_role::result_file);
auto message_obj
= builder.make_message_object (pp_formatted_text (builder.get_printer ()));
@@ -1579,6 +1650,7 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_printer (&printer),
m_line_maps (line_maps),
m_token_printer (*this),
+ m_logical_loc_mgr (nullptr),
m_invocation_obj
(std::make_unique<sarif_invocation> (*this,
context.get_original_argv ())),
@@ -1587,6 +1659,8 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_seen_any_relative_paths (false),
m_rule_id_set (),
m_rules_arr (new json::array ()),
+ m_cached_logical_locs
+ (std::make_unique<sarif_array_of_unique<sarif_logical_location>> ()),
m_tabstop (context.m_tabstop),
m_serialization_format (std::move (serialization_format)),
m_sarif_gen_opts (sarif_gen_opts),
@@ -1596,6 +1670,9 @@ sarif_builder::sarif_builder (diagnostic_context &context,
gcc_assert (m_line_maps);
gcc_assert (m_serialization_format);
+ if (auto client_data_hooks = context.get_client_data_hooks ())
+ m_logical_loc_mgr = client_data_hooks->get_logical_location_manager ();
+
/* Mark MAIN_INPUT_FILENAME_ as the artifact that the tool was
instructed to scan.
Only quote the contents if it gets referenced by physical locations,
@@ -2089,7 +2166,7 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
enum diagnostic_artifact_role role)
{
auto locations_arr = std::make_unique<json::array> ();
- const logical_location *logical_loc = nullptr;
+ logical_location logical_loc;
if (auto client_data_hooks = m_context.get_client_data_hooks ())
logical_loc = client_data_hooks->get_current_logical_location ();
@@ -2103,18 +2180,24 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
}
/* If LOGICAL_LOC is non-null, use it to create a "logicalLocations" property
- within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */
+ within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4) with a minimal logical
+ location object referencing theRuns.logicalLocations (3.33.3). */
void
sarif_builder::
set_any_logical_locs_arr (sarif_location &location_obj,
- const logical_location *logical_loc)
+ logical_location logical_loc)
{
if (!logical_loc)
return;
+ gcc_assert (m_logical_loc_mgr);
auto location_locs_arr = std::make_unique<json::array> ();
+
+ auto logical_loc_obj = make_minimal_sarif_logical_location (logical_loc);
+
location_locs_arr->append<sarif_logical_location>
- (make_sarif_logical_location_object (*logical_loc));
+ (std::move (logical_loc_obj));
+
location_obj.set<json::array> ("logicalLocations",
std::move (location_locs_arr));
}
@@ -2127,7 +2210,7 @@ set_any_logical_locs_arr (sarif_location &location_obj,
std::unique_ptr<sarif_location>
sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
const rich_location &rich_loc,
- const logical_location *logical_loc,
+ logical_location logical_loc,
enum diagnostic_artifact_role role)
{
class escape_nonascii_renderer : public content_renderer
@@ -2321,7 +2404,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
std::move (phs_loc_obj));
/* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
- const logical_location *logical_loc = event.get_logical_location ();
+ logical_location logical_loc = event.get_logical_location ();
set_any_logical_locs_arr (*location_obj, logical_loc);
/* "message" property (SARIF v2.1.0 section 3.28.5). */
@@ -2651,6 +2734,7 @@ maybe_get_sarif_kind (enum logical_location_kind kind)
case LOGICAL_LOCATION_KIND_UNKNOWN:
return nullptr;
+ /* Kinds within executable code. */
case LOGICAL_LOCATION_KIND_FUNCTION:
return "function";
case LOGICAL_LOCATION_KIND_MEMBER:
@@ -2667,35 +2751,120 @@ maybe_get_sarif_kind (enum logical_location_kind kind)
return "parameter";
case LOGICAL_LOCATION_KIND_VARIABLE:
return "variable";
+
+ /* Kinds within XML or HTML documents. */
+ case LOGICAL_LOCATION_KIND_ELEMENT:
+ return "element";
+ case LOGICAL_LOCATION_KIND_ATTRIBUTE:
+ return "attribute";
+ case LOGICAL_LOCATION_KIND_TEXT:
+ return "text";
+ case LOGICAL_LOCATION_KIND_COMMENT:
+ return "comment";
+ case LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION:
+ return "processingInstruction";
+ case LOGICAL_LOCATION_KIND_DTD:
+ return "dtd";
+ case LOGICAL_LOCATION_KIND_DECLARATION:
+ return "declaration";
+
+ /* Kinds within JSON documents. */
+ case LOGICAL_LOCATION_KIND_OBJECT:
+ return "object";
+ case LOGICAL_LOCATION_KIND_ARRAY:
+ return "array";
+ case LOGICAL_LOCATION_KIND_PROPERTY:
+ return "property";
+ case LOGICAL_LOCATION_KIND_VALUE:
+ return "value";
}
}
-/* Make a "logicalLocation" object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
- or return nullptr. */
+/* Set PROPERTY_NAME within this bag to a "logicalLocation" object (SARIF v2.1.0
+ section 3.33) for LOGICAL_LOC. The object has an "index" property to refer to
+ theRuns.logicalLocations (3.33.3). */
-std::unique_ptr<sarif_logical_location>
-make_sarif_logical_location_object (const logical_location &logical_loc)
+void
+sarif_property_bag::set_logical_location (const char *property_name,
+ sarif_builder &builder,
+ logical_location logical_loc)
{
- auto logical_loc_obj = std::make_unique<sarif_logical_location> ();
+ set<sarif_logical_location>
+ (property_name,
+ builder.make_minimal_sarif_logical_location (logical_loc));
+}
- /* "name" property (SARIF v2.1.0 section 3.33.4). */
- if (const char *short_name = logical_loc.get_short_name ())
- logical_loc_obj->set_string ("name", short_name);
+/* Ensure that m_cached_logical_locs has a "logicalLocation" object
+ (SARIF v2.1.0 section 3.33) for K, and return its index within the
+ array. */
+
+int
+sarif_builder::
+ensure_sarif_logical_location_for (logical_location k)
+{
+ gcc_assert (m_logical_loc_mgr);
+
+ auto sarif_logical_loc = std::make_unique<sarif_logical_location> ();
+
+ if (const char *short_name = m_logical_loc_mgr->get_short_name (k))
+ sarif_logical_loc->set_string ("name", short_name);
/* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
- if (const char *name_with_scope = logical_loc.get_name_with_scope ())
- logical_loc_obj->set_string ("fullyQualifiedName", name_with_scope);
+ if (const char *name_with_scope = m_logical_loc_mgr->get_name_with_scope (k))
+ sarif_logical_loc->set_string ("fullyQualifiedName", name_with_scope);
/* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
- if (const char *internal_name = logical_loc.get_internal_name ())
- logical_loc_obj->set_string ("decoratedName", internal_name);
+ if (const char *internal_name = m_logical_loc_mgr->get_internal_name (k))
+ sarif_logical_loc->set_string ("decoratedName", internal_name);
/* "kind" property (SARIF v2.1.0 section 3.33.7). */
- enum logical_location_kind kind = logical_loc.get_kind ();
+ enum logical_location_kind kind = m_logical_loc_mgr->get_kind (k);
if (const char *sarif_kind_str = maybe_get_sarif_kind (kind))
- logical_loc_obj->set_string ("kind", sarif_kind_str);
+ sarif_logical_loc->set_string ("kind", sarif_kind_str);
+
+ /* "parentIndex" property (SARIF v2.1.0 section 3.33.8). */
+ if (auto parent_key = m_logical_loc_mgr->get_parent (k))
+ {
+ /* Recurse upwards. */
+ int parent_index = ensure_sarif_logical_location_for (parent_key);
+ sarif_logical_loc->set_integer ("parentIndex", parent_index);
+ }
+
+ /* Consolidate if this logical location already exists. */
+ int index
+ = m_cached_logical_locs->append_uniquely (std::move (sarif_logical_loc));
- return logical_loc_obj;
+ return index;
+}
+
+/* Ensure that theRuns.logicalLocations (3.14.17) has a "logicalLocation" object
+ (SARIF v2.1.0 section 3.33) for LOGICAL_LOC.
+ Create and return a minimal logicalLocation object referring to the
+ full object by index. */
+
+std::unique_ptr<sarif_logical_location>
+sarif_builder::
+make_minimal_sarif_logical_location (logical_location logical_loc)
+{
+ gcc_assert (m_logical_loc_mgr);
+
+ /* Ensure that m_cached_logical_locs has a "logicalLocation" object
+ (SARIF v2.1.0 section 3.33) for LOGICAL_LOC, and return its index within
+ the array. */
+
+ auto sarif_logical_loc = std::make_unique <sarif_logical_location> ();
+
+ int index = ensure_sarif_logical_location_for (logical_loc);
+
+ // 3.33.3 index property
+ sarif_logical_loc->set_integer ("index", index);
+
+ /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
+ if (const char *name_with_scope
+ = m_logical_loc_mgr->get_name_with_scope (logical_loc))
+ sarif_logical_loc->set_string ("fullyQualifiedName", name_with_scope);
+
+ return sarif_logical_loc;
}
label_text
@@ -2784,7 +2953,7 @@ populate_thread_flow_location_object (sarif_result &result,
{
/* Give diagnostic_event subclasses a chance to add custom properties
via a property bag. */
- ev.maybe_add_sarif_properties (tfl_obj);
+ ev.maybe_add_sarif_properties (*this, tfl_obj);
/* "location" property (SARIF v2.1.0 section 3.38.3). */
tfl_obj.set<sarif_location>
@@ -3038,6 +3207,14 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
/* "results" property (SARIF v2.1.0 section 3.14.23). */
run_obj->set<json::array> ("results", std::move (results));
+ /* "logicalLocations" property (SARIF v2.1.0 3.14.17). */
+ if (m_cached_logical_locs->size () > 0)
+ {
+ m_cached_logical_locs->add_explicit_index_values ();
+ run_obj->set<json::array> ("logicalLocations",
+ std::move (m_cached_logical_locs));
+ }
+
return run_obj;
}
@@ -3924,6 +4101,76 @@ sarif_generation_options::sarif_generation_options ()
namespace selftest {
+static void
+test_sarif_array_of_unique_1 ()
+{
+ sarif_array_of_unique<json::string> arr;
+
+ ASSERT_EQ (arr.length (), 0);
+
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("foo"));
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 1);
+ }
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("bar"));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+ }
+
+ /* Try adding them again, should be idempotent. */
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("foo"));
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 2);
+ }
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("bar"));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+ }
+}
+
+static void
+test_sarif_array_of_unique_2 ()
+{
+ sarif_array_of_unique<json::object> arr;
+
+ ASSERT_EQ (arr.length (), 0);
+
+ {
+ auto obj0 = std::make_unique<json::object> ();
+ size_t idx = arr.append_uniquely (std::move (obj0));
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 1);
+
+ // Attempting to add another empty objects should be idempotent.
+ idx = arr.append_uniquely (std::make_unique<json::object> ());
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 1);
+ }
+ {
+ auto obj1 = std::make_unique<json::object> ();
+ obj1->set_string ("foo", "bar");
+ size_t idx = arr.append_uniquely (std::move (obj1));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+
+ // Attempting to add an equivalent object should be idempotent.
+ auto other = std::make_unique<json::object> ();
+ other->set_string ("foo", "bar");
+ idx = arr.append_uniquely (std::move (other));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+ }
+
+ // Verify behavior of add_explicit_index_values.
+ arr.add_explicit_index_values ();
+ ASSERT_JSON_INT_PROPERTY_EQ (arr[0], "index", 0);
+ ASSERT_JSON_INT_PROPERTY_EQ (arr[1], "index", 1);
+}
+
/* A subclass of sarif_output_format for writing selftests.
The JSON output is cached internally, rather than written
out to a file. */
@@ -4029,7 +4276,8 @@ test_make_location_object (const sarif_generation_options &sarif_gen_opts,
std::unique_ptr<sarif_location> location_obj
= builder.make_location_object
- (result, richloc, nullptr, diagnostic_artifact_role::analysis_target);
+ (result, richloc, logical_location (),
+ diagnostic_artifact_role::analysis_target);
ASSERT_NE (location_obj, nullptr);
auto physical_location
@@ -4588,6 +4836,9 @@ run_line_table_case_tests_per_version (const line_table_case &case_)
void
diagnostic_format_sarif_cc_tests ()
{
+ test_sarif_array_of_unique_1 ();
+ test_sarif_array_of_unique_2 ();
+
for_each_sarif_gen_option (test_simple_log);
for_each_sarif_gen_option (test_message_with_embedded_link);
for_each_sarif_gen_option (test_message_with_braces);
diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostic-format-sarif.h
index 6446257..4e6a525 100644
--- a/gcc/diagnostic-format-sarif.h
+++ b/gcc/diagnostic-format-sarif.h
@@ -24,8 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "json.h"
#include "diagnostic-format.h"
#include "diagnostic-output-file.h"
-
-class logical_location;
+#include "logical-location.h"
/* Enum for choosing what format to serializing the generated SARIF into. */
@@ -115,11 +114,17 @@ make_sarif_sink (diagnostic_context &context,
const sarif_generation_options &sarif_gen_opts,
diagnostic_output_file output_file);
+class sarif_builder;
+
/* Concrete subclass of json::object for SARIF property bags
(SARIF v2.1.0 section 3.8). */
class sarif_property_bag : public json::object
{
+public:
+ void set_logical_location (const char *property_name,
+ sarif_builder &,
+ logical_location logical_loc);
};
/* Concrete subclass of json::object for SARIF objects that can
@@ -134,14 +139,4 @@ public:
sarif_property_bag &get_or_create_properties ();
};
-/* Subclass of sarif_object for SARIF "logicalLocation" objects
- (SARIF v2.1.0 section 3.33). */
-
-class sarif_logical_location : public sarif_object
-{
-};
-
-extern std::unique_ptr<sarif_logical_location>
-make_sarif_logical_location_object (const logical_location &logical_loc);
-
#endif /* ! GCC_DIAGNOSTIC_FORMAT_SARIF_H */
diff --git a/gcc/diagnostic-path.cc b/gcc/diagnostic-path.cc
index d618c37..9340e4e 100644
--- a/gcc/diagnostic-path.cc
+++ b/gcc/diagnostic-path.cc
@@ -181,8 +181,8 @@ diagnostic_path::get_first_event_in_a_function (unsigned *out_idx) const
for (unsigned i = 0; i < num; i++)
{
const diagnostic_event &event = get_event (i);
- if (const logical_location *logical_loc = event.get_logical_location ())
- if (logical_loc->function_p ())
+ if (logical_location logical_loc = event.get_logical_location ())
+ if (m_logical_loc_mgr.function_p (logical_loc))
{
*out_idx = i;
return true;
@@ -409,8 +409,10 @@ class per_thread_summary
{
public:
per_thread_summary (const diagnostic_path &path,
+ const logical_location_manager &logical_loc_mgr,
label_text name, unsigned swimlane_idx)
: m_path (path),
+ m_logical_loc_mgr (logical_loc_mgr),
m_name (std::move (name)),
m_swimlane_idx (swimlane_idx),
m_last_event (nullptr),
@@ -437,6 +439,7 @@ private:
friend struct event_range;
const diagnostic_path &m_path;
+ const logical_location_manager &m_logical_loc_mgr;
const label_text m_name;
@@ -703,7 +706,7 @@ struct event_range
const diagnostic_path &m_path;
const diagnostic_event &m_initial_event;
- const logical_location *m_logical_loc;
+ logical_location m_logical_loc;
int m_stack_depth;
unsigned m_start_idx;
unsigned m_end_idx;
@@ -729,6 +732,10 @@ struct path_summary
bool colorize = false,
bool show_event_links = true);
+ const logical_location_manager &get_logical_location_manager () const
+ {
+ return m_logical_loc_mgr;
+ }
unsigned get_num_ranges () const { return m_ranges.length (); }
bool multithreaded_p () const { return m_per_thread_summary.length () > 1; }
@@ -740,6 +747,7 @@ struct path_summary
return **slot;
}
+ const logical_location_manager &m_logical_loc_mgr;
auto_delete_vec <event_range> m_ranges;
auto_delete_vec <per_thread_summary> m_per_thread_summary;
hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
@@ -756,6 +764,7 @@ private:
const diagnostic_thread &thread = path.get_thread (tid);
per_thread_summary *pts
= new per_thread_summary (path,
+ m_logical_loc_mgr,
thread.get_name (false),
m_per_thread_summary.length ());
m_thread_id_to_events.put (tid, pts);
@@ -792,6 +801,7 @@ path_summary::path_summary (const path_print_policy &policy,
bool check_rich_locations,
bool colorize,
bool show_event_links)
+: m_logical_loc_mgr (path.get_logical_location_manager ())
{
const unsigned num_events = path.num_events ();
@@ -872,6 +882,7 @@ public:
void
print_swimlane_for_event_range (diagnostic_text_output_format &text_output,
pretty_printer *pp,
+ const logical_location_manager &logical_loc_mgr,
event_range *range,
diagnostic_source_effect_info *effect_info)
{
@@ -916,9 +927,10 @@ public:
m_cur_indent += 5;
}
}
- if (const logical_location *logical_loc = range->m_logical_loc)
+ if (range->m_logical_loc)
{
- label_text name (logical_loc->get_name_for_path_output ());
+ label_text name
+ (logical_loc_mgr.get_name_for_path_output (range->m_logical_loc));
if (name.get ())
pp_printf (pp, "%qs: ", name.get ());
}
@@ -1113,7 +1125,9 @@ print_path_summary_as_text (const path_summary &ps,
of this range. */
diagnostic_source_effect_info effect_info;
effect_info.m_leading_in_edge_column = last_out_edge_column;
- tep.print_swimlane_for_event_range (text_output, pp, range, &effect_info);
+ tep.print_swimlane_for_event_range (text_output, pp,
+ ps.get_logical_location_manager (),
+ range, &effect_info);
last_out_edge_column = effect_info.m_trailing_out_edge_column;
}
}
@@ -1155,6 +1169,7 @@ diagnostic_text_output_format::print_path (const diagnostic_path &path)
case DPF_SEPARATE_EVENTS:
{
/* A note per event. */
+ auto &logical_loc_mgr = path.get_logical_location_manager ();
for (unsigned i = 0; i < num_events; i++)
{
const diagnostic_event &event = path.get_event (i);
@@ -1166,10 +1181,11 @@ diagnostic_text_output_format::print_path (const diagnostic_path &path)
/* -fdiagnostics-path-format=separate-events doesn't print
fndecl information, so with -fdiagnostics-show-path-depths
print the fndecls too, if any. */
- if (const logical_location *logical_loc
+ if (logical_location logical_loc
= event.get_logical_location ())
{
- label_text name (logical_loc->get_name_for_path_output ());
+ label_text name
+ (logical_loc_mgr.get_name_for_path_output (logical_loc));
inform (event.get_location (),
"%@ %e (fndecl %qs, depth %i)",
&event_id, &e_event_desc,
diff --git a/gcc/diagnostic-path.h b/gcc/diagnostic-path.h
index 878d6ff..4419139 100644
--- a/gcc/diagnostic-path.h
+++ b/gcc/diagnostic-path.h
@@ -23,7 +23,9 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG. */
#include "diagnostic-event-id.h"
+#include "logical-location.h"
+class sarif_builder;
class sarif_object;
/* A diagnostic_path is an optional additional piece of metadata associated
@@ -149,8 +151,8 @@ class diagnostic_event
/* Print a localized (and possibly colorized) description of this event. */
virtual void print_desc (pretty_printer &pp) const = 0;
- /* Get a logical_location for this event, or nullptr if there is none. */
- virtual const logical_location *get_logical_location () const = 0;
+ /* Get a logical location for this event, or null if there is none. */
+ virtual logical_location get_logical_location () const = 0;
virtual meaning get_meaning () const = 0;
@@ -163,7 +165,8 @@ class diagnostic_event
/* Hook for SARIF output to allow for adding diagnostic-specific
properties to the threadFlowLocation object's property bag. */
virtual void
- maybe_add_sarif_properties (sarif_object &/*thread_flow_loc_obj*/) const
+ maybe_add_sarif_properties (sarif_builder &,
+ sarif_object &/*thread_flow_loc_obj*/) const
{
}
@@ -203,8 +206,21 @@ class diagnostic_path
bool interprocedural_p () const;
bool multithreaded_p () const;
+ const logical_location_manager &get_logical_location_manager () const
+ {
+ return m_logical_loc_mgr;
+ }
+
+protected:
+ diagnostic_path (const logical_location_manager &logical_loc_mgr)
+ : m_logical_loc_mgr (logical_loc_mgr)
+ {
+ }
+
private:
bool get_first_event_in_a_function (unsigned *out_idx) const;
+
+ const logical_location_manager &m_logical_loc_mgr;
};
/* Concrete subclasses of the above can be found in
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index c3ea1b3..b43fc90 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -580,6 +580,14 @@ diagnostic_context::pop_urlifier ()
delete node.m_urlifier;
}
+const logical_location_manager *
+diagnostic_context::get_logical_location_manager () const
+{
+ if (!m_client_data_hooks)
+ return nullptr;
+ return m_client_data_hooks->get_logical_location_manager ();
+}
+
const urlifier *
diagnostic_context::get_urlifier () const
{
@@ -1037,14 +1045,14 @@ diagnostic_context::notes_inhibited_in_group () const
return false;
}
-/* class logical_location. */
+/* class logical_location_manager. */
/* Return true iff this is a function or method. */
bool
-logical_location::function_p () const
+logical_location_manager::function_p (key k) const
{
- switch (get_kind ())
+ switch (get_kind (k))
{
default:
gcc_unreachable ();
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 88288d0..00d7812 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -217,7 +217,7 @@ public:
class edit_context;
class diagnostic_client_data_hooks;
-class logical_location;
+class logical_location_manager;
class diagnostic_diagram;
class diagnostic_source_effect_info;
class diagnostic_output_format;
@@ -671,6 +671,9 @@ public:
return m_client_data_hooks;
}
+ const logical_location_manager *
+ get_logical_location_manager () const;
+
const urlifier *get_urlifier () const;
text_art::theme *get_diagram_theme () const { return m_diagrams.m_theme; }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 32bc457..90cbb51 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -20774,6 +20774,93 @@ By default, the dump will contain messages about successful
optimizations (equivalent to @option{-optimized}) together with
low-level details about the analysis.
+@opindex fdump-ipa-clones
+@item -fdump-ipa-clones
+
+Create a dump file containing information about creation of call graph
+node clones and removals of call graph nodes during inter-procedural
+optimizations and transformations. Its main intended use is that tools
+that create live-patches can determine the set of functions that need to
+be live-patched to completely replace a particular function (see
+@option{-flive-patching}). The file name is generated by appending
+suffix @code{ipa-clones} to the source file name, and the file is
+created in the same directory as the output file. Each entry in the
+file is on a separate line containing semicolon separated fields.
+
+In the case of call graph clone creation, the individual fields are:
+
+@enumerate
+@item
+String @code{Callgraph clone}.
+
+@item
+Name of the function being cloned as it is presented to the assembler.
+
+@item
+A number that uniquely represents the function being cloned in the call
+graph. Note that the number is unique only within a compilation unit or
+within whole-program analysis but is likely to be different in the two
+phases.
+
+@item
+The file name of the source file where the function is defined.
+
+@item
+The line on which the function definition is located.
+
+@item
+The column where the function definition is located.
+
+@item
+Name of the new function clone as it is presented to the assembler.
+
+@item
+A number that uniquely represents the new function clone in the call
+graph. Note that the number is unique only within a compilation unit or
+within whole-program analysis but is likely to be different in the two
+phases.
+
+@item
+The file name of the source file where the source code location of the
+new clone points to.
+
+@item
+The line to which the source code location of the new clone points to.
+
+@item
+The column to which the source code location of the new clone points to.
+
+@item
+A string that determines the reason for cloning.
+
+@end enumerate
+
+In the case of call graph clone removal, the individual fields are:
+
+@enumerate
+@item
+String @code{Callgraph removal}.
+
+@item
+Name of the function being removed as it would be presented to the assembler.
+
+@item
+A number that uniquely represents the function being cloned in the call
+graph. Note that the number is unique only within a compilation unit or
+within whole-program analysis but is likely to be different in the two
+phases.
+
+@item
+The file name of the source file where the function is defined.
+
+@item
+The line on which the function definition is located.
+
+@item
+The column where the function definition is located.
+
+@end enumerate
+
@opindex fdump-lang
@item -fdump-lang
Dump language-specific information. The file name is made by appending
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..184b563 100644
--- a/gcc/doc/libgdiagnostics/topics/logical-locations.rst
+++ b/gcc/doc/libgdiagnostics/topics/logical-locations.rst
@@ -51,6 +51,8 @@ source location
This roughly corresponds to the ``kind`` property in SARIF v2.1.0
(`§3.33.7 <https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790976>`_).
+ Kinds within executable code:
+
.. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION
.. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER
@@ -67,6 +69,32 @@ source location
.. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE
+ Kinds within XML or HTML documents:
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION
+
+ Kinds within JSON documents:
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY
+
+ .. macro:: DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE
+
``parent`` can be NULL; if non-NULL it can be used to express tree-like
nesting of logical locations, such as in::
@@ -113,3 +141,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/fortran/check.cc b/gcc/fortran/check.cc
index 299c216..f02a2a3 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -5955,30 +5955,40 @@ gfc_check_c_sizeof (gfc_expr *arg)
bool
gfc_check_c_associated (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2)
{
- if (c_ptr_1->ts.type != BT_DERIVED
- || c_ptr_1->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
- || (c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR
- && c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR))
+ if (c_ptr_1)
{
- gfc_error ("Argument C_PTR_1 at %L to C_ASSOCIATED shall have the "
- "type TYPE(C_PTR) or TYPE(C_FUNPTR)", &c_ptr_1->where);
- return false;
+ if (c_ptr_1->expr_type == EXPR_FUNCTION && c_ptr_1->ts.type == BT_VOID)
+ return true;
+
+ if (c_ptr_1->ts.type != BT_DERIVED
+ || c_ptr_1->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
+ || (c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR
+ && c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR))
+ {
+ gfc_error ("Argument C_PTR_1 at %L to C_ASSOCIATED shall have the "
+ "type TYPE(C_PTR) or TYPE(C_FUNPTR)", &c_ptr_1->where);
+ return false;
+ }
}
if (!scalar_check (c_ptr_1, 0))
return false;
- if (c_ptr_2
- && (c_ptr_2->ts.type != BT_DERIVED
+ if (c_ptr_2)
+ {
+ if (c_ptr_2->expr_type == EXPR_FUNCTION && c_ptr_2->ts.type == BT_VOID)
+ return true;
+
+ if (c_ptr_2->ts.type != BT_DERIVED
|| c_ptr_2->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
|| (c_ptr_1->ts.u.derived->intmod_sym_id
- != c_ptr_2->ts.u.derived->intmod_sym_id)))
- {
- gfc_error ("Argument C_PTR_2 at %L to C_ASSOCIATED shall have the "
- "same type as C_PTR_1: %s instead of %s", &c_ptr_1->where,
- gfc_typename (&c_ptr_1->ts),
- gfc_typename (&c_ptr_2->ts));
- return false;
+ != c_ptr_2->ts.u.derived->intmod_sym_id))
+ {
+ gfc_error ("Argument C_PTR_2 at %L to C_ASSOCIATED shall have the "
+ "same type as C_PTR_1: %s instead of %s", &c_ptr_1->where,
+ gfc_typename (&c_ptr_1->ts), gfc_typename (&c_ptr_2->ts));
+ return false;
+ }
}
if (c_ptr_2 && !scalar_check (c_ptr_2, 1))
diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index 1e552a3..753f589 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -1403,77 +1403,82 @@ gfc_check_dummy_characteristics (gfc_symbol *s1, gfc_symbol *s2,
}
}
- /* Check INTENT. */
- if (s1->attr.intent != s2->attr.intent && !s1->attr.artificial
- && !s2->attr.artificial)
- {
- snprintf (errmsg, err_len, "INTENT mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* A lot of information is missing for artificially generated
+ formal arguments, let's not look into that. */
- /* Check OPTIONAL attribute. */
- if (s1->attr.optional != s2->attr.optional)
+ if (!s1->attr.artificial && !s2->attr.artificial)
{
- snprintf (errmsg, err_len, "OPTIONAL mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check INTENT. */
+ if (s1->attr.intent != s2->attr.intent)
+ {
+ snprintf (errmsg, err_len, "INTENT mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check ALLOCATABLE attribute. */
- if (s1->attr.allocatable != s2->attr.allocatable)
- {
- snprintf (errmsg, err_len, "ALLOCATABLE mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check OPTIONAL attribute. */
+ if (s1->attr.optional != s2->attr.optional)
+ {
+ snprintf (errmsg, err_len, "OPTIONAL mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check POINTER attribute. */
- if (s1->attr.pointer != s2->attr.pointer)
- {
- snprintf (errmsg, err_len, "POINTER mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check ALLOCATABLE attribute. */
+ if (s1->attr.allocatable != s2->attr.allocatable)
+ {
+ snprintf (errmsg, err_len, "ALLOCATABLE mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check TARGET attribute. */
- if (s1->attr.target != s2->attr.target)
- {
- snprintf (errmsg, err_len, "TARGET mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check POINTER attribute. */
+ if (s1->attr.pointer != s2->attr.pointer)
+ {
+ snprintf (errmsg, err_len, "POINTER mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check ASYNCHRONOUS attribute. */
- if (s1->attr.asynchronous != s2->attr.asynchronous)
- {
- snprintf (errmsg, err_len, "ASYNCHRONOUS mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check TARGET attribute. */
+ if (s1->attr.target != s2->attr.target)
+ {
+ snprintf (errmsg, err_len, "TARGET mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check CONTIGUOUS attribute. */
- if (s1->attr.contiguous != s2->attr.contiguous)
- {
- snprintf (errmsg, err_len, "CONTIGUOUS mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check ASYNCHRONOUS attribute. */
+ if (s1->attr.asynchronous != s2->attr.asynchronous)
+ {
+ snprintf (errmsg, err_len, "ASYNCHRONOUS mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check VALUE attribute. */
- if (s1->attr.value != s2->attr.value)
- {
- snprintf (errmsg, err_len, "VALUE mismatch in argument '%s'",
- s1->name);
- return false;
- }
+ /* Check CONTIGUOUS attribute. */
+ if (s1->attr.contiguous != s2->attr.contiguous)
+ {
+ snprintf (errmsg, err_len, "CONTIGUOUS mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
- /* Check VOLATILE attribute. */
- if (s1->attr.volatile_ != s2->attr.volatile_)
- {
- snprintf (errmsg, err_len, "VOLATILE mismatch in argument '%s'",
- s1->name);
- return false;
+ /* Check VALUE attribute. */
+ if (s1->attr.value != s2->attr.value)
+ {
+ snprintf (errmsg, err_len, "VALUE mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
+
+ /* Check VOLATILE attribute. */
+ if (s1->attr.volatile_ != s2->attr.volatile_)
+ {
+ snprintf (errmsg, err_len, "VOLATILE mismatch in argument '%s'",
+ s1->name);
+ return false;
+ }
}
/* Check interface of dummy procedures. */
@@ -5849,6 +5854,12 @@ gfc_get_formal_from_actual_arglist (gfc_symbol *sym,
char name[GFC_MAX_SYMBOL_LEN + 1];
static int var_num;
+ /* Do not infer the formal from actual arguments if we are dealing with
+ classes. */
+
+ if (sym->ts.type == BT_CLASS)
+ return;
+
f = &sym->formal;
for (a = actual_args; a != NULL; a = a->next)
{
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 94d5a1e..5884b79 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -8334,6 +8334,8 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree truth_type,
ll_and_mask &= sign;
if (l_xor)
{
+ if (ll_bitsize != lr_bitsize)
+ return 0;
if (!lr_and_mask.get_precision ())
lr_and_mask = sign;
else
@@ -8355,6 +8357,8 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree truth_type,
rl_and_mask &= sign;
if (r_xor)
{
+ if (rl_bitsize != rr_bitsize)
+ return 0;
if (!rr_and_mask.get_precision ())
rr_and_mask = sign;
else
@@ -8762,7 +8766,7 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree truth_type,
wide_int lr_mask, rr_mask;
if (lr_and_mask.get_precision ())
lr_mask = wi::lshift (wide_int::from (lr_and_mask, rnprec, UNSIGNED),
- xlr_bitpos);
+ xlr_bitpos);
else
lr_mask = wi::shifted_mask (xlr_bitpos, lr_bitsize, false, rnprec);
if (rr_and_mask.get_precision ())
diff --git a/gcc/ipa-inline-transform.cc b/gcc/ipa-inline-transform.cc
index e00887b..46b8e5b 100644
--- a/gcc/ipa-inline-transform.cc
+++ b/gcc/ipa-inline-transform.cc
@@ -225,7 +225,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
e->count,
update_original, vNULL, true,
inlining_into,
- NULL);
+ NULL, NULL);
n->used_as_abstract_origin = e->callee->used_as_abstract_origin;
e->redirect_callee (n);
}
diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc
index 38fdbfd..35e5496 100644
--- a/gcc/ipa-inline.cc
+++ b/gcc/ipa-inline.cc
@@ -1865,7 +1865,7 @@ recursive_inlining (struct cgraph_edge *edge,
{
/* We need original clone to copy around. */
master_clone = node->create_clone (node->decl, node->count,
- false, vNULL, true, NULL, NULL);
+ false, vNULL, true, NULL, NULL, NULL);
for (e = master_clone->callees; e; e = e->next_callee)
if (!e->inline_failed)
clone_inlined_nodes (e, true, false, NULL);
diff --git a/gcc/json.cc b/gcc/json.cc
index e66a7ae..f3f3645 100644
--- a/gcc/json.cc
+++ b/gcc/json.cc
@@ -74,6 +74,52 @@ print_escaped_json_string (pretty_printer *pp,
pp_character (pp, '"');
}
+/* class pointer::token. */
+
+pointer::token::token ()
+{
+ m_parent = nullptr;
+ m_data.u_member = nullptr;
+ m_kind = kind::root_value;
+}
+
+pointer::token::token (json::object &parent, const char *member)
+{
+ m_parent = &parent;
+ m_data.u_member = xstrdup (member); // ideally we'd share
+ m_kind = kind::object_member;
+}
+
+pointer::token::token (json::array &parent, size_t index)
+{
+ m_parent = &parent;
+ m_data.u_index = index;
+ m_kind = kind::array_index;
+}
+
+pointer::token::~token ()
+{
+ if (m_kind == kind::object_member)
+ {
+ gcc_assert (m_data.u_member);
+ free (m_data.u_member);
+ }
+}
+
+pointer::token &
+pointer::token::operator= (pointer::token &&other)
+{
+ m_parent = other.m_parent;
+ m_data = other.m_data;
+ m_kind = other.m_kind;
+
+ other.m_parent = nullptr;
+ other.m_data.u_member = nullptr;
+ other.m_kind = kind::root_value;
+
+ return *this;
+}
+
/* class json::value. */
/* Dump this json::value tree to OUTF.
@@ -100,6 +146,94 @@ value::dump () const
fprintf (stderr, "\n");
}
+/* A deterministic total ordering for comparing json values, so that we
+ can e.g. put them in std::map.
+
+ This is intended to follow the condition for equality described in
+ the JSON Schema standard (§4.3, “Instance equality”), as referenced
+ by SARIF v2.1.0 (§3.7.3 "Array properties with unique values"), but has
+ the following limitations:
+ - numbers are supposed to be checked for "the same mathematical value",
+ but in this implementation int vs float numbers won't compare as equal,
+ and float number comparison is bitwise
+ - strings are supposed to be "the same codepoint-for-codepoint", but
+ this implementation doesn't take into account canonicalization issues. */
+
+int
+value::compare (const value &val_a, const value &val_b)
+{
+ enum kind kind_a = val_a.get_kind ();
+ enum kind kind_b = val_b.get_kind ();
+ if (kind_a != kind_b)
+ return (int)kind_a - (int)kind_b;
+
+ switch (kind_a)
+ {
+ default:
+ gcc_unreachable ();
+
+ case JSON_OBJECT:
+ {
+ const object &obj_a = (const object &)val_a;
+ const object &obj_b = (const object &)val_b;
+ return object::compare (obj_a, obj_b);
+ }
+ break;
+
+ case JSON_ARRAY:
+ {
+ const array &arr_a = (const array &)val_a;
+ const array &arr_b = (const array &)val_b;
+ if (int cmp_size = (int)arr_a.size () - (int)arr_b.size ())
+ return cmp_size;
+ for (size_t idx = 0; idx < arr_a.size (); ++idx)
+ if (int cmp_element = compare (*arr_a[idx], *arr_b[idx]))
+ return cmp_element;
+ return 0;
+ }
+ break;
+
+ case JSON_INTEGER:
+ {
+ const integer_number &int_a = (const integer_number &)val_a;
+ const integer_number &int_b = (const integer_number &)val_b;
+ return int_a.get () - int_b.get ();
+ }
+ break;
+
+ case JSON_FLOAT:
+ {
+ const float_number &float_a = (const float_number &)val_a;
+ const float_number &float_b = (const float_number &)val_b;
+ union u
+ {
+ double u_double;
+ char u_buf[sizeof(double)];
+ };
+ union u u_a, u_b;
+ u_a.u_double = float_a.get ();
+ u_b.u_double = float_b.get ();
+ return memcmp (&u_a, &u_b, sizeof(double));
+ }
+ break;
+
+ case JSON_STRING:
+ {
+ const string &str_a = (const string &)val_a;
+ const string &str_b = (const string &)val_b;
+ return strcmp (str_a.get_string (), str_b.get_string ());
+ }
+ break;
+
+ case JSON_TRUE:
+ case JSON_FALSE:
+ case JSON_NULL:
+ /* All instances of literals compare equal to instances
+ of the same literal. */
+ return 0;
+ }
+}
+
/* class json::object, a subclass of json::value, representing
an ordered collection of key/value pairs. */
@@ -180,6 +314,8 @@ object::set (const char *key, value *v)
m_map.put (owned_key, v);
m_keys.safe_push (owned_key);
}
+
+ v->m_pointer_token = pointer::token (*this, key);
}
/* Get the json::value * for KEY.
@@ -234,6 +370,36 @@ object::set_bool (const char *key, bool v)
set (key, new json::literal (v));
}
+/* Subroutine of json::compare for comparing a pairs of objects. */
+
+int
+object::compare (const json::object &obj_a, const json::object &obj_b)
+{
+ if (int cmp_size = (int)obj_a.m_keys.length () - (int)obj_b.m_keys.length ())
+ return cmp_size;
+
+ for (auto iter_a : obj_a.m_map)
+ {
+ const char *key = iter_a.first;
+ const value *value_a = iter_a.second;
+ gcc_assert (value_a);
+
+ const value *value_b = obj_b.get (key);
+ if (!value_b)
+ /* Key is in OBJ_A but not in OBJ_B. */
+ return 1;
+ /* If key is OBJ_B but not in OBJ_A, then the
+ count of keys will have been different, or
+ OBJ_A would have had a key not in OBJ_B. */
+ if (int cmp_value = value::compare (*value_a, *value_b))
+ /* Values for key are non-equal. */
+ return cmp_value;
+ }
+
+ /* Objects are equal. */
+ return 0;
+}
+
/* class json::array, a subclass of json::value, representing
an ordered collection of values. */
@@ -283,6 +449,7 @@ void
array::append (value *v)
{
gcc_assert (v);
+ v->m_pointer_token = pointer::token (*this, m_elements.length ());
m_elements.safe_push (v);
}
@@ -540,6 +707,213 @@ test_formatting ()
" \"int\": 1776}, \"int\": 42}"));
}
+/* Helper function for reporting failure of JSON comparisons. */
+
+static void
+fail_comparison (const location &loc,
+ const char *desc,
+ const value &val_a, const value &val_b,
+ const char *desc_expected_value,
+ int actual_value)
+{
+ fprintf (stderr, "val_a: ");
+ val_a.dump ();
+
+ fprintf (stderr, "val_b: ");
+ val_b.dump ();
+
+ selftest::fail_formatted (loc,
+ "%s: failed JSON comparison:"
+ " expected: %s got: %i\n",
+ desc,
+ desc_expected_value, actual_value);
+}
+
+/* Implementation of ASSERT_JSON_EQ. */
+
+static void
+assert_json_equal (const location &loc,
+ const char *desc,
+ const value &val_a, const value &val_b)
+{
+ /* Comparison should return zero, both ways, indicating no differences. */
+ const int a_vs_b = value::compare (val_a, val_b);
+ if (a_vs_b != 0)
+ fail_comparison (loc, desc, val_a, val_b, "zero", a_vs_b);
+
+ const int b_vs_a = value::compare (val_b, val_a);
+ if (b_vs_a != 0)
+ fail_comparison (loc, desc, val_b, val_a, "zero", b_vs_a);
+}
+
+/* Verify that json::value::compare returns 0 ("no differences") on
+ VAL1 and VAL2, in both orders. */
+
+#define ASSERT_JSON_EQ(VAL1, VAL2) \
+ SELFTEST_BEGIN_STMT \
+ assert_json_equal ((SELFTEST_LOCATION), \
+ "ASSERT_JSON_EQ", \
+ (VAL1), (VAL2)); \
+ SELFTEST_END_STMT
+
+/* Implementation of ASSERT_JSON_NE. */
+
+static void
+assert_json_non_equal (const location &loc,
+ const char *desc,
+ const value &val_a, const value &val_b)
+{
+ /* Comparison should be non-zero, indicating differences. */
+ const int a_vs_b = value::compare (val_a, val_b);
+ if (a_vs_b == 0)
+ fail_comparison (loc, desc, val_a, val_b, "non-zero", a_vs_b);
+
+ const int b_vs_a = value::compare (val_b, val_a);
+ ASSERT_NE_AT (loc, b_vs_a, 0);
+ if (b_vs_a == 0)
+ fail_comparison (loc, desc, val_b, val_a, "non-zero", b_vs_a);
+
+ /* Swapping the args should swap the sign of the result
+ (but isn't necessarily the negation). */
+ if ( (a_vs_b > 0) == (b_vs_a > 0) )
+ fail_comparison (loc, desc, val_b, val_a, "opposite signs", 1);
+}
+
+/* Verify that json::value::compare returns non-zero ("different") on
+ VAL1 and VAL2, in both orders, and that they have opposite
+ sign. */
+
+#define ASSERT_JSON_NE(VAL1, VAL2) \
+ SELFTEST_BEGIN_STMT \
+ assert_json_non_equal ((SELFTEST_LOCATION), \
+ "ASSERT_JSON_NE", \
+ (VAL1), (VAL2)); \
+ SELFTEST_END_STMT
+
+/* Verify that json::value::compare works as expected. */
+
+static void
+test_comparisons ()
+{
+ /* Literals. */
+
+ literal null_lit (JSON_NULL);
+ ASSERT_JSON_EQ (null_lit, null_lit);
+
+ literal other_null_lit (JSON_NULL);
+ ASSERT_JSON_EQ (null_lit, other_null_lit);
+
+ literal true_lit (JSON_TRUE);
+ ASSERT_JSON_EQ (true_lit, true_lit);
+ ASSERT_JSON_NE (true_lit, null_lit);
+
+ literal false_lit (JSON_FALSE);
+ ASSERT_JSON_EQ (false_lit, false_lit);
+ ASSERT_JSON_NE (false_lit, true_lit);
+ ASSERT_JSON_NE (false_lit, null_lit);
+
+ /* Strings. */
+ string str_foo_1 ("foo");
+ ASSERT_JSON_EQ (str_foo_1, str_foo_1);
+
+ string str_foo_2 ("foo");
+ ASSERT_JSON_EQ (str_foo_1, str_foo_2);
+
+ string str_bar ("bar");
+ ASSERT_JSON_NE (str_bar, str_foo_1);
+
+ /* Numbers. */
+ integer_number i_42 (42);
+ ASSERT_JSON_EQ (i_42, i_42);
+ integer_number i_42_2 (42);
+ ASSERT_JSON_EQ (i_42, i_42_2);
+ integer_number i_43 (43);
+ ASSERT_JSON_NE (i_42, i_43);
+
+ float_number f_zero (0.0);
+ ASSERT_JSON_EQ (f_zero, f_zero);
+ float_number f_zero_2 (0.0);
+ ASSERT_JSON_EQ (f_zero, f_zero_2);
+ float_number f_one (1.0);
+ ASSERT_JSON_NE (f_zero, f_one);
+ /* We don't yet test the more awkward cases e.g. NaN. */
+
+ /* Objects. */
+
+ // Empty object
+ // Self comparison should be 0
+ object empty_obj_a;
+ ASSERT_JSON_EQ (empty_obj_a, empty_obj_a);
+
+ // Instances of empty objects should compare equal to each other
+ object empty_obj_b;
+ ASSERT_JSON_EQ (empty_obj_a, empty_obj_b);
+
+ // Object with one field:
+ object obj_1;
+ obj_1.set_string ("foo", "bar");
+ // Self comparison should be 0
+ ASSERT_JSON_EQ (obj_1, obj_1);
+
+ // but should be different to an empty object:
+ ASSERT_JSON_NE (obj_1, empty_obj_a);
+
+ // Another with one field, with same key/value:
+ object obj_2;
+ obj_2.set_string ("foo", "bar");
+ ASSERT_JSON_EQ (obj_1, obj_2);
+
+ // Same key, different value:
+ object obj_3;
+ obj_3.set_string ("foo", "baz");
+ ASSERT_JSON_NE (obj_1, obj_3);
+
+ // Adding an extra property:
+ obj_2.set_integer ("year", 1066);
+ ASSERT_JSON_NE (obj_1, obj_2);
+
+ /* Different insertion order, but same k-v pairs should be equal,
+ despite having different serialization. */
+ object obj_4;
+ obj_4.set_integer ("year", 1066);
+ obj_4.set_string ("foo", "bar");
+ ASSERT_JSON_EQ (obj_2, obj_4);
+ ASSERT_PRINT_EQ (obj_2, false, "{\"foo\": \"bar\", \"year\": 1066}");
+ ASSERT_PRINT_EQ (obj_4, false, "{\"year\": 1066, \"foo\": \"bar\"}");
+
+ /* Arrays. */
+
+ // Empty array
+ array empty_arr_a;
+ // Self comparison should be 0
+ ASSERT_JSON_EQ (empty_arr_a, empty_arr_a);
+
+ // Objects and arrays are different
+ ASSERT_JSON_NE (empty_obj_a, empty_arr_a);
+
+ // Instances of empty arrays should compare equal to each other
+ array empty_arr_b;
+ ASSERT_JSON_EQ (empty_arr_a, empty_arr_b);
+
+ // Array with one element:
+ array arr_1;
+ arr_1.append (std::make_unique<string> ("foo"));
+ // Self comparison should be 0
+ ASSERT_JSON_EQ (arr_1, arr_1);
+
+ // but should be different to an empty array:
+ ASSERT_JSON_NE (arr_1, empty_arr_a);
+
+ // Another with one element:
+ array arr_2;
+ arr_2.append (std::make_unique<string> ("foo"));
+ ASSERT_JSON_EQ (arr_1, arr_2);
+
+ // Adding an extra element:
+ arr_2.append (std::make_unique<string> ("bar"));
+ ASSERT_JSON_NE (arr_1, arr_2);
+}
+
/* Run all of the selftests within this file. */
void
@@ -553,6 +927,7 @@ json_cc_tests ()
test_writing_strings ();
test_writing_literals ();
test_formatting ();
+ test_comparisons ();
}
} // namespace selftest
diff --git a/gcc/json.h b/gcc/json.h
index e369244..da4da85 100644
--- a/gcc/json.h
+++ b/gcc/json.h
@@ -73,6 +73,49 @@ enum kind
JSON_NULL
};
+namespace pointer { // json::pointer
+
+/* Implementation of JSON pointer (RFC 6901). */
+
+/* A token within a JSON pointer, expressing the parent of a particular
+ JSON value, and how it is descended from that parent.
+
+ A JSON pointer can be built as a list of these tokens. */
+
+struct token
+{
+ enum class kind
+ {
+ root_value,
+ object_member,
+ array_index
+ };
+
+ token ();
+ token (json::object &parent, const char *member);
+ token (json::array &parent, size_t index);
+ token (const token &other) = delete;
+ token (token &&other) = delete;
+
+ ~token ();
+
+ token &
+ operator= (const token &other) = delete;
+
+ token &
+ operator= (token &&other);
+
+ json::value *m_parent;
+ union u
+ {
+ char *u_member;
+ size_t u_index;
+ } m_data;
+ enum kind m_kind;
+};
+
+} // namespace json::pointer
+
/* Base class of JSON value. */
class value
@@ -84,6 +127,14 @@ class value
void dump (FILE *, bool formatted) const;
void DEBUG_FUNCTION dump () const;
+
+ virtual object *dyn_cast_object () { return nullptr; }
+
+ static int compare (const json::value &val_a, const json::value &val_b);
+
+ const pointer::token &get_pointer_token () const { return m_pointer_token; }
+
+ pointer::token m_pointer_token;
};
/* Subclass of value for objects: a collection of key/value pairs
@@ -100,6 +151,8 @@ class object : public value
enum kind get_kind () const final override { return JSON_OBJECT; }
void print (pretty_printer *pp, bool formatted) const final override;
+ object *dyn_cast_object () final override { return this; }
+
bool is_empty () const { return m_map.is_empty (); }
void set (const char *key, value *v);
@@ -127,6 +180,8 @@ class object : public value
/* Set to literal true/false. */
void set_bool (const char *key, bool v);
+ static int compare (const json::object &obj_a, const json::object &obj_b);
+
private:
typedef hash_map <char *, value *,
simple_hashmap_traits<nofree_string_hash, value *> > map_t;
diff --git a/gcc/lazy-diagnostic-path.cc b/gcc/lazy-diagnostic-path.cc
index 1474f70..37c8e25 100644
--- a/gcc/lazy-diagnostic-path.cc
+++ b/gcc/lazy-diagnostic-path.cc
@@ -91,7 +91,8 @@ class test_lazy_path : public lazy_diagnostic_path
{
public:
test_lazy_path (pretty_printer &pp)
- : m_pp (pp)
+ : lazy_diagnostic_path (m_logical_loc_mgr),
+ m_pp (pp)
{
}
std::unique_ptr<diagnostic_path> make_inner_path () const final override
@@ -99,12 +100,15 @@ public:
tree fntype_void_void
= build_function_type_array (void_type_node, 0, NULL);
tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
- auto path = std::make_unique<simple_diagnostic_path> (&m_pp);
+ auto path
+ = std::make_unique<simple_diagnostic_path> (m_logical_loc_mgr,
+ &m_pp);
path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
return path;
}
private:
+ const tree_logical_location_manager m_logical_loc_mgr;
pretty_printer &m_pp;
};
diff --git a/gcc/lazy-diagnostic-path.h b/gcc/lazy-diagnostic-path.h
index 0156456..9609cab 100644
--- a/gcc/lazy-diagnostic-path.h
+++ b/gcc/lazy-diagnostic-path.h
@@ -48,6 +48,12 @@ class lazy_diagnostic_path : public diagnostic_path
bool generated_p () const { return m_inner_path != nullptr; }
+protected:
+ lazy_diagnostic_path (const logical_location_manager &logical_loc_mgr)
+ : diagnostic_path (logical_loc_mgr)
+ {
+ }
+
private:
void lazily_generate_path () const;
virtual std::unique_ptr<diagnostic_path> make_inner_path () const = 0;
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..70b0f36 100644
--- a/gcc/libgdiagnostics.cc
+++ b/gcc/libgdiagnostics.cc
@@ -162,7 +162,7 @@ as_location_t (const diagnostic_physical_location *loc)
/* This has to be a "struct" as it is exposed in the C API. */
-struct diagnostic_logical_location : public logical_location
+struct diagnostic_logical_location
{
diagnostic_logical_location (enum diagnostic_logical_location_kind_t kind,
const diagnostic_logical_location *parent,
@@ -177,55 +177,6 @@ struct diagnostic_logical_location : public logical_location
{
}
- const char *get_short_name () const final override
- {
- return m_short_name.get_str ();
- }
- const char *get_name_with_scope () const final override
- {
- return m_fully_qualified_name.get_str ();
- }
- const char *get_internal_name () const final override
- {
- return m_decorated_name.get_str ();
- }
- enum logical_location_kind get_kind () const final override
- {
- switch (m_kind)
- {
- default:
- gcc_unreachable ();
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION:
- return LOGICAL_LOCATION_KIND_FUNCTION;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER:
- return LOGICAL_LOCATION_KIND_MEMBER;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_MODULE:
- return LOGICAL_LOCATION_KIND_MODULE;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_NAMESPACE:
- return LOGICAL_LOCATION_KIND_NAMESPACE;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_TYPE:
- return LOGICAL_LOCATION_KIND_TYPE;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_RETURN_TYPE:
- return LOGICAL_LOCATION_KIND_RETURN_TYPE;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER:
- return LOGICAL_LOCATION_KIND_PARAMETER;
- case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE:
- return LOGICAL_LOCATION_KIND_VARIABLE;
- }
- }
-
- enum diagnostic_logical_location_kind_t get_external_kind () const
- {
- return m_kind;
- }
-
- const diagnostic_logical_location *get_parent () const { return m_parent; }
-
- label_text get_name_for_path_output () const
- {
- return label_text::borrow (m_short_name.get_str ());
- }
-
bool
operator< (const diagnostic_logical_location &other) const
{
@@ -243,7 +194,6 @@ struct diagnostic_logical_location : public logical_location
return false;
}
-private:
enum diagnostic_logical_location_kind_t m_kind;
const diagnostic_logical_location *m_parent;
owned_nullable_string m_short_name;
@@ -308,6 +258,112 @@ round_alloc_size (size_t s)
return s;
}
+class impl_logical_location_manager : public logical_location_manager
+{
+public:
+ static const diagnostic_logical_location *
+ ptr_from_key (logical_location k)
+ {
+ return k.cast_to<const diagnostic_logical_location *> ();
+ }
+
+ static logical_location
+ key_from_ptr (const diagnostic_logical_location *ptr)
+ {
+ return logical_location::from_ptr (ptr);
+ }
+
+ const char *get_short_name (key k) const final override
+ {
+ if (auto loc = ptr_from_key (k))
+ return loc->m_short_name.get_str ();
+ else
+ return nullptr;
+ }
+
+ const char *get_name_with_scope (key k) const final override
+ {
+ if (auto loc = ptr_from_key (k))
+ return loc->m_fully_qualified_name.get_str ();
+ else
+ return nullptr;
+ }
+
+ const char *get_internal_name (key k) const final override
+ {
+ if (auto loc = ptr_from_key (k))
+ return loc->m_decorated_name.get_str ();
+ else
+ return nullptr;
+ }
+
+ enum logical_location_kind get_kind (key k) const final override
+ {
+ auto loc = ptr_from_key (k);
+ gcc_assert (loc);
+ switch (loc->m_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION:
+ return LOGICAL_LOCATION_KIND_FUNCTION;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER:
+ return LOGICAL_LOCATION_KIND_MEMBER;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_MODULE:
+ return LOGICAL_LOCATION_KIND_MODULE;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_NAMESPACE:
+ return LOGICAL_LOCATION_KIND_NAMESPACE;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_TYPE:
+ return LOGICAL_LOCATION_KIND_TYPE;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_RETURN_TYPE:
+ return LOGICAL_LOCATION_KIND_RETURN_TYPE;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER:
+ return LOGICAL_LOCATION_KIND_PARAMETER;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE:
+ return LOGICAL_LOCATION_KIND_VARIABLE;
+
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT:
+ return LOGICAL_LOCATION_KIND_ELEMENT;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE:
+ return LOGICAL_LOCATION_KIND_ATTRIBUTE;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT:
+ return LOGICAL_LOCATION_KIND_TEXT;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT:
+ return LOGICAL_LOCATION_KIND_COMMENT;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION:
+ return LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD:
+ return LOGICAL_LOCATION_KIND_DTD;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION:
+ return LOGICAL_LOCATION_KIND_DECLARATION;
+
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT:
+ return LOGICAL_LOCATION_KIND_OBJECT;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY:
+ return LOGICAL_LOCATION_KIND_ARRAY;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY:
+ return LOGICAL_LOCATION_KIND_PROPERTY;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE:
+ return LOGICAL_LOCATION_KIND_VALUE;
+ }
+ }
+
+ label_text get_name_for_path_output (key k) const final override
+ {
+ auto loc = ptr_from_key (k);
+ gcc_assert (loc);
+ return label_text::borrow (loc->m_short_name.get_str ());
+ }
+
+ key get_parent (key k) const final override
+ {
+ auto loc = ptr_from_key (k);
+ gcc_assert (loc);
+ return key_from_ptr (loc->m_parent);
+ }
+};
+
class impl_diagnostic_client_data_hooks : public diagnostic_client_data_hooks
{
public:
@@ -316,7 +372,14 @@ public:
{}
const client_version_info *get_any_version_info () const final override;
- const logical_location *get_current_logical_location () const final override;
+
+ const logical_location_manager *
+ get_logical_location_manager () const final override
+ {
+ return &m_logical_location_manager;
+ }
+ logical_location get_current_logical_location () const final override;
+
const char * maybe_get_sarif_source_language (const char *filename)
const final override;
void add_sarif_invocation_properties (sarif_object &invocation_obj)
@@ -324,6 +387,7 @@ public:
private:
diagnostic_manager &m_mgr;
+ impl_logical_location_manager m_logical_location_manager;
};
class impl_client_version_info : public client_version_info
@@ -424,6 +488,14 @@ public:
line_maps *get_line_table () { return &m_line_table; }
diagnostic_context &get_dc () { return m_dc; }
+ const logical_location_manager &
+ get_logical_location_manager () const
+ {
+ auto mgr = m_dc.get_logical_location_manager ();
+ gcc_assert (mgr);
+ return *mgr;
+ }
+
void write_patch (FILE *dst_stream);
void add_sink (std::unique_ptr<sink> sink)
@@ -706,9 +778,9 @@ public:
pp_string (&pp, m_desc_uncolored.get ());
}
- const logical_location *get_logical_location () const
+ logical_location get_logical_location () const final override
{
- return m_logical_loc;
+ return impl_logical_location_manager::key_from_ptr (m_logical_loc);
}
meaning get_meaning () const final override
@@ -772,8 +844,9 @@ private:
struct diagnostic_execution_path : public diagnostic_path
{
- diagnostic_execution_path ()
- : m_thread ("")
+ diagnostic_execution_path (const logical_location_manager &logical_loc_mgr)
+ : diagnostic_path (logical_loc_mgr),
+ m_thread ("")
{
}
@@ -814,9 +887,9 @@ struct diagnostic_execution_path : public diagnostic_path
same_function_p (int event_idx_a,
int event_idx_b) const final override
{
- const logical_location *logical_loc_a
+ logical_location logical_loc_a
= m_events[event_idx_a]->get_logical_location ();
- const logical_location *logical_loc_b
+ logical_location logical_loc_b
= m_events[event_idx_b]->get_logical_location ();
/* Pointer equality, as we uniqify logical location instances. */
@@ -902,7 +975,9 @@ public:
diagnostic_execution_path *
add_execution_path ()
{
- m_path = std::make_unique<diagnostic_execution_path> ();
+ m_path
+ = std::make_unique<diagnostic_execution_path>
+ (m_diag_mgr.get_logical_location_manager ());
m_rich_loc.set_path (m_path.get ());
return m_path.get ();
}
@@ -973,12 +1048,13 @@ impl_diagnostic_client_data_hooks::get_any_version_info () const
return m_mgr.get_client_version_info ();
}
-const logical_location *
+logical_location
impl_diagnostic_client_data_hooks::get_current_logical_location () const
{
gcc_assert (m_mgr.get_current_diag ());
- return m_mgr.get_current_diag ()->get_logical_location ();
+ return impl_logical_location_manager::key_from_ptr
+ (m_mgr.get_current_diag ()->get_logical_location ());
}
const char *
@@ -1046,21 +1122,57 @@ diagnostic_text_sink::text_starter (diagnostic_text_output_format &text_output,
if (diag_logical_loc && diag_logical_loc != mgr.get_prev_diag_logical_loc ())
{
pp_set_prefix (pp, nullptr);
- switch (diag_logical_loc->get_kind ())
+
+ /* This macro is used to ensure that all format strings are visible to gettext
+ and checked at compile time. */
+
+#define CASE(KIND, MSGID) \
+ case KIND: \
+ if (const char *name \
+ = diag_logical_loc->m_fully_qualified_name.get_str ()) \
+ { \
+ pp_printf (pp, (MSGID), name); \
+ pp_character (pp, ':'); \
+ pp_newline (pp); \
+ } \
+ break;
+
+ switch (diag_logical_loc->m_kind)
{
default:
break;
- case LOGICAL_LOCATION_KIND_FUNCTION:
- if (const char *name
- = diag_logical_loc->get_name_with_scope ())
- {
- pp_printf (pp, _("In function %qs"), name);
- pp_character (pp, ':');
- pp_newline (pp);
- }
- break;
- // TODO: handle other cases
+
+ /* Kinds within executable code. */
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION, _("In function %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER, _("In member %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_MODULE, _("In module %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_NAMESPACE, _("In namespace %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_TYPE, _("In type %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_RETURN_TYPE,
+ _("In return type %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER, _("In parameter %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE, _("In variable %qs"))
+
+ /* Kinds within XML or HTML documents. */
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT, _("In element %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE, _("In attribute %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT, _("In text %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT, _("In comment %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION,
+ _("In processing instruction %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD, _("In DTD %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION,
+ _("In declaration %qs"))
+
+ /* Kinds within JSON documents. */
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT, _("In JSON object %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY, _("In JSON array %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY,
+ _("In JSON property %qs"))
+ CASE(DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE, _("In JSON value %qs"))
}
+
+#undef CASE
}
pp_set_prefix (pp,
text_output.build_prefix (*info));
@@ -1130,7 +1242,9 @@ GCC_DIAGNOSTIC_POP
diagnostic_execution_path *
diagnostic_manager::new_execution_path ()
{
- return new diagnostic_execution_path ();
+ auto mgr = m_dc.get_logical_location_manager ();
+ gcc_assert (mgr);
+ return new diagnostic_execution_path (*mgr);
}
/* Error-checking at the API boundary. */
@@ -1458,10 +1572,11 @@ diagnostic_manager_debug_dump_logical_location (const diagnostic_manager *diag_m
if (loc)
{
fprintf (out, "logical_location(kind=");
- switch (loc->get_external_kind ())
+ switch (loc->m_kind)
{
default:
gcc_unreachable ();
+
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION:
fprintf (out, "function");
break;
@@ -1486,16 +1601,54 @@ diagnostic_manager_debug_dump_logical_location (const diagnostic_manager *diag_m
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE:
fprintf (out, "variable");
break;
+
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT:
+ fprintf (out, "element");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE:
+ fprintf (out, "attribute");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT:
+ fprintf (out, "text");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT:
+ fprintf (out, "comment");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION:
+ fprintf (out, "processing_instruction");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD:
+ fprintf (out, "dtd");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION:
+ fprintf (out, "declaration");
+ break;
+
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT:
+ fprintf (out, "object");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY:
+ fprintf (out, "array");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY:
+ fprintf (out, "property");
+ break;
+ case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE:
+ fprintf (out, "value");
+ break;
}
- if (const diagnostic_logical_location *parent = loc->get_parent ())
- diagnostic_manager_debug_dump_logical_location (diag_mgr,
- parent,
- out);
- if (const char *val = loc->get_short_name ())
+ if (auto parent = loc->m_parent)
+ {
+ fprintf (out, ", parent=");
+ diagnostic_manager_debug_dump_logical_location (diag_mgr,
+ parent,
+ out);
+ }
+ if (const char *val = loc->m_short_name.get_str ())
fprintf (out, ", short_name=\"%s\"", val);
- if (const char *val = loc->get_name_with_scope ())
+ if (const char *val = loc->m_fully_qualified_name.get_str ())
fprintf (out, ", fully_qualified_name=\"%s\"", val);
- if (const char *val = loc->get_internal_name ())
+ if (const char *val = loc->m_decorated_name.get_str ())
fprintf (out, ", decorated_name=\"%s\"", val);
fprintf (out, ")");
}
@@ -1788,3 +1941,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->m_kind;
+}
+
+const diagnostic_logical_location *
+diagnostic_logical_location_get_parent (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->m_parent;
+}
+
+const char *
+diagnostic_logical_location_get_short_name (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->m_short_name.get_str ();
+}
+
+const char *
+diagnostic_logical_location_get_fully_qualified_name (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->m_fully_qualified_name.get_str ();
+}
+
+const char *
+diagnostic_logical_location_get_decorated_name (const diagnostic_logical_location *loc)
+{
+ FAIL_IF_NULL (loc);
+
+ return loc->m_decorated_name.get_str ();
+}
diff --git a/gcc/libgdiagnostics.h b/gcc/libgdiagnostics.h
index 2ce0f4c..f957779 100644
--- a/gcc/libgdiagnostics.h
+++ b/gcc/libgdiagnostics.h
@@ -161,6 +161,7 @@ typedef struct diagnostic_logical_location diagnostic_logical_location;
enum diagnostic_logical_location_kind_t
{
+ /* Kinds within executable code. */
DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER,
DIAGNOSTIC_LOGICAL_LOCATION_KIND_MODULE,
@@ -168,7 +169,22 @@ enum diagnostic_logical_location_kind_t
DIAGNOSTIC_LOGICAL_LOCATION_KIND_TYPE,
DIAGNOSTIC_LOGICAL_LOCATION_KIND_RETURN_TYPE,
DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER,
- DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE,
+
+ /* Kinds within XML or HTML documents. */
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION,
+
+ /* Kinds within JSON documents. */
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE
};
/* A "diagnostic" is an opaque bundle of state for a particular
@@ -487,6 +503,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/libsarifreplay.cc b/gcc/libsarifreplay.cc
index f5f1f20..6c79762 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -106,6 +106,82 @@ make_physical_location (libgdiagnostics::manager &mgr,
return mgr.new_location_from_range (start, start, end);
}
+static enum diagnostic_logical_location_kind_t
+get_logical_location_kind_for_json_kind (enum json::kind json_kind)
+{
+ switch (json_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case json::JSON_OBJECT:
+ return DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT;
+
+ case json::JSON_ARRAY:
+ return DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY;
+
+ case json::JSON_INTEGER:
+ case json::JSON_FLOAT:
+ case json::JSON_STRING:
+ case json::JSON_TRUE:
+ case json::JSON_FALSE:
+ case json::JSON_NULL:
+ return DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY;
+ /* Perhaps this should be DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE,
+ but then we need to more carefully track context. */
+ }
+}
+
+static libgdiagnostics::logical_location
+make_logical_location_from_jv (libgdiagnostics::manager &mgr,
+ const json::value &jv)
+{
+ libgdiagnostics::logical_location parent;
+ const json::pointer::token &pointer_token = jv.get_pointer_token ();
+
+ if (pointer_token.m_parent)
+ /* Recursively ensure that we have ancestor locations. */
+ parent = make_logical_location_from_jv (mgr,
+ *jv.m_pointer_token.m_parent);
+
+ std::string short_name;
+ std::string fully_qualified_name;
+ switch (pointer_token.m_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case json::pointer::token::kind::root_value:
+ short_name = "";
+ fully_qualified_name = "";
+ break;
+
+ case json::pointer::token::kind::object_member:
+ short_name = pointer_token.m_data.u_member;
+ gcc_assert (parent.m_inner);
+ fully_qualified_name
+ = std::string (parent.get_fully_qualified_name ()) + "/" + short_name;
+ break;
+
+ case json::pointer::token::kind::array_index:
+ short_name = std::to_string (pointer_token.m_data.u_index);
+ gcc_assert (parent.m_inner);
+ fully_qualified_name
+ = std::string (parent.get_fully_qualified_name ()) + "/" + short_name;
+ break;
+ }
+
+ enum diagnostic_logical_location_kind_t kind
+ = get_logical_location_kind_for_json_kind (jv.get_kind ());
+
+ return mgr.new_logical_location (kind,
+ parent,
+ short_name.c_str (),
+ fully_qualified_name.c_str (),
+ nullptr);
+}
+
+
enum class status
{
ok,
@@ -417,6 +493,9 @@ private:
m_json_location_map.get_range_for_value (jv));
diag.set_location (loc_range);
+ diag.set_logical_location (make_logical_location_from_jv (m_control_mgr,
+ jv));
+
diag.finish_va (gmsgid, args);
}
@@ -2008,7 +2087,32 @@ handle_logical_location_object (const json::object &logical_loc_obj,
{ "parameter",
DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER },
{ "variable",
- DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE } };
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE },
+
+ { "element",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT },
+ { "attribute",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE },
+ { "text",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT },
+ { "comment",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT },
+ { "processingInstruction",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION },
+ { "dtd",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD },
+ { "declaration",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION },
+
+ { "object",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT },
+ { "array",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY },
+ { "property",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY },
+ { "value",
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE },
+ };
auto result
= get_value_from_json_string<enum diagnostic_logical_location_kind_t>
(*kind_str, kind_prop, kind_values, ARRAY_SIZE (kind_values));
diff --git a/gcc/logical-location.h b/gcc/logical-location.h
index 000335c..dba9dc4 100644
--- a/gcc/logical-location.h
+++ b/gcc/logical-location.h
@@ -33,6 +33,7 @@ enum logical_location_kind
{
LOGICAL_LOCATION_KIND_UNKNOWN,
+ /* Kinds within executable code. */
LOGICAL_LOCATION_KIND_FUNCTION,
LOGICAL_LOCATION_KIND_MEMBER,
LOGICAL_LOCATION_KIND_MODULE,
@@ -40,41 +41,135 @@ enum logical_location_kind
LOGICAL_LOCATION_KIND_TYPE,
LOGICAL_LOCATION_KIND_RETURN_TYPE,
LOGICAL_LOCATION_KIND_PARAMETER,
- LOGICAL_LOCATION_KIND_VARIABLE
+ LOGICAL_LOCATION_KIND_VARIABLE,
+
+ /* Kinds within XML or HTML documents. */
+ LOGICAL_LOCATION_KIND_ELEMENT,
+ LOGICAL_LOCATION_KIND_ATTRIBUTE,
+ LOGICAL_LOCATION_KIND_TEXT,
+ LOGICAL_LOCATION_KIND_COMMENT,
+ LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION,
+ LOGICAL_LOCATION_KIND_DTD,
+ LOGICAL_LOCATION_KIND_DECLARATION,
+
+ /* Kinds within JSON documents. */
+ LOGICAL_LOCATION_KIND_OBJECT,
+ LOGICAL_LOCATION_KIND_ARRAY,
+ LOGICAL_LOCATION_KIND_PROPERTY,
+ LOGICAL_LOCATION_KIND_VALUE
};
-/* Abstract base class for passing around logical locations in the
+/* We want to efficiently support passing around logical locations in the
diagnostics subsystem, such as:
- "within function 'foo'", or
- - "within method 'bar'",
- but *without* requiring knowledge of trees
- (see tree-logical-location.h for concrete subclasses relating to trees,
- and selftest-logical-location.h for a concrete subclass for selftests). */
+ - "within method 'bar'"
-class logical_location
+ However we want to do this *without* requiring knowledge of trees (or of
+ libgdiagnostics internals), and without requiring heap allocation of an
+ interface class when emitting a diagnostic.
+
+ To do this, we split the implementation into logical_location, which is
+ a wrapper around a (const void *), and logical_location_manager which
+ is provided by the client and has vfunc hooks for interpreting
+ logical_location instances.
+
+ Every logical_location is associated with a logical_location_manager and
+ only has meaning in relation to that manager.
+
+ A "nullptr" within a logical_location means "no logical location".
+
+ See tree-logical-location.h for concrete subclasses relating to trees,
+ where the pointer is a const_tree.
+
+ See selftest-logical-location.h for a concrete subclass for selftests. */
+
+/* Abstract base class for giving meaning to logical_location values.
+ Typically there will just be one client-provided instance, of a
+ client-specific subclass. */
+
+class logical_location_manager
{
public:
- virtual ~logical_location () {}
-
- /* Get a string (or NULL) suitable for use by the SARIF logicalLocation
+ /* Extrinsic state for identifying a specific logical location.
+ This will be our logical_location type.
+ This only makes sense with respect to a specific manager.
+ e.g. for a tree-based one it's a wrapper around "tree".
+ "nullptr" means "no logical location". */
+ class key
+ {
+ public:
+ key () : m_ptr (nullptr) {}
+
+ static key from_ptr (const void *ptr)
+ {
+ return key (ptr);
+ }
+
+ operator bool () const
+ {
+ return m_ptr != nullptr;
+ }
+
+ template <typename T>
+ T cast_to () const { return static_cast<T> (m_ptr); }
+
+ bool
+ operator== (const key &other) const
+ {
+ return m_ptr == other.m_ptr;
+ }
+
+ bool
+ operator!= (const key &other) const
+ {
+ return m_ptr != other.m_ptr;
+ }
+
+ bool
+ operator< (const key &other) const
+ {
+ return m_ptr < other.m_ptr;
+ }
+
+ private:
+ explicit key (const void *ptr) : m_ptr (ptr) {}
+
+ const void *m_ptr;
+ };
+
+ virtual ~logical_location_manager () {}
+
+ /* vfuncs for interpreting logical_location values. */
+
+ /* Get a string (or NULL) for K suitable for use by the SARIF logicalLocation
"name" property (SARIF v2.1.0 section 3.33.4). */
- virtual const char *get_short_name () const = 0;
+ virtual const char *get_short_name (key k) const = 0;
- /* Get a string (or NULL) suitable for use by the SARIF logicalLocation
+ /* Get a string (or NULL) for K suitable for use by the SARIF logicalLocation
"fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
- virtual const char *get_name_with_scope () const = 0;
+ virtual const char *get_name_with_scope (key k) const = 0;
- /* Get a string (or NULL) suitable for use by the SARIF logicalLocation
+ /* Get a string (or NULL) for K suitable for use by the SARIF logicalLocation
"decoratedName" property (SARIF v2.1.0 section 3.33.6). */
- virtual const char *get_internal_name () const = 0;
+ virtual const char *get_internal_name (key k) const = 0;
+
+ /* Get what kind of SARIF logicalLocation K is (if any). */
+ virtual enum logical_location_kind get_kind (key k) const = 0;
- /* Get what kind of SARIF logicalLocation this is (if any). */
- virtual enum logical_location_kind get_kind () const = 0;
+ /* Get a string for location K in a form suitable for path output. */
+ virtual label_text get_name_for_path_output (key k) const = 0;
- /* Get a string for this location in a form suitable for path output. */
- virtual label_text get_name_for_path_output () const = 0;
+ /* Get the parent logical_logical of K, if any, or nullptr. */
+ virtual key get_parent (key k) const = 0;
- bool function_p () const;
+ bool function_p (key k) const;
};
+/* A logical location is a key for a given logical_location_manager.
+
+ Note that there is no integration with GCC's garbage collector and thus
+ logical_location instances can't be long-lived. */
+
+typedef logical_location_manager::key logical_location;
+
#endif /* GCC_LOGICAL_LOCATION_H. */
diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc
index 8439c51..ec34f65 100644
--- a/gcc/lto-cgraph.cc
+++ b/gcc/lto-cgraph.cc
@@ -1303,7 +1303,7 @@ input_node (struct lto_file_decl_data *file_data,
{
node = dyn_cast<cgraph_node *> (nodes[clone_ref])->create_clone (fn_decl,
profile_count::uninitialized (), false,
- vNULL, false, NULL, NULL);
+ vNULL, false, NULL, NULL, NULL);
}
else
{
diff --git a/gcc/selftest-diagnostic-path.cc b/gcc/selftest-diagnostic-path.cc
index 0e80eea..04372e7 100644
--- a/gcc/selftest-diagnostic-path.cc
+++ b/gcc/selftest-diagnostic-path.cc
@@ -36,7 +36,8 @@ namespace selftest {
/* class test_diagnostic_path : public diagnostic_path. */
test_diagnostic_path::test_diagnostic_path (pretty_printer *event_pp)
-: m_event_pp (event_pp)
+: diagnostic_path (m_test_logical_loc_mgr),
+ m_event_pp (event_pp)
{
add_thread ("main");
}
@@ -75,12 +76,8 @@ bool
test_diagnostic_path::same_function_p (int event_idx_a,
int event_idx_b) const
{
- const char *name_a = m_events[event_idx_a]->get_function_name ();
- const char *name_b = m_events[event_idx_b]->get_function_name ();
-
- if (name_a && name_b)
- return 0 == strcmp (name_a, name_b);
- return name_a == name_b;
+ return (m_events[event_idx_a]->get_logical_location ()
+ == m_events[event_idx_b]->get_logical_location ());
}
diagnostic_thread_id_t
@@ -121,7 +118,10 @@ test_diagnostic_path::add_event (location_t loc,
va_end (ap);
test_diagnostic_event *new_event
- = new test_diagnostic_event (loc, funcname, depth, pp_formatted_text (pp));
+ = new test_diagnostic_event (loc,
+ logical_location_from_funcname (funcname),
+ depth,
+ pp_formatted_text (pp));
m_events.safe_push (new_event);
pp_clear_output_area (pp);
@@ -154,8 +154,11 @@ test_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
va_end (ap);
test_diagnostic_event *new_event
- = new test_diagnostic_event (loc, funcname, depth, pp_formatted_text (pp),
- thread_id);
+ = new test_diagnostic_event (loc,
+ logical_location_from_funcname (funcname),
+ depth,
+ pp_formatted_text (pp),
+ thread_id);
m_events.safe_push (new_event);
pp_clear_output_area (pp);
@@ -203,18 +206,24 @@ test_diagnostic_path::add_call (const char *caller_name,
add_entry (callee_name, caller_stack_depth + 1, thread_id);
}
+logical_location
+test_diagnostic_path::logical_location_from_funcname (const char *funcname)
+{
+ return m_test_logical_loc_mgr.logical_location_from_funcname (funcname);
+}
+
/* struct test_diagnostic_event. */
/* test_diagnostic_event's ctor. */
test_diagnostic_event::
test_diagnostic_event (location_t loc,
- const char *funcname,
- int depth,
- const char *desc,
- diagnostic_thread_id_t thread_id)
+ logical_location logical_loc,
+ int depth,
+ const char *desc,
+ diagnostic_thread_id_t thread_id)
: m_loc (loc),
- m_logical_loc (LOGICAL_LOCATION_KIND_FUNCTION, funcname),
+ m_logical_loc (logical_loc),
m_depth (depth), m_desc (xstrdup (desc)),
m_connected_to_next_event (false),
m_thread_id (thread_id)
diff --git a/gcc/selftest-diagnostic-path.h b/gcc/selftest-diagnostic-path.h
index e20986c..8829943 100644
--- a/gcc/selftest-diagnostic-path.h
+++ b/gcc/selftest-diagnostic-path.h
@@ -41,7 +41,9 @@ namespace selftest {
class test_diagnostic_event : public diagnostic_event
{
public:
- test_diagnostic_event (location_t loc, const char *funcname, int depth,
+ test_diagnostic_event (location_t loc,
+ logical_location logical_loc,
+ int depth,
const char *desc,
diagnostic_thread_id_t thread_id = 0);
~test_diagnostic_event ();
@@ -52,12 +54,9 @@ class test_diagnostic_event : public diagnostic_event
{
pp_string (&pp, m_desc);
}
- const logical_location *get_logical_location () const final override
+ logical_location get_logical_location () const final override
{
- if (m_logical_loc.get_name ())
- return &m_logical_loc;
- else
- return nullptr;
+ return m_logical_loc;
}
meaning get_meaning () const final override
{
@@ -77,14 +76,9 @@ class test_diagnostic_event : public diagnostic_event
m_connected_to_next_event = true;
}
- const char *get_function_name () const
- {
- return m_logical_loc.get_name ();
- }
-
private:
location_t m_loc;
- test_logical_location m_logical_loc;
+ logical_location m_logical_loc;
int m_depth;
char *m_desc; // has been formatted; doesn't get i18n-ed
bool m_connected_to_next_event;
@@ -149,6 +143,10 @@ class test_diagnostic_path : public diagnostic_path
diagnostic_thread_id_t thread_id = 0);
private:
+ logical_location
+ logical_location_from_funcname (const char *funcname);
+
+ test_logical_location_manager m_test_logical_loc_mgr;
auto_delete_vec<test_diagnostic_thread> m_threads;
auto_delete_vec<test_diagnostic_event> m_events;
diff --git a/gcc/selftest-diagnostic.cc b/gcc/selftest-diagnostic.cc
index 8cf47ab..1a10807 100644
--- a/gcc/selftest-diagnostic.cc
+++ b/gcc/selftest-diagnostic.cc
@@ -69,7 +69,7 @@ bool
test_diagnostic_context::report (diagnostic_t kind,
rich_location &richloc,
const diagnostic_metadata *metadata,
- int option,
+ diagnostic_option_id option,
const char * fmt, ...)
{
va_list ap;
diff --git a/gcc/selftest-diagnostic.h b/gcc/selftest-diagnostic.h
index dccad97..c8f67a0 100644
--- a/gcc/selftest-diagnostic.h
+++ b/gcc/selftest-diagnostic.h
@@ -50,7 +50,7 @@ class test_diagnostic_context : public diagnostic_context
report (diagnostic_t kind,
rich_location &richloc,
const diagnostic_metadata *metadata,
- int option,
+ diagnostic_option_id option,
const char * fmt, ...) ATTRIBUTE_GCC_DIAG(6,7);
const char *test_show_locus (rich_location &richloc);
diff --git a/gcc/selftest-logical-location.cc b/gcc/selftest-logical-location.cc
index 6c1c757..5f33b48 100644
--- a/gcc/selftest-logical-location.cc
+++ b/gcc/selftest-logical-location.cc
@@ -21,49 +21,96 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "selftest.h"
#include "selftest-logical-location.h"
#if CHECKING_P
namespace selftest {
-/* class test_logical_location : public logical_location. */
+/* class test_logical_location_manager : public logical_location_manager. */
-test_logical_location::test_logical_location (enum logical_location_kind kind,
- const char *name)
-: m_kind (kind),
- m_name (name)
+test_logical_location_manager::~test_logical_location_manager ()
{
+ for (auto iter : m_name_to_item_map)
+ delete iter.second;
}
const char *
-test_logical_location::get_short_name () const
+test_logical_location_manager::get_short_name (key k) const
{
- return m_name;
+ auto item = item_from_key (k);
+ if (!item)
+ return nullptr;
+ return item->m_name;
}
const char *
-test_logical_location::get_name_with_scope () const
+test_logical_location_manager::get_name_with_scope (key k) const
{
- return m_name;
+ auto item = item_from_key (k);
+ return item->m_name;
}
const char *
-test_logical_location::get_internal_name () const
+test_logical_location_manager::get_internal_name (key k) const
{
- return m_name;
+ auto item = item_from_key (k);
+ return item->m_name;
}
enum logical_location_kind
-test_logical_location::get_kind () const
+test_logical_location_manager::get_kind (key k) const
{
- return m_kind;
+ auto item = item_from_key (k);
+ return item->m_kind;
}
label_text
-test_logical_location::get_name_for_path_output () const
+test_logical_location_manager::get_name_for_path_output (key k) const
{
- return label_text::borrow (m_name);
+ auto item = item_from_key (k);
+ return label_text::borrow (item->m_name);
+}
+
+logical_location
+test_logical_location_manager::
+logical_location_from_funcname (const char *funcname)
+{
+ const item *i = item_from_funcname (funcname);
+ return key::from_ptr (i);
+}
+
+const test_logical_location_manager::item *
+test_logical_location_manager::item_from_funcname (const char *funcname)
+{
+ if (!funcname)
+ return nullptr;
+
+ if (item **slot = m_name_to_item_map.get (funcname))
+ return *slot;
+
+ item *i = new item (LOGICAL_LOCATION_KIND_FUNCTION, funcname);
+ m_name_to_item_map.put (funcname, i);
+ return i;
+}
+
+/* Run all of the selftests within this file. */
+
+void
+selftest_logical_location_cc_tests ()
+{
+ test_logical_location_manager mgr;
+
+ ASSERT_FALSE (mgr.logical_location_from_funcname (nullptr));
+
+ logical_location loc_foo = mgr.logical_location_from_funcname ("foo");
+ logical_location loc_bar = mgr.logical_location_from_funcname ("bar");
+
+ ASSERT_NE (loc_foo, loc_bar);
+
+ ASSERT_STREQ (mgr.get_short_name (loc_foo), "foo");
+ ASSERT_STREQ (mgr.get_short_name (loc_bar), "bar");
}
} // namespace selftest
diff --git a/gcc/selftest-logical-location.h b/gcc/selftest-logical-location.h
index dea59d8..d9bf38f 100644
--- a/gcc/selftest-logical-location.h
+++ b/gcc/selftest-logical-location.h
@@ -30,24 +30,49 @@ along with GCC; see the file COPYING3. If not see
namespace selftest {
-/* Concrete subclass of logical_location for use in selftests. */
+/* Concrete subclass of logical_location_manager for use in selftests. */
-class test_logical_location : public logical_location
+class test_logical_location_manager : public logical_location_manager
{
public:
- test_logical_location (enum logical_location_kind kind,
- const char *name);
- virtual const char *get_short_name () const final override;
- virtual const char *get_name_with_scope () const final override;
- virtual const char *get_internal_name () const final override;
- virtual enum logical_location_kind get_kind () const final override;
- virtual label_text get_name_for_path_output () const final override;
-
- const char *get_name () const { return m_name; }
-
- private:
- enum logical_location_kind m_kind;
- const char *m_name;
+ ~test_logical_location_manager ();
+
+ const char *get_short_name (key) const final override;
+ const char *get_name_with_scope (key) const final override;
+ const char *get_internal_name (key) const final override;
+ enum logical_location_kind get_kind (key) const final override;
+ label_text get_name_for_path_output (key) const final override;
+ key get_parent (key) const final override
+ {
+ return key ();
+ }
+
+ logical_location
+ logical_location_from_funcname (const char *funcname);
+
+private:
+ struct item
+ {
+ item (enum logical_location_kind kind,
+ const char *name)
+ : m_kind (kind),
+ m_name (name)
+ {
+ }
+
+ enum logical_location_kind m_kind;
+ const char *m_name;
+ };
+
+ const item *
+ item_from_funcname (const char *funcname);
+
+ static const item *item_from_key (logical_location k)
+ {
+ return k.cast_to<const item *> ();
+ }
+
+ hash_map<nofree_string_hash, item *> m_name_to_item_map;
};
} // namespace selftest
diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
index f705501..3c12e8a 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -92,6 +92,7 @@ selftest::run_tests ()
digraph_cc_tests ();
tristate_cc_tests ();
ipa_modref_tree_cc_tests ();
+ selftest_logical_location_cc_tests ();
/* Higher-level tests, or for components that other selftests don't
rely on. */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 52ee0f1..a0d2473 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -257,6 +257,7 @@ extern void read_rtl_function_cc_tests ();
extern void rtl_tests_cc_tests ();
extern void sbitmap_cc_tests ();
extern void selftest_cc_tests ();
+extern void selftest_logical_location_cc_tests ();
extern void simple_diagnostic_path_cc_tests ();
extern void simplify_rtx_cc_tests ();
extern void spellcheck_cc_tests ();
diff --git a/gcc/simple-diagnostic-path.cc b/gcc/simple-diagnostic-path.cc
index 5af69b6..b756cd5 100644
--- a/gcc/simple-diagnostic-path.cc
+++ b/gcc/simple-diagnostic-path.cc
@@ -34,8 +34,11 @@ along with GCC; see the file COPYING3. If not see
/* class simple_diagnostic_path : public diagnostic_path. */
-simple_diagnostic_path::simple_diagnostic_path (pretty_printer *event_pp)
-: m_event_pp (event_pp),
+simple_diagnostic_path::
+simple_diagnostic_path (const tree_logical_location_manager &logical_loc_mgr,
+ pretty_printer *event_pp)
+: diagnostic_path (logical_loc_mgr),
+ m_event_pp (event_pp),
m_localize_events (true)
{
add_thread ("main");
@@ -161,7 +164,8 @@ simple_diagnostic_event (location_t loc,
int depth,
const char *desc,
diagnostic_thread_id_t thread_id)
-: m_loc (loc), m_fndecl (fndecl), m_logical_loc (fndecl),
+: m_loc (loc), m_fndecl (fndecl),
+ m_logical_loc (tree_logical_location_manager::key_from_tree (fndecl)),
m_depth (depth), m_desc (xstrdup (desc)),
m_connected_to_next_event (false),
m_thread_id (thread_id)
@@ -188,11 +192,12 @@ namespace selftest {
static void
test_intraprocedural_path (pretty_printer *event_pp)
{
+ tree_logical_location_manager mgr;
tree fntype_void_void
= build_function_type_array (void_type_node, 0, NULL);
tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
- simple_diagnostic_path path (event_pp);
+ simple_diagnostic_path path (mgr, event_pp);
path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
diff --git a/gcc/simple-diagnostic-path.h b/gcc/simple-diagnostic-path.h
index e9a97f2..d2b366e 100644
--- a/gcc/simple-diagnostic-path.h
+++ b/gcc/simple-diagnostic-path.h
@@ -40,12 +40,9 @@ class simple_diagnostic_event : public diagnostic_event
location_t get_location () const final override { return m_loc; }
int get_stack_depth () const final override { return m_depth; }
void print_desc (pretty_printer &pp) const final override;
- const logical_location *get_logical_location () const final override
+ logical_location get_logical_location () const final override
{
- if (m_fndecl)
- return &m_logical_loc;
- else
- return nullptr;
+ return tree_logical_location_manager::key_from_tree (m_fndecl);
}
meaning get_meaning () const final override
{
@@ -70,7 +67,7 @@ class simple_diagnostic_event : public diagnostic_event
private:
location_t m_loc;
tree m_fndecl;
- tree_logical_location m_logical_loc;
+ logical_location m_logical_loc;
int m_depth;
char *m_desc; // has been i18n-ed and formatted
bool m_connected_to_next_event;
@@ -98,7 +95,8 @@ private:
class simple_diagnostic_path : public diagnostic_path
{
public:
- simple_diagnostic_path (pretty_printer *event_pp);
+ simple_diagnostic_path (const tree_logical_location_manager &logical_loc_mgr,
+ pretty_printer *event_pp);
unsigned num_events () const final override { return m_events.length (); }
const diagnostic_event & get_event (int idx) const final override;
diff --git a/gcc/testsuite/g++.dg/sarif-output/logical-locations-1.C b/gcc/testsuite/g++.dg/sarif-output/logical-locations-1.C
new file mode 100644
index 0000000..75ad3b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/logical-locations-1.C
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=sarif-file" } */
+
+/* Verify that we can capture the chain of parents of a
+ logical location (PR 116176). */
+
+namespace ns {
+ class foo
+ {
+ void bar ()
+ {
+ return 0;
+ }
+ };
+}
+
+/* We expect a failing compile due to the error, but the use of
+ -fdiagnostics-format=sarif-file means there should be no output to stderr.
+ DejaGnu injects this message; ignore it:
+ { dg-prune-output "exit status is 1" } */
+
+/* Verify that some JSON was written to a file with the expected name:
+ { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest logical-locations-1.C "logical-locations-1.py" } } */
diff --git a/gcc/testsuite/g++.dg/sarif-output/logical-locations-1.py b/gcc/testsuite/g++.dg/sarif-output/logical-locations-1.py
new file mode 100644
index 0000000..954f6df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/logical-locations-1.py
@@ -0,0 +1,79 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+expected_filename = 'logical-locations-1.C'
+
+def test_result(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+ results = run['results']
+
+ # The textual form of the diagnostic would look like this:
+ # . PATH/logical-locations-1.C: In member function ‘void ns::foo::bar()’:
+ # . PATH/logical-locations-1.C:12:14: error: return-statement with a value, in function returning ‘void’ [-fpermissive]
+ # . 12 | return 0;
+ # . | ^
+ assert len(results) == 1
+
+ result = results[0]
+ assert result['ruleId'] == '-fpermissive'
+ assert result['level'] == 'error'
+ assert result['message']['text'] \
+ == "return-statement with a value, in function returning 'void'"
+
+ locations = result['locations']
+ assert len(locations) == 1
+
+ location = locations[0]
+ assert get_location_artifact_uri(location).endswith(expected_filename)
+ assert get_location_snippet_text(location) == ' return 0;\n'
+
+def test_logical_locations(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ # We expect 3 logical locations within the run:
+ assert len(run['logicalLocations']) == 3
+
+ assert run['logicalLocations'][0] \
+ == {"name": "ns",
+ "fullyQualifiedName": "ns",
+ "kind": "namespace",
+ "index": 0}
+ assert run['logicalLocations'][1] \
+ == {"name": "foo",
+ # Ideally we'd also have:
+ # "fullyQualifiedName": "ns::foo",
+ "kind": "type",
+ "parentIndex": 0,
+ "index": 1}
+ assert run['logicalLocations'][2] \
+ == {"name": "bar",
+ "fullyQualifiedName": "ns::foo::bar",
+ "decoratedName": "_ZN2ns3foo3barEv",
+ "kind": "function",
+ "parentIndex": 1,
+ "index": 2}
+
+ results = run['results']
+
+ assert len(results) == 1
+
+ result = results[0]
+
+ locations = result['locations']
+ assert len(locations) == 1
+
+ location = locations[0]
+
+ # We expect one logical location within the result, referencing
+ # one in the run
+ assert len(location['logicalLocations']) == 1
+ assert location['logicalLocations'][0] \
+ == {'fullyQualifiedName': 'ns::foo::bar',
+ 'index': 2}
diff --git a/gcc/testsuite/g++.dg/sarif-output/logical-locations-2.C b/gcc/testsuite/g++.dg/sarif-output/logical-locations-2.C
new file mode 100644
index 0000000..67aa4c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/logical-locations-2.C
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=sarif-file" } */
+
+/* Verify that we correctly consolidate logical locations
+ involving repeated diagnostics within a nested hierarchy
+ (PR 116176). */
+
+namespace ns_outer {
+ namespace ns_inner_1 {
+ class klass_1
+ {
+ void member_fn_1 ()
+ {
+ return 0;
+ }
+ void member_fn_2 ()
+ {
+ return 0;
+ }
+ };
+ class klass_2
+ {
+ void member_fn_1 ()
+ {
+ return 0;
+ }
+ void member_fn_2 ()
+ {
+ return 0;
+ }
+ };
+ } // ns_inner_1
+ namespace ns_inner_2 {
+ class klass_1
+ {
+ void member_fn_1 ()
+ {
+ return 0;
+ }
+ void member_fn_2 ()
+ {
+ return 0;
+ }
+ };
+ class klass_2
+ {
+ void member_fn_1 ()
+ {
+ return 0;
+ }
+ void member_fn_2 ()
+ {
+ return 0;
+ }
+ };
+ } // ns_inner_2
+} // ns_outer
+
+/* We expect a failing compile due to the error, but the use of
+ -fdiagnostics-format=sarif-file means there should be no output to stderr.
+ DejaGnu injects this message; ignore it:
+ { dg-prune-output "exit status is 1" } */
+
+/* Verify that some JSON was written to a file with the expected name:
+ { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest logical-locations-2.C "logical-locations-2.py" } } */
diff --git a/gcc/testsuite/g++.dg/sarif-output/logical-locations-2.py b/gcc/testsuite/g++.dg/sarif-output/logical-locations-2.py
new file mode 100644
index 0000000..e34531b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/logical-locations-2.py
@@ -0,0 +1,90 @@
+from sarif import *
+from pprint import pprint
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+expected_filename = 'logical-locations-2.C'
+
+def test_logical_locations(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ # We expect 15 logical locations within the run expressing
+ # a logical hierarchy, and 8 results with one logical locations
+ # in each, referencing back into the run.
+
+ # Generate the "gold" output we expect.
+ expected_in_run = []
+ expected_in_results = []
+
+ outer_ns_index_in_run = len(expected_in_run)
+ expected_in_run += [{"name": "ns_outer",
+ "fullyQualifiedName": "ns_outer",
+ "kind": "namespace",
+ "index": outer_ns_index_in_run}]
+
+ for inner_ns in ['ns_inner_1', 'ns_inner_2']:
+ inner_ns_idx_in_run = len(expected_in_run)
+ expected_in_run += [{"name": inner_ns,
+ "fullyQualifiedName": f"ns_outer::{inner_ns}",
+ "kind": "namespace",
+ "index": inner_ns_idx_in_run,
+ "parentIndex": 0}]
+ for klass in ['klass_1', 'klass_2']:
+ klass_idx_in_run = len(expected_in_run)
+ expected_in_run += [{"name": klass,
+ "kind": "type",
+ "index": klass_idx_in_run,
+ "parentIndex": inner_ns_idx_in_run}]
+ for member_fn in ['member_fn_1', 'member_fn_2']:
+ fqn = f'ns_outer::{inner_ns}::{klass}::{member_fn}'
+ member_fn_idx_in_run = len(expected_in_run)
+ expected_in_run += [{"name": member_fn,
+ "kind": "function",
+ "fullyQualifiedName": f"ns_outer::{inner_ns}::{klass}::{member_fn}",
+ "decoratedName": f"_ZN8ns_outer10{inner_ns}7{klass}11{member_fn}Ev",
+ "index": member_fn_idx_in_run,
+ "parentIndex": klass_idx_in_run}]
+ expected_in_results += [{'fullyQualifiedName': fqn,
+ 'index': member_fn_idx_in_run}]
+
+ pprint(expected_in_run)
+ pprint(expected_in_results)
+ assert len(expected_in_run) == 15
+ assert len(expected_in_results) == 8
+
+ # We expect 15 logical locations within the run:
+ assert len(run['logicalLocations']) == len(expected_in_run)
+ for actual, expected in zip(run['logicalLocations'], expected_in_run):
+ assert actual == expected
+
+ # We expect 8 results with one logical location in each
+ results = run['results']
+ assert len(results) == len(expected_in_results)
+
+ index = 0
+ for inner_ns in ['ns_inner_1', 'ns_inner_2']:
+ for klass in ['klass_1', 'klass_2']:
+ for member_fn in ['member_fn_1', 'member_fn_2']:
+ result = results[index]
+ assert result['ruleId'] == '-fpermissive'
+ assert result['level'] == 'error'
+ assert result['message']['text'] \
+ == "return-statement with a value, in function returning 'void'"
+
+ locations = result['locations']
+ assert len(locations) == 1
+
+ location = locations[0]
+
+ # We expect one logical location within the result, referencing
+ # one in the run
+ assert len(location['logicalLocations']) == 1
+ assert location['logicalLocations'][0] \
+ == expected_in_results[index]
+
+ index += 1
diff --git a/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.C b/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.C
new file mode 100644
index 0000000..59ed84a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.C
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=sarif-file" } */
+
+/* Verify that we handle deeply nested logical locations
+ (PR 116176). */
+
+#define NS_OPEN(SUFFIX) namespace ns_##SUFFIX {
+#define NS_CLOSE }
+
+#define NS_OPEN_10(SUFFIX) \
+ NS_OPEN(SUFFIX##0) \
+ NS_OPEN(SUFFIX##1) \
+ NS_OPEN(SUFFIX##2) \
+ NS_OPEN(SUFFIX##3) \
+ NS_OPEN(SUFFIX##4) \
+ NS_OPEN(SUFFIX##5) \
+ NS_OPEN(SUFFIX##6) \
+ NS_OPEN(SUFFIX##7) \
+ NS_OPEN(SUFFIX##8) \
+ NS_OPEN(SUFFIX##9)
+
+#define NS_CLOSE_10 \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE \
+ NS_CLOSE
+
+#define NS_OPEN_100(SUFFIX) \
+ NS_OPEN_10(SUFFIX##0) \
+ NS_OPEN_10(SUFFIX##1) \
+ NS_OPEN_10(SUFFIX##2) \
+ NS_OPEN_10(SUFFIX##3) \
+ NS_OPEN_10(SUFFIX##4) \
+ NS_OPEN_10(SUFFIX##5) \
+ NS_OPEN_10(SUFFIX##6) \
+ NS_OPEN_10(SUFFIX##7) \
+ NS_OPEN_10(SUFFIX##8) \
+ NS_OPEN_10(SUFFIX##9)
+
+#define NS_CLOSE_100 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10 \
+ NS_CLOSE_10
+
+#define NS_OPEN_200 \
+ NS_OPEN_100(a) \
+ NS_OPEN_100(b)
+
+#define NS_CLOSE_200 \
+ NS_CLOSE_100 \
+ NS_CLOSE_100
+
+NS_OPEN_200
+
+void return_from_void ()
+{
+ return 0;
+}
+
+NS_CLOSE_200
+
+/* We expect a failing compile due to the error, but the use of
+ -fdiagnostics-format=sarif-file means there should be no output to stderr.
+ DejaGnu injects this message; ignore it:
+ { dg-prune-output "exit status is 1" } */
+
+/* Verify that some JSON was written to a file with the expected name:
+ { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest logical-locations-3.C "logical-locations-3.py" } } */
diff --git a/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.py b/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.py
new file mode 100644
index 0000000..199299c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.py
@@ -0,0 +1,61 @@
+from sarif import *
+from pprint import pprint
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+expected_filename = 'logical-locations-3.C'
+
+def test_logical_locations(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ # We expect a single error with this very long logical location:
+ # ../../src/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.C: In function ‘void ns_a00::ns_a01::ns_a02::ns_a03::ns_a04::ns_a05::ns_a06::ns_a07::ns_a08::ns_a09::ns_a10::ns_a11::ns_a12::ns_a13::ns_a14::ns_a15::ns_a16::ns_a17::ns_a18::ns_a19::ns_a20::ns_a21::ns_a22::ns_a23::ns_a24::ns_a25::ns_a26::ns_a27::ns_a28::ns_a29::ns_a30::ns_a31::ns_a32::ns_a33::ns_a34::ns_a35::ns_a36::ns_a37::ns_a38::ns_a39::ns_a40::ns_a41::ns_a42::ns_a43::ns_a44::ns_a45::ns_a46::ns_a47::ns_a48::ns_a49::ns_a50::ns_a51::ns_a52::ns_a53::ns_a54::ns_a55::ns_a56::ns_a57::ns_a58::ns_a59::ns_a60::ns_a61::ns_a62::ns_a63::ns_a64::ns_a65::ns_a66::ns_a67::ns_a68::ns_a69::ns_a70::ns_a71::ns_a72::ns_a73::ns_a74::ns_a75::ns_a76::ns_a77::ns_a78::ns_a79::ns_a80::ns_a81::ns_a82::ns_a83::ns_a84::ns_a85::ns_a86::ns_a87::ns_a88::ns_a89::ns_a90::ns_a91::ns_a92::ns_a93::ns_a94::ns_a95::ns_a96::ns_a97::ns_a98::ns_a99::ns_b00::ns_b01::ns_b02::ns_b03::ns_b04::ns_b05::ns_b06::ns_b07::ns_b08::ns_b09::ns_b10::ns_b11::ns_b12::ns_b13::ns_b14::ns_b15::ns_b16::ns_b17::ns_b18::ns_b19::ns_b20::ns_b21::ns_b22::ns_b23::ns_b24::ns_b25::ns_b26::ns_b27::ns_b28::ns_b29::ns_b30::ns_b31::ns_b32::ns_b33::ns_b34::ns_b35::ns_b36::ns_b37::ns_b38::ns_b39::ns_b40::ns_b41::ns_b42::ns_b43::ns_b44::ns_b45::ns_b46::ns_b47::ns_b48::ns_b49::ns_b50::ns_b51::ns_b52::ns_b53::ns_b54::ns_b55::ns_b56::ns_b57::ns_b58::ns_b59::ns_b60::ns_b61::ns_b62::ns_b63::ns_b64::ns_b65::ns_b66::ns_b67::ns_b68::ns_b69::ns_b70::ns_b71::ns_b72::ns_b73::ns_b74::ns_b75::ns_b76::ns_b77::ns_b78::ns_b79::ns_b80::ns_b81::ns_b82::ns_b83::ns_b84::ns_b85::ns_b86::ns_b87::ns_b88::ns_b89::ns_b90::ns_b91::ns_b92::ns_b93::ns_b94::ns_b95::ns_b96::ns_b97::ns_b98::ns_b99::return_from_void()’:
+ # ../../src/gcc/testsuite/g++.dg/sarif-output/logical-locations-3.C:70:10: error: return-statement with a value, in function returning ‘void’ [-fpermissive]
+ # 70 | return 0;
+ # | ^
+
+ # We expect 201 logical locations within the run expressing
+ # the logical hierarchy: the 200 nested namespaces, and then
+ # the function within the innermost namespace.
+ assert len(run['logicalLocations']) == 201
+
+ outermost = run['logicalLocations'][0]
+ assert outermost == {'fullyQualifiedName': 'ns_a00',
+ 'index': 0,
+ 'kind': 'namespace',
+ 'name': 'ns_a00'}
+
+ for i in range(1, 200):
+ ns_i = run['logicalLocations'][i]
+ assert ns_i['index'] == i
+ assert ns_i['kind'] == 'namespace'
+ assert ns_i['parentIndex'] == i - 1
+ expected_name = 'ns_' + 'ab'[i // 100] + '%02i' % (i % 100)
+ assert ns_i['name'] == expected_name
+ assert ns_i['fullyQualifiedName'] \
+ == run['logicalLocations'][i - 1]['fullyQualifiedName'] + "::" + expected_name
+
+ innermost = run['logicalLocations'][200]
+ assert innermost['index'] == 200
+ assert innermost['kind'] == 'function'
+ assert innermost['name'] == 'return_from_void'
+ assert innermost['parentIndex'] == 199
+ assert innermost['fullyQualifiedName'] \
+ == run['logicalLocations'][199]['fullyQualifiedName'] + '::return_from_void'
+
+ # We expect 1 error in the run, referring to the innermost
+ # logical location by index within the run's logical locations
+ results = run['results']
+ assert len(results) == 1
+ result = results[0]
+ assert len(result['locations']) == 1
+ assert len(result['locations'][0]['logicalLocations']) == 1
+ assert result['locations'][0]['logicalLocations'][0]['index'] \
+ == innermost['index']
+ assert result['locations'][0]['logicalLocations'][0]['fullyQualifiedName'] \
+ == innermost['fullyQualifiedName']
diff --git a/gcc/testsuite/g++.dg/sarif-output/sarif-output.exp b/gcc/testsuite/g++.dg/sarif-output/sarif-output.exp
new file mode 100644
index 0000000..20b2845
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sarif-output/sarif-output.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2012-2025 Free Software Foundation, Inc.
+#
+# 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib g++-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" ""
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/ipa/pr119852.c b/gcc/testsuite/gcc.dg/ipa/pr119852.c
new file mode 100644
index 0000000..eab8d212
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr119852.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-clones" } */
+
+typedef struct rtx_def *rtx;
+enum rtx_code {
+ LAST_AND_UNUSED_RTX_CODE};
+extern const char * const rtx_format[((int) LAST_AND_UNUSED_RTX_CODE)];
+struct rtx_def {
+ enum rtx_code code;
+};
+typedef int (*rtx_function) (rtx *, void *);
+extern int for_each_rtx (rtx *, rtx_function, void *);
+int
+replace_label (rtx *x, void *data)
+{
+ rtx l = *x;
+ if (l == (rtx) 0)
+ {
+ {
+ rtx new_c, new_l;
+ for_each_rtx (&new_c, replace_label, data);
+ }
+ }
+}
+static int
+for_each_rtx_1 (rtx exp, int n, rtx_function f, void *data)
+{
+ int result, i, j;
+ const char *format = (rtx_format[(int) (((enum rtx_code) (exp)->code))]);
+ rtx *x;
+ for (; format[n] != '\0'; n++)
+ {
+ switch (format[n])
+ {
+ case 'e':
+ result = (*f) (x, data);
+ {
+ result = for_each_rtx_1 (*x, i, f, data);
+ }
+ }
+ }
+}
+int
+for_each_rtx (rtx *x, rtx_function f, void *data)
+{
+ int i;
+ return for_each_rtx_1 (*x, i, f, data);
+}
+
+/* { dg-final { scan-ipa-dump-not "(null)" "ipa-clones" } } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc
index 954538f..a7963fa 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc
@@ -147,7 +147,9 @@ example_1 ()
{
auto_diagnostic_group d;
gcc_rich_location richloc (gimple_location (call_to_PyList_Append));
- simple_diagnostic_path path (global_dc->get_reference_printer ());
+ tree_logical_location_manager logical_loc_mgr;
+ simple_diagnostic_path path (logical_loc_mgr,
+ global_dc->get_reference_printer ());
diagnostic_event_id_t alloc_event_id
= path.add_event (gimple_location (call_to_PyList_New),
example_a_fun->decl, 0,
@@ -214,7 +216,8 @@ class test_diagnostic_path : public simple_diagnostic_path
{
public:
test_diagnostic_path (pretty_printer *event_pp)
- : simple_diagnostic_path (event_pp)
+ : simple_diagnostic_path (m_logical_loc_mgr,
+ event_pp)
{
}
diagnostic_event_id_t
@@ -262,6 +265,9 @@ class test_diagnostic_path : public simple_diagnostic_path
add_event (call_evloc.m_loc, call_evloc.m_fun->decl, caller_stack_depth,
"calling %qs", callee);
}
+
+private:
+ tree_logical_location_manager m_logical_loc_mgr;
};
static void
diff --git a/gcc/testsuite/gcc.dg/pr120074.c b/gcc/testsuite/gcc.dg/pr120074.c
new file mode 100644
index 0000000..3f31516
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr120074.c
@@ -0,0 +1,20 @@
+/* PR tree-optimization/120074 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fno-tree-copy-prop -fno-tree-forwprop -fno-tree-ccp" } */
+
+int foo (int);
+short a;
+int b;
+
+int
+bar (int d, int e)
+{
+ return d < 0 || d > __INT_MAX__ >> e;
+}
+
+int
+main ()
+{
+ int f = bar ((b ^ a) & 3, __SIZEOF_INT__ * __CHAR_BIT__ - 2);
+ foo (f);
+}
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr115777.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr115777.c
new file mode 100644
index 0000000..bba0dc7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr115777.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+
+typedef unsigned int T;
+
+#define SWAP(A, B) do { T tmp = A; A = B; B = tmp; } while (0)
+
+void
+insertion_sort(T *v, int n)
+{
+ for (int i = 1; i < n; ++i)
+ for (int k = i; k > 0 && v[k-1] > v[k]; --k)
+ SWAP(v[k-1], v[k]);
+}
+
+/* { dg-final { scan-tree-dump "using element-wise load" "slp1" { target { { x86_64-*-* i?86-*-* } && { ! ia32 } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/pr114512.c b/gcc/testsuite/gcc.target/riscv/pr114512.c
new file mode 100644
index 0000000..205071c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr114512.c
@@ -0,0 +1,109 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gcb -mabi=ilp32" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+/* We need to adjust the constant so this works for rv32 and rv64. */
+#if __riscv_xlen == 32
+#define ONE 1U
+#define MASK 0x1f
+typedef unsigned int utype;
+#else
+#define ONE 1ULL
+#define MASK 0x3f
+typedef unsigned long utype;
+#endif
+
+
+_Bool my_isxdigit_1(unsigned char ch) {
+ utype mask1 = 0x03FF007E;
+ if (!((mask1 >> (ch & MASK)) & 1))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_1a(unsigned char ch) {
+ utype mask2 = 0x58;
+ if (!((mask2 >> (ch >> 4)) & 1))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_2(unsigned char ch) {
+ utype mask1 = 0x03FF007E;
+ if (!(mask1 & (ONE << (ch & MASK))))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_2a(unsigned char ch) {
+ utype mask2 = 0x58;
+ if (!(mask2 & (ONE << (ch >> 4))))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_3(unsigned char ch) {
+ utype mask1 = 0x7E00FFC0;
+ if (!((mask1 << (MASK - (ch & MASK))) >> MASK))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_3a(unsigned char ch) {
+ utype mask2 = 0x7E00FFC0;
+ if (!((mask2 << (MASK - ((ch >> 4) & MASK))) >> MASK))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_1_parm(unsigned char ch, utype mask1) {
+ if (!((mask1 >> (ch & MASK)) & 1))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_1a_parm(unsigned char ch, utype mask2) {
+ if (!((mask2 >> (ch >> 4)) & 1))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_2_parm(unsigned char ch, utype mask1) {
+ if (!(mask1 & (ONE << (ch & MASK))))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_2a_parm(unsigned char ch, utype mask2) {
+ if (!(mask2 & (ONE << (ch >> 4))))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_3_parm(unsigned char ch, utype mask1) {
+ if (!((mask1 << (MASK - (ch & MASK))) >> MASK))
+ return 0;
+
+ return 1;
+}
+
+_Bool my_isxdigit_3a_parm(unsigned char ch, utype mask2) {
+ if (!((mask2 << (MASK - ((ch >> 4) & MASK))) >> MASK))
+ return 0;
+
+ return 1;
+}
+
+/* Each test should generate a single bext. */
+/* { dg-final { scan-assembler-times "bext\t" 12 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h
new file mode 100644
index 0000000..66654eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h
@@ -0,0 +1,17 @@
+#ifndef HAVE_DEFINED_VX_VF_BINARY_H
+#define HAVE_DEFINED_VX_VF_BINARY_H
+
+#include <stdint.h>
+
+#define DEF_VX_BINARY(T, OP) \
+void \
+test_vx_binary (T * restrict out, T * restrict in, T x, unsigned n) \
+{ \
+ for (unsigned i = 0; i < n; i++) \
+ out[i] = in[i] OP x; \
+}
+#define DEF_VX_BINARY_WRAP(T, OP) DEF_VX_BINARY(T, OP)
+#define RUN_VX_BINARY(out, in, x, n) test_vx_binary(out, in, x, n)
+#define RUN_VX_BINARY_WRAP(out, in, x, n) RUN_VX_BINARY(out, in, x, n)
+
+#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h
new file mode 100644
index 0000000..11a32cb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h
@@ -0,0 +1,401 @@
+#ifndef HAVE_DEFINED_VX_BINARY_DATA_H
+#define HAVE_DEFINED_VX_BINARY_DATA_H
+
+#define N 16
+
+#define TEST_BINARY_DATA(T, NAME) test_##T##_##NAME##_data
+#define TEST_BINARY_DATA_WRAP(T, NAME) TEST_BINARY_DATA(T, NAME)
+
+int8_t TEST_BINARY_DATA(int8_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ },
+ },
+ {
+ { 127 },
+ {
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ -128, -128, -128, -128,
+ -2, -2, -2, -2,
+ },
+ {
+ 127, 127, 127, 127,
+ 126, 126, 126, 126,
+ -1, -1, -1, -1,
+ 125, 125, 125, 125,
+ },
+ },
+ {
+ { -128 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 127, 127, 127, 127,
+ 2, 2, 2, 2,
+ },
+ {
+ -128, -128, -128, -128,
+ -127, -127, -127, -127,
+ -1, -1, -1, -1,
+ -126, -126, -126, -126,
+ },
+ },
+};
+
+int16_t TEST_BINARY_DATA(int16_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ },
+ },
+ {
+ { 32767 },
+ {
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ -32768, -32768, -32768, -32768,
+ -2, -2, -2, -2,
+ },
+ {
+ 32767, 32767, 32767, 32767,
+ 32766, 32766, 32766, 32766,
+ -1, -1, -1, -1,
+ 32765, 32765, 32765, 32765,
+ },
+ },
+ {
+ { -32768 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 32767, 32767, 32767, 32767,
+ 2, 2, 2, 2,
+ },
+ {
+ -32768, -32768, -32768, -32768,
+ -32767, -32767, -32767, -32767,
+ -1, -1, -1, -1,
+ -32766, -32766, -32766, -32766,
+ },
+ },
+};
+
+int32_t TEST_BINARY_DATA(int32_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ },
+ },
+ {
+ { 2147483647 },
+ {
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ -2, -2, -2, -2,
+ },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2147483646, 2147483646, 2147483646, 2147483646,
+ -1, -1, -1, -1,
+ 2147483645, 2147483645, 2147483645, 2147483645,
+ },
+ },
+ {
+ { -2147483648 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2, 2, 2, 2,
+ },
+ {
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ -2147483647, -2147483647, -2147483647, -2147483647,
+ -1, -1, -1, -1,
+ -2147483646, -2147483646, -2147483646, -2147483646,
+ },
+ },
+};
+
+int64_t TEST_BINARY_DATA(int64_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ },
+ },
+ {
+ { 9223372036854775807ll },
+ {
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ -2, -2, -2, -2,
+ },
+ {
+ 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll,
+ 9223372036854775806ll, 9223372036854775806ll, 9223372036854775806ll, 9223372036854775806ll,
+ -1, -1, -1, -1,
+ 9223372036854775805ll, 9223372036854775805ll, 9223372036854775805ll, 9223372036854775805ll,
+ },
+ },
+ {
+ { -9223372036854775808ull },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll,
+ 2, 2, 2, 2,
+ },
+ {
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ -9223372036854775807ll, -9223372036854775807ll, -9223372036854775807ll, -9223372036854775807ll,
+ -1, -1, -1, -1,
+ -9223372036854775806ll, -9223372036854775806ll, -9223372036854775806ll, -9223372036854775806ll,
+ },
+ },
+};
+
+uint8_t TEST_BINARY_DATA(uint8_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 11, 11, 11, 11,
+ 9, 9, 9, 9,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 12, 12, 12, 12,
+ 10, 10, 10, 10,
+ },
+ },
+ {
+ { 127 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 127, 127, 127, 127,
+ 128, 128, 128, 128,
+ },
+ {
+ 127, 127, 127, 127,
+ 128, 128, 128, 128,
+ 254, 254, 254, 254,
+ 255, 255, 255, 255,
+ },
+ },
+ {
+ { 253 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 255, 255, 255, 255,
+ },
+ {
+ 253, 253, 253, 253,
+ 254, 254, 254, 254,
+ 255, 255, 255, 255,
+ 252, 252, 252, 252,
+ },
+ },
+};
+
+uint16_t TEST_BINARY_DATA(uint16_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 11, 11, 11, 11,
+ 9, 9, 9, 9,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 12, 12, 12, 12,
+ 10, 10, 10, 10,
+ },
+ },
+ {
+ { 32767 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 32767, 32767, 32767, 32767,
+ 32768, 32768, 32768, 32768,
+ },
+ {
+ 32767, 32767, 32767, 32767,
+ 32768, 32768, 32768, 32768,
+ 65534, 65534, 65534, 65534,
+ 65535, 65535, 65535, 65535,
+ },
+ },
+ {
+ { 65533 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 65535, 65535, 65535, 65535,
+ },
+ {
+ 65533, 65533, 65533, 65533,
+ 65534, 65534, 65534, 65534,
+ 65535, 65535, 65535, 65535,
+ 65532, 65532, 65532, 65532,
+ },
+ },
+};
+
+uint32_t TEST_BINARY_DATA(uint32_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 11, 11, 11, 11,
+ 9, 9, 9, 9,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 12, 12, 12, 12,
+ 10, 10, 10, 10,
+ },
+ },
+ {
+ { 2147483647 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2147483648, 2147483648, 2147483648, 2147483648,
+ },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2147483648, 2147483648, 2147483648, 2147483648,
+ 4294967294, 4294967294, 4294967294, 4294967294,
+ 4294967295, 4294967295, 4294967295, 4294967295,
+ },
+ },
+ {
+ { 4294967293 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 4294967295, 4294967295, 4294967295, 4294967295,
+ },
+ {
+ 4294967293, 4294967293, 4294967293, 4294967293,
+ 4294967294, 4294967294, 4294967294, 4294967294,
+ 4294967295, 4294967295, 4294967295, 4294967295,
+ 4294967292, 4294967292, 4294967292, 4294967292,
+ },
+ },
+};
+
+uint64_t TEST_BINARY_DATA(uint64_t, vadd)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 11, 11, 11, 11,
+ 9, 9, 9, 9,
+ },
+ {
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 12, 12, 12, 12,
+ 10, 10, 10, 10,
+ },
+ },
+ {
+ { 9223372036854775807ull },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull,
+ },
+ {
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull,
+ 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull,
+ 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull,
+ },
+ },
+ {
+ { 18446744073709551613ull },
+ {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull,
+ },
+ {
+ 18446744073709551613ull, 18446744073709551613ull, 18446744073709551613ull, 18446744073709551613ull,
+ 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull,
+ 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull,
+ 18446744073709551612ull, 18446744073709551612ull, 18446744073709551612ull, 18446744073709551612ull,
+ },
+ },
+};
+
+#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_run.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_run.h
new file mode 100644
index 0000000..bb35184
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_run.h
@@ -0,0 +1,26 @@
+#ifndef HAVE_DEFINED_VX_BINARY_RUN_H
+#define HAVE_DEFINED_VX_BINARY_RUN_H
+
+int
+main ()
+{
+ unsigned i, k;
+ T out[N];
+
+ for (i = 0; i < sizeof (TEST_DATA) / sizeof (TEST_DATA[0]); i++)
+ {
+ T x = TEST_DATA[i][0][0];
+ T *in = TEST_DATA[i][1];
+ T *expect = TEST_DATA[i][2];
+
+ TEST_RUN (out, in, x, N);
+
+ for (k = 0; k < N; k++)
+ if (out[k] != expect[k])
+ __builtin_abort ();
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i16.c
new file mode 100644
index 0000000..488bc75
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i16.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int16_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i32.c
new file mode 100644
index 0000000..aeba835
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i32.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int32_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i64.c
new file mode 100644
index 0000000..ed0b937
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i64.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int64_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i8.c
new file mode 100644
index 0000000..781d3c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-i8.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int8_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u16.c
new file mode 100644
index 0000000..c01fc23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u16.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint16_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u32.c
new file mode 100644
index 0000000..63198492
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u32.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint32_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u64.c
new file mode 100644
index 0000000..36eec53
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u64.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint64_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u8.c
new file mode 100644
index 0000000..6bf4b61
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-1-u8.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint8_t, +)
+
+/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i16.c
new file mode 100644
index 0000000..eb19938
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i16.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int16_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i32.c
new file mode 100644
index 0000000..24182c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i32.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int32_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i64.c
new file mode 100644
index 0000000..b3d3d4b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i64.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int64_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i8.c
new file mode 100644
index 0000000..fb35315
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-i8.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int8_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u16.c
new file mode 100644
index 0000000..6ba2658
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u16.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint16_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u32.c
new file mode 100644
index 0000000..b60412c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u32.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint32_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u64.c
new file mode 100644
index 0000000..a273294
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u64.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint64_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u8.c
new file mode 100644
index 0000000..f3c41f9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-2-u8.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=1" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint8_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i16.c
new file mode 100644
index 0000000..f3a2627
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i16.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int16_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i32.c
new file mode 100644
index 0000000..490854c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i32.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int32_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i64.c
new file mode 100644
index 0000000..a7448df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i64.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int64_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i8.c
new file mode 100644
index 0000000..72c7cd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-i8.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(int8_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u16.c
new file mode 100644
index 0000000..552b4ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u16.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint16_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u32.c
new file mode 100644
index 0000000..e319672
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u32.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint32_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u64.c
new file mode 100644
index 0000000..6e2a89e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u64.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint64_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u8.c
new file mode 100644
index 0000000..d3383e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-3-u8.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=gpr2vr-cost=15" } */
+
+#include "vx_binary.h"
+
+DEF_VX_BINARY(uint8_t, +)
+
+/* { dg-final { scan-assembler-not {vadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i16.c
new file mode 100644
index 0000000..fb5375d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i16.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int16_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i32.c
new file mode 100644
index 0000000..c2c79f5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i32.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int32_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i64.c
new file mode 100644
index 0000000..541ed21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i64.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int64_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i8.c
new file mode 100644
index 0000000..d507bbb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-i8.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int8_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u16.c
new file mode 100644
index 0000000..52c0749
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u16.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint16_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u32.c
new file mode 100644
index 0000000..70dc347
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u32.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint32_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u64.c
new file mode 100644
index 0000000..6ce0060
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u64.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint64_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u8.c
new file mode 100644
index 0000000..a0e80b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vadd-run-1-u8.c
@@ -0,0 +1,14 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint8_t
+
+DEF_VX_BINARY_WRAP(T, +)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, vadd)
+#define TEST_RUN(out, in, x, n) RUN_VX_BINARY_WRAP(out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 3824997..4283d12 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -130,6 +130,8 @@ foreach op $AUTOVEC_TEST_OPTS {
"$op" ""
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/sat/*.\[cS\]]] \
"$op" ""
+ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/vx_vf/*.\[cS\]]] \
+ "$op" ""
}
# All done.
diff --git a/gcc/testsuite/gfortran.dg/interface_60.f90 b/gcc/testsuite/gfortran.dg/interface_60.f90
new file mode 100644
index 0000000..a7701f6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/interface_60.f90
@@ -0,0 +1,70 @@
+! { dg-do run }
+! { dg-options "-Wexternal-argument-mismatch" }
+! Originally proc_ptr_52.f90, this gave an error with the warning above.
+
+module cs
+
+implicit none
+
+integer, target :: integer_target
+
+abstract interface
+ function classStar_map_ifc(x) result(y)
+ class(*), pointer :: y
+ class(*), target, intent(in) :: x
+ end function classStar_map_ifc
+end interface
+
+contains
+
+ function fun(x) result(y)
+ class(*), pointer :: y
+ class(*), target, intent(in) :: x
+ select type (x)
+ type is (integer)
+ integer_target = x ! Deals with dangling target.
+ y => integer_target
+ class default
+ y => null()
+ end select
+ end function fun
+
+ function apply(fap, x) result(y)
+ procedure(classStar_map_ifc) :: fap
+ integer, intent(in) :: x
+ integer :: y
+ class(*), pointer :: p
+ y = 0 ! Get rid of 'y' undefined warning
+ p => fap (x)
+ select type (p)
+ type is (integer)
+ y = p
+ end select
+ end function apply
+
+ function selector() result(fsel)
+ procedure(classStar_map_ifc), pointer :: fsel
+ fsel => fun
+ end function selector
+
+end module cs
+
+
+program classStar_map
+
+use cs
+implicit none
+
+integer :: x, y
+procedure(classStar_map_ifc), pointer :: fm
+
+x = 123654
+fm => selector () ! Fixed by second chunk in patch
+y = apply (fm, x) ! Fixed by first chunk in patch
+if (x .ne. y) stop 1
+
+x = 2 * x
+y = apply (fun, x) ! PR93925; fixed as above
+if (x .ne. y) stop 2
+
+end program classStar_map
diff --git a/gcc/testsuite/gfortran.dg/pr120049_a.f90 b/gcc/testsuite/gfortran.dg/pr120049_a.f90
new file mode 100644
index 0000000..c404a4d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr120049_a.f90
@@ -0,0 +1,15 @@
+! { dg-do preprocess }
+! { dg-additional-options "-cpp" }
+!
+! Test the fix for PR86248
+program tests_gtk_sup
+ use gtk_sup
+ implicit none
+ type(c_ptr), target :: val
+ if (c_associated(val, c_loc(val))) then
+ stop 1
+ endif
+ if (c_associated(c_loc(val), val)) then
+ stop 2
+ endif
+end program tests_gtk_sup
diff --git a/gcc/testsuite/gfortran.dg/pr120049_b.f90 b/gcc/testsuite/gfortran.dg/pr120049_b.f90
new file mode 100644
index 0000000..127db98
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr120049_b.f90
@@ -0,0 +1,8 @@
+! { dg-do run }
+! { dg-additional-sources pr120049_a.f90 }
+!
+! Module for pr120049.f90
+!
+module gtk_sup
+ use, intrinsic :: iso_c_binding
+end module gtk_sup
diff --git a/gcc/testsuite/libgdiagnostics.dg/test-logical-location-c.py b/gcc/testsuite/libgdiagnostics.dg/test-logical-location-c.py
index 7448a1e..55f338b 100644
--- a/gcc/testsuite/libgdiagnostics.dg/test-logical-location-c.py
+++ b/gcc/testsuite/libgdiagnostics.dg/test-logical-location-c.py
@@ -31,7 +31,16 @@ def test_sarif_output_with_logical_location(sarif):
assert len(location['logicalLocations']) == 1
logical_loc = location['logicalLocations'][0]
+ assert logical_loc['index'] == 0
+ assert logical_loc['fullyQualifiedName'] == 'test_qualified_name'
+
+ # Check theRun.logicalLocations
+ assert 'logicalLocations' in run
+ assert len(run['logicalLocations']) == 1
+ logical_loc = run['logicalLocations'][0]
assert logical_loc['name'] == 'test_short_name'
assert logical_loc['fullyQualifiedName'] == 'test_qualified_name'
assert logical_loc['decoratedName'] == 'test_decorated_name'
assert logical_loc['kind'] == 'function'
+ assert logical_loc['index'] == 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 "" } */
diff --git a/gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json-c.py b/gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json-c.py
new file mode 100644
index 0000000..39cc1a9
--- /dev/null
+++ b/gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json-c.py
@@ -0,0 +1,79 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_sarif_output_with_logical_location(sarif):
+ schema = sarif['$schema']
+ assert schema == 'https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json'
+
+ version = sarif['version']
+ assert version == '2.1.0'
+
+ runs = sarif['runs']
+ run = runs[0]
+
+ tool = run['tool']
+ assert tool['driver']['name'] == 'test-nested-logical-locations-json.c.exe'
+
+ results = run['results']
+ assert len(results) == 2
+
+ result = results[0]
+ assert result['ruleId'] == 'warning'
+ assert result['level'] == 'warning'
+ assert result['message']['text'] == "product ID is blank"
+ assert len(result['locations']) == 1
+ location = result['locations'][0]
+ assert len(location['logicalLocations']) == 1
+ logical_loc = location['logicalLocations'][0]
+ assert logical_loc['index'] == 3
+ assert logical_loc['fullyQualifiedName'] == '/orders/0/productIds/1'
+
+ result = results[1]
+ assert result['ruleId'] == 'warning'
+ assert result['level'] == 'warning'
+ assert result['message']['text'] == "value is negative"
+ assert len(result['locations']) == 1
+ location = result['locations'][0]
+ assert len(location['logicalLocations']) == 1
+ logical_loc = location['logicalLocations'][0]
+ assert logical_loc['index'] == 4
+ assert logical_loc['fullyQualifiedName'] == '/orders/0/total'
+
+ # Check theRun.logicalLocations
+ assert 'logicalLocations' in run
+ assert len(run['logicalLocations']) == 5
+ logical_loc = run['logicalLocations'][0]
+ assert logical_loc['name'] == 'orders'
+ assert logical_loc['fullyQualifiedName'] == '/orders'
+ assert logical_loc['kind'] == 'array'
+ assert logical_loc['index'] == 0
+ logical_loc = run['logicalLocations'][1]
+ assert logical_loc['name'] == '0'
+ assert logical_loc['fullyQualifiedName'] == '/orders/0'
+ assert logical_loc['kind'] == 'object'
+ assert logical_loc['parentIndex'] == 0
+ assert logical_loc['index'] == 1
+ logical_loc = run['logicalLocations'][2]
+ assert logical_loc['name'] == 'productIds'
+ assert logical_loc['fullyQualifiedName'] == '/orders/0/productIds'
+ assert logical_loc['kind'] == 'array'
+ assert logical_loc['parentIndex'] == 1
+ assert logical_loc['index'] == 2
+ logical_loc = run['logicalLocations'][3]
+ assert logical_loc['name'] == '1'
+ assert logical_loc['fullyQualifiedName'] == '/orders/0/productIds/1'
+ assert logical_loc['kind'] == 'value'
+ assert logical_loc['parentIndex'] == 2
+ assert logical_loc['index'] == 3
+ logical_loc = run['logicalLocations'][4]
+ assert logical_loc['name'] == 'total'
+ assert logical_loc['fullyQualifiedName'] == '/orders/0/total'
+ assert logical_loc['kind'] == 'property'
+ assert logical_loc['parentIndex'] == 1
+ assert logical_loc['index'] == 4
+
diff --git a/gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json.c b/gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json.c
new file mode 100644
index 0000000..d06450e
--- /dev/null
+++ b/gcc/testsuite/libgdiagnostics.dg/test-nested-logical-locations-json.c
@@ -0,0 +1,165 @@
+/* Example of nested logical locations, based on the JSON example in
+ SARIF v2.1.0, 3.33.7 "kind" property;
+ though see https://github.com/oasis-tcs/sarif-spec/issues/670
+
+ Intended output is similar to:
+
+In JSON value '/orders/0/productIds/1':
+PATH/test-nested-logical-locations-json.c:28:32: warning: product ID is blank
+ 28 | "productIds": [ "A-101", "", "A-223" ],
+ | ^~
+In JSON property '/orders/0/total':
+PATH/test-nested-logical-locations-json.c:29:16: warning: value is negative
+ 29 | "total": "-3.25"
+ | ^~~~~~~
+
+ along with the equivalent in SARIF, capturing JSON structure
+ as nested logical locations. */
+
+#include "libgdiagnostics.h"
+#include "test-helpers.h"
+
+/* Placeholder source:
+_________1111111111222222222233333333334444444444
+1234567890123456789012345678901234567890123456789
+{
+ "orders": [
+ {
+ "productIds": [ "A-101", "", "A-223" ],
+ "total": "-3.25"
+ }
+ ]
+}
+*/
+const int start_line_num = __LINE__ - 9;
+const int line_num_of_product_ids = start_line_num + 3;
+const int line_num_of_total = line_num_of_product_ids + 1;
+
+#include <assert.h>
+
+int
+main ()
+{
+ begin_test ("test-nested-logical-locations-json.c.exe",
+ "test-nested-logical-locations-json.c.sarif",
+ __FILE__, "c");
+
+ /* Create tree of logical locations. */
+ /* begin quoted source */
+ const diagnostic_logical_location *logical_loc_orders_arr
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY,
+ NULL, /* parent */
+ "orders",
+ "/orders",
+ NULL);
+ const diagnostic_logical_location *logical_loc_order_0
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT,
+ logical_loc_orders_arr, /* parent */
+ "0",
+ "/orders/0",
+ NULL);
+ const diagnostic_logical_location *logical_loc_product_ids
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY,
+ logical_loc_order_0, /* parent */
+ "productIds",
+ "/orders/0/productIds",
+ NULL);
+ const diagnostic_logical_location *logical_loc_element_1
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE,
+ logical_loc_product_ids, /* parent */
+ "1",
+ "/orders/0/productIds/1",
+ NULL);
+ const diagnostic_logical_location *logical_loc_total
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY,
+ logical_loc_order_0, /* parent */
+ "total",
+ "/orders/0/total",
+ NULL);
+ /* end quoted source */
+
+ {
+ const int line_num = line_num_of_product_ids;
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr,
+ main_file,
+ line_num,
+ 32);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr,
+ main_file,
+ line_num,
+ 33);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_WARNING);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_set_logical_location (d, logical_loc_element_1);
+
+ diagnostic_finish (d, "product ID is blank");
+ }
+ {
+ const int line_num = line_num_of_total;
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr,
+ main_file,
+ line_num,
+ 16);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr,
+ main_file,
+ line_num,
+ 22);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_WARNING);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_set_logical_location (d, logical_loc_total);
+
+ diagnostic_finish (d, "value is negative");
+ }
+
+ return end_test ();
+}
+
+/* Check the output from the text sink. */
+/* { dg-begin-multiline-output "" }
+In JSON value '/orders/0/productIds/1':
+ { dg-end-multiline-output "" } */
+/* { dg-regexp "\[^\n\r\]+test-nested-logical-locations-json.c:28:32: warning: product ID is blank" } */
+/* { dg-begin-multiline-output "" }
+ 28 | "productIds": [ "A-101", "", "A-223" ],
+ | ^~
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+In JSON property '/orders/0/total':
+ { dg-end-multiline-output "" } */
+/* { dg-regexp "\[^\n\r\]+test-nested-logical-locations-json.c:29:16: warning: value is negative" } */
+/* { dg-begin-multiline-output "" }
+ 29 | "total": "-3.25"
+ | ^~~~~~~
+ { dg-end-multiline-output "" } */
+
+/* Verify that some JSON was written to a file with the expected name:
+ { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest test-nested-logical-locations-json.c "test-nested-logical-locations-json-c.py" } } */
diff --git a/gcc/testsuite/libgdiagnostics.dg/test-warning-with-path-c.py b/gcc/testsuite/libgdiagnostics.dg/test-warning-with-path-c.py
index 5d3bbc4..af1e7b9 100644
--- a/gcc/testsuite/libgdiagnostics.dg/test-warning-with-path-c.py
+++ b/gcc/testsuite/libgdiagnostics.dg/test-warning-with-path-c.py
@@ -51,10 +51,8 @@ def test_sarif_output_for_warning_with_path(sarif):
assert len(location['logicalLocations']) == 1
logical_loc = location['logicalLocations'][0]
- assert logical_loc['name'] == 'make_a_list_of_random_ints_badly'
+ assert logical_loc['index'] == 0
assert logical_loc['fullyQualifiedName'] == 'make_a_list_of_random_ints_badly'
- assert logical_loc['decoratedName'] == 'make_a_list_of_random_ints_badly'
- assert logical_loc['kind'] == 'function'
assert len(result['codeFlows']) == 1
assert len(result['codeFlows'][0]['threadFlows']) == 1
@@ -106,3 +104,13 @@ def test_sarif_output_for_warning_with_path(sarif):
== "when calling 'PyList_Append', passing NULL from (1) as argument 1"
assert tfl_2['nestingLevel'] == 0
assert tfl_2['executionOrder'] == 3
+
+ # Check theRun.logicalLocations
+ assert 'logicalLocations' in run
+ assert len(run['logicalLocations']) == 1
+ logical_loc = run['logicalLocations'][0]
+ assert logical_loc['name'] == 'make_a_list_of_random_ints_badly'
+ assert logical_loc['fullyQualifiedName'] == 'make_a_list_of_random_ints_badly'
+ assert logical_loc['decoratedName'] == 'make_a_list_of_random_ints_badly'
+ assert logical_loc['kind'] == 'function'
+ assert logical_loc['index'] == 0
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.1-not-an-object.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.1-not-an-object.sarif
index 4743bad..9f0b87b 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.1-not-an-object.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.1-not-an-object.sarif
@@ -1,6 +1,9 @@
[ null ] // { dg-error "expected a sarifLog object as the top-level value \\\[SARIF v2.1.0 §3.1\\\]" }
/* { dg-begin-multiline-output "" }
+In JSON array '':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
1 | [ null ]
| ^~~~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-missing-arguments-for-placeholders.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-missing-arguments-for-placeholders.sarif
index c4354d4..be2316a 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-missing-arguments-for-placeholders.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-missing-arguments-for-placeholders.sarif
@@ -9,6 +9,9 @@
}
/* { dg-begin-multiline-output "" }
+In JSON object '/runs/0/results/0/message':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
6 | { "message": { "text" : "the {0} {1} fox jumps over the {2} dog" } }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-not-enough-arguments-for-placeholders.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-not-enough-arguments-for-placeholders.sarif
index e3eb534..98c3dc9 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-not-enough-arguments-for-placeholders.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.11-not-enough-arguments-for-placeholders.sarif
@@ -9,6 +9,9 @@
}
/* { dg-begin-multiline-output "" }
+In JSON object '/runs/0/results/0/message':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
6 | { "message": { "text" : "the {0} {1} fox jumps over the {2} dog", "arguments": ["quick", "brown"] } }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.5-unescaped-braces.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.5-unescaped-braces.sarif
index 29460e1..f816859 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.5-unescaped-braces.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.11.5-unescaped-braces.sarif
@@ -10,6 +10,9 @@
}
/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/message/text':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
6 | { "message": { "text" : "before {} after" },
| ^~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-no-version.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-no-version.sarif
index 771bd9c..d290604 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-no-version.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-no-version.sarif
@@ -1,6 +1,9 @@
{ } // { dg-error "expected sarifLog object to have a 'version' property \\\[SARIF v2.1.0 §3.13.2\\\]" }
/* { dg-begin-multiline-output "" }
+In JSON object '':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
1 | { }
| ^~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-version-not-a-string.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-version-not-a-string.sarif
index 87bfd0d..c83be50 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-version-not-a-string.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.2-version-not-a-string.sarif
@@ -1,6 +1,9 @@
{ "version" : 42 } // { dg-error "15: expected sarifLog.version to be a JSON string; got JSON number \\\[SARIF v2.1.0 §3.13.2\\\]" }
/* { dg-begin-multiline-output "" }
+In JSON property '/version':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
1 | { "version" : 42 }
| ^~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-bad-runs.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-bad-runs.sarif
index c5a26f0..202698e 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-bad-runs.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-bad-runs.sarif
@@ -2,6 +2,9 @@
"runs": 42 } // { dg-error "expected sarifLog.runs to be 'null' or an array \\\[SARIF v2.1.0 §3.13.4\\\]" }
/* { dg-begin-multiline-output "" }
+In JSON property '/runs':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
2 | "runs": 42 }
| ^~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-no-runs.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-no-runs.sarif
index f142321..a4870c1 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-no-runs.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-no-runs.sarif
@@ -1,6 +1,9 @@
{ "version": "2.1.0" } // { dg-error "expected sarifLog object to have a 'runs' property \\\[SARIF v2.1.0 §3.13.4\\\]" }
/* { dg-begin-multiline-output "" }
+In JSON object '':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
1 | { "version": "2.1.0" }
| ^~~~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-non-object-in-runs.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-non-object-in-runs.sarif
index 4eeaaaa..b870959 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-non-object-in-runs.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.13.4-non-object-in-runs.sarif
@@ -2,6 +2,9 @@
"runs" : [42] } // { dg-error "expected element of sarifLog.runs array to be an object \\\[SARIF v2.1.0 §3.13.4\\\]" }
/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
2 | "runs" : [42] }
| ^~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.27.10-bad-level.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.27.10-bad-level.sarif
index b5c3fbe..eb60b66 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.27.10-bad-level.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.27.10-bad-level.sarif
@@ -20,6 +20,9 @@
}
/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/level':
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
12 | "level": "mostly harmless",
| ^~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.33.3-index-out-of-range.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.33.3-index-out-of-range.sarif
index ef22614..d7baac9 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.33.3-index-out-of-range.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-invalid/3.33.3-index-out-of-range.sarif
@@ -27,6 +27,9 @@
}
/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/locations/0/logicalLocations/0/index'
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
17 | "index": 42
| ^~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-unhandled/3.27.10-none-level.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-unhandled/3.27.10-none-level.sarif
index 7f58677..20552a3 100644
--- a/gcc/testsuite/sarif-replay.dg/2.1.0-unhandled/3.27.10-none-level.sarif
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-unhandled/3.27.10-none-level.sarif
@@ -20,6 +20,9 @@
}
/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/level'
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
12 | "level": "none",
| ^~~~~~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-json-example.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-json-example.sarif
new file mode 100644
index 0000000..6e4cf5b
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-json-example.sarif
@@ -0,0 +1,83 @@
+/* Adapted from the JSON example in SARIF v2.1.0, 3.33.7 "kind" property;
+ see https://github.com/oasis-tcs/sarif-spec/issues/670 */
+{
+ "version": "2.1.0",
+ "runs": [
+ {
+ "tool": {
+ "driver": {
+ "name": "example JSON scanner"
+ }
+ },
+ "results": [
+ {
+ "message": {"text": "product ID is blank"},
+ "locations": [
+ {
+ "logicalLocations": [
+ {
+ "fullyQualifiedName": "/orders/0/productIds/1",
+ "index": 3
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "message": {"text": "value is negative"},
+ "locations": [
+ {
+ "logicalLocations": [
+ {
+ "fullyQualifiedName": "/orders/0/total",
+ "index": 4
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "logicalLocations": [
+ {
+ "name": "orders",
+ "fullyQualifiedName": "/orders",
+ "kind": "array"
+ },
+ {
+ "name": "0",
+ "fullyQualifiedName": "/orders/0",
+ "kind": "object",
+ "parentIndex": 0
+ },
+ {
+ "name": "productIds",
+ "fullyQualifiedName": "/orders/0/productIds",
+ "kind": "array",
+ "parentIndex": 1
+ },
+ {
+ "name": "1",
+ "fullyQualifiedName": "/orders/0/productIds/1",
+ "kind": "value",
+ "parentIndex": 2
+ },
+ {
+ "name": "total",
+ "fullyQualifiedName": "/orders/0/total",
+ "kind": "property",
+ "parentIndex": 1
+ }
+ ]
+ }
+ ]
+}
+
+/* { dg-begin-multiline-output "" }
+In JSON value '/orders/0/productIds/1':
+example JSON scanner: warning: product ID is blank
+ { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+In JSON property '/orders/0/total':
+example JSON scanner: warning: value is negative
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-xml-example.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-xml-example.sarif
new file mode 100644
index 0000000..36afc65
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.33.7-xml-example.sarif
@@ -0,0 +1,77 @@
+/* Adapted from the XML example in SARIF v2.1.0, 3.33.7 "kind" property;
+ see also https://github.com/oasis-tcs/sarif-spec/issues/669 */
+{
+ "version": "2.1.0",
+ "runs": [
+ {
+ "tool": {
+ "driver": {
+ "name": "example XML scanner"
+ }
+ },
+ "results": [
+ {
+ "message": {"text": "empty value"},
+ "locations": [
+ {
+ "logicalLocations": [
+ {
+ "fullyQualifiedName": "/orders/order[1]/@number",
+ "index": 2
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "message": {"text": "total is negative"},
+ "locations": [
+ {
+ "logicalLocations": [
+ {
+ "fullyQualifiedName": "/orders/order[1]/total/text()",
+ "index": 3
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "logicalLocations": [
+ {
+ "name": "orders",
+ "fullyQualifiedName": "/orders",
+ "kind": "element"
+ },
+ {
+ "name": "order[1]",
+ "fullyQualifiedName": "/orders/order[1]",
+ "kind": "element",
+ "parentIndex": 0
+ },
+ {
+ "name": "number",
+ "fullyQualifiedName": "/orders/order[1]/@number",
+ "kind": "attribute",
+ "parentIndex": 1
+ },
+ {
+ "name": "text",
+ "fullyQualifiedName": "/orders/order[1]/total/text()",
+ "kind": "text",
+ "parentIndex": 1
+ }
+ ]
+ }
+ ]
+}
+
+/* { dg-begin-multiline-output "" }
+In attribute '/orders/order[1]/@number':
+example XML scanner: warning: empty value
+ { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+In text '/orders/order[1]/total/text()':
+example XML scanner: warning: total is negative
+ { dg-end-multiline-output "" } */
diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc
index 11701f5..06a0894 100644
--- a/gcc/tree-diagnostic-client-data-hooks.cc
+++ b/gcc/tree-diagnostic-client-data-hooks.cc
@@ -123,12 +123,14 @@ public:
return &m_version_info;
}
- const logical_location *get_current_logical_location () const final override
+ const logical_location_manager *get_logical_location_manager () const final override
{
- if (current_function_decl)
- return &m_current_fndecl_logical_loc;
- else
- return NULL;
+ return &m_logical_location_manager;
+ }
+
+ logical_location_manager::key get_current_logical_location () const final override
+ {
+ return m_logical_location_manager.key_from_tree (current_function_decl);
}
const char *
@@ -159,7 +161,7 @@ public:
private:
compiler_version_info m_version_info;
- current_fndecl_logical_location m_current_fndecl_logical_loc;
+ tree_logical_location_manager m_logical_location_manager;
};
/* Create a compiler_data_hooks (so that the class can be local
diff --git a/gcc/tree-logical-location.cc b/gcc/tree-logical-location.cc
index 8f677a3..1b2702f 100644
--- a/gcc/tree-logical-location.cc
+++ b/gcc/tree-logical-location.cc
@@ -1,4 +1,4 @@
-/* Subclasses of logical_location with knowledge of "tree".
+/* Subclass of logical_location_manager with knowledge of "tree".
Copyright (C) 2022-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -27,50 +27,67 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "intl.h"
-/* class compiler_logical_location : public logical_location. */
+static void
+assert_valid_tree (const_tree node)
+{
+ gcc_assert (node);
+ gcc_assert (DECL_P (node) || TYPE_P (node));
+ gcc_assert (TREE_CODE (node) != TRANSLATION_UNIT_DECL);
+}
-/* Get a string for DECL suitable for use by the SARIF logicalLocation
- "name" property (SARIF v2.1.0 section 3.33.4). */
+/* class tree_logical_location_manager : public logical_location_manager. */
const char *
-compiler_logical_location::get_short_name_for_tree (tree decl)
+tree_logical_location_manager::get_short_name (key k) const
{
- gcc_assert (decl);
- return identifier_to_locale (lang_hooks.decl_printable_name (decl, 0));
+ tree node = tree_from_key (k);
+ assert_valid_tree (node);
+
+ if (DECL_P (node))
+ return identifier_to_locale (lang_hooks.decl_printable_name (node, 0));
+ if (TYPE_P (node))
+ return IDENTIFIER_POINTER (TYPE_IDENTIFIER (node));
+ return nullptr;
}
-/* Get a string for DECL suitable for use by the SARIF logicalLocation
- "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
-
const char *
-compiler_logical_location::get_name_with_scope_for_tree (tree decl)
+tree_logical_location_manager::get_name_with_scope (key k) const
{
- gcc_assert (decl);
- return identifier_to_locale (lang_hooks.decl_printable_name (decl, 1));
+ tree node = tree_from_key (k);
+ assert_valid_tree (node);
+
+ if (DECL_P (node))
+ return identifier_to_locale (lang_hooks.decl_printable_name (node, 1));
+ if (TYPE_P (node))
+ return nullptr;
+ return nullptr;
}
-/* Get a string for DECL suitable for use by the SARIF logicalLocation
- "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
-
const char *
-compiler_logical_location::get_internal_name_for_tree (tree decl)
+tree_logical_location_manager::get_internal_name (key k) const
{
- gcc_assert (decl);
- if (HAS_DECL_ASSEMBLER_NAME_P (decl))
- if (tree id = DECL_ASSEMBLER_NAME (decl))
- return IDENTIFIER_POINTER (id);
+ tree node = tree_from_key (k);
+ assert_valid_tree (node);
+
+ if (DECL_P (node))
+ {
+ if (HAS_DECL_ASSEMBLER_NAME_P (node)
+ && TREE_CODE (node) != NAMESPACE_DECL) // FIXME
+ if (tree id = DECL_ASSEMBLER_NAME (node))
+ return IDENTIFIER_POINTER (id);
+ }
+ else if (TYPE_P (node))
+ return nullptr;
return NULL;
}
-/* Get what kind of SARIF logicalLocation DECL is (if any). */
-
enum logical_location_kind
-compiler_logical_location::get_kind_for_tree (tree decl)
+tree_logical_location_manager::get_kind (key k) const
{
- if (!decl)
- return LOGICAL_LOCATION_KIND_UNKNOWN;
+ tree node = tree_from_key (k);
+ assert_valid_tree (node);
- switch (TREE_CODE (decl))
+ switch (TREE_CODE (node))
{
default:
return LOGICAL_LOCATION_KIND_UNKNOWN;
@@ -80,94 +97,51 @@ compiler_logical_location::get_kind_for_tree (tree decl)
return LOGICAL_LOCATION_KIND_PARAMETER;
case VAR_DECL:
return LOGICAL_LOCATION_KIND_VARIABLE;
- }
-}
-
-label_text
-compiler_logical_location::get_name_for_tree_for_path_output (tree decl)
-{
- gcc_assert (decl);
- const char *n = DECL_NAME (decl)
- ? identifier_to_locale (lang_hooks.decl_printable_name (decl, 2))
- : _("<anonymous>");
- return label_text::borrow (n);
-}
-
-/* class tree_logical_location : public compiler_logical_location. */
-
-/* Implementation of the logical_location vfuncs, using m_decl. */
-
-const char *
-tree_logical_location::get_short_name () const
-{
- gcc_assert (m_decl);
- return get_short_name_for_tree (m_decl);
-}
-
-const char *
-tree_logical_location::get_name_with_scope () const
-{
- gcc_assert (m_decl);
- return get_name_with_scope_for_tree (m_decl);
-}
-
-const char *
-tree_logical_location::get_internal_name () const
-{
- gcc_assert (m_decl);
- return get_internal_name_for_tree (m_decl);
-}
+ case NAMESPACE_DECL:
+ return LOGICAL_LOCATION_KIND_NAMESPACE;
-enum logical_location_kind
-tree_logical_location::get_kind () const
-{
- gcc_assert (m_decl);
- return get_kind_for_tree (m_decl);
+ case RECORD_TYPE:
+ return LOGICAL_LOCATION_KIND_TYPE;
+ }
}
label_text
-tree_logical_location::get_name_for_path_output () const
-{
- gcc_assert (m_decl);
- return get_name_for_tree_for_path_output (m_decl);
-}
-
-/* class current_fndecl_logical_location : public compiler_logical_location. */
-
-/* Implementation of the logical_location vfuncs, using
- current_function_decl. */
-
-const char *
-current_fndecl_logical_location::get_short_name () const
+tree_logical_location_manager::get_name_for_path_output (key k) const
{
- gcc_assert (current_function_decl);
- return get_short_name_for_tree (current_function_decl);
-}
+ tree node = tree_from_key (k);
+ assert_valid_tree (node);
-const char *
-current_fndecl_logical_location::get_name_with_scope () const
-{
- gcc_assert (current_function_decl);
- return get_name_with_scope_for_tree (current_function_decl);
-}
-
-const char *
-current_fndecl_logical_location::get_internal_name () const
-{
- gcc_assert (current_function_decl);
- return get_internal_name_for_tree (current_function_decl);
+ if (DECL_P (node))
+ {
+ const char *n = DECL_NAME (node)
+ ? identifier_to_locale (lang_hooks.decl_printable_name (node, 2))
+ : _("<anonymous>");
+ return label_text::borrow (n);
+ }
+ else if (TYPE_P (node))
+ return label_text ();
+ return label_text ();
}
-enum logical_location_kind
-current_fndecl_logical_location::get_kind () const
+logical_location
+tree_logical_location_manager::get_parent (key k) const
{
- gcc_assert (current_function_decl);
- return get_kind_for_tree (current_function_decl);
-}
+ tree node = tree_from_key (k);
+ assert_valid_tree (node);
-label_text
-current_fndecl_logical_location::get_name_for_path_output () const
-{
- gcc_assert (current_function_decl);
- return get_name_for_tree_for_path_output (current_function_decl);
+ if (DECL_P (node))
+ {
+ if (!DECL_CONTEXT (node))
+ return logical_location ();
+ if (TREE_CODE (DECL_CONTEXT (node)) == TRANSLATION_UNIT_DECL)
+ return logical_location ();
+ return key_from_tree (DECL_CONTEXT (node));
+ }
+ else if (TYPE_P (node))
+ {
+ if (!TYPE_CONTEXT (node))
+ return logical_location ();
+ return key_from_tree (TYPE_CONTEXT (node));
+ }
+ return logical_location ();
}
diff --git a/gcc/tree-logical-location.h b/gcc/tree-logical-location.h
index 1e15bee..0d57888 100644
--- a/gcc/tree-logical-location.h
+++ b/gcc/tree-logical-location.h
@@ -1,4 +1,4 @@
-/* Subclasses of logical_location with knowledge of "tree".
+/* Subclass of logical_location_manager with knowledge of "tree".
Copyright (C) 2022-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -23,48 +23,28 @@ along with GCC; see the file COPYING3. If not see
#include "logical-location.h"
-/* Abstract subclass of logical_location, with knowledge of "tree", but
- for no specific tree. */
-
-class compiler_logical_location : public logical_location
-{
- protected:
- static const char *get_short_name_for_tree (tree);
- static const char *get_name_with_scope_for_tree (tree);
- static const char *get_internal_name_for_tree (tree);
- static enum logical_location_kind get_kind_for_tree (tree);
- static label_text get_name_for_tree_for_path_output (tree);
-};
-
-/* Concrete subclass of logical_location, with reference to a specific
- tree. */
-
-class tree_logical_location : public compiler_logical_location
-{
-public:
- tree_logical_location (tree decl) : m_decl (decl) {}
-
- const char *get_short_name () const final override;
- const char *get_name_with_scope () const final override;
- const char *get_internal_name () const final override;
- enum logical_location_kind get_kind () const final override;
- label_text get_name_for_path_output () const final override;
-
-private:
- tree m_decl;
-};
-
-/* Concrete subclass of logical_location, with reference to
- current_function_decl. */
-
-class current_fndecl_logical_location : public compiler_logical_location
+/* A subclass of logical_location_manager in which the keys are
+ "tree".
+ Note that there is no integration with the garbage collector,
+ and so logical_location instances can only be short-lived. */
+class tree_logical_location_manager : public logical_location_manager
{
public:
- const char *get_short_name () const final override;
- const char *get_name_with_scope () const final override;
- const char *get_internal_name () const final override;
- enum logical_location_kind get_kind () const final override;
- label_text get_name_for_path_output () const final override;
+ const char *get_short_name (key) const final override;
+ const char *get_name_with_scope (key) const final override;
+ const char *get_internal_name (key) const final override;
+ enum logical_location_kind get_kind (key) const final override;
+ label_text get_name_for_path_output (key) const final override;
+ key get_parent (key) const final override;
+
+ static tree tree_from_key (logical_location k)
+ {
+ return const_cast<tree> (k.cast_to<const_tree> ());
+ }
+ static logical_location key_from_tree (tree node)
+ {
+ return logical_location::from_ptr (node);
+ }
};
#endif /* GCC_TREE_LOGICAL_LOCATION_H. */
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index c9395e3..231a3ca 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -1203,6 +1203,97 @@ vect_slp_analyze_instance_dependence (vec_info *vinfo, slp_instance instance)
for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (store).length (); ++k)
gimple_set_visited (SLP_TREE_SCALAR_STMTS (store)[k]->stmt, false);
+ /* If this is a SLP instance with a store check if there's a dependent
+ load that cannot be forwarded from a previous iteration of a loop
+ both are in. This is to avoid situations like that in PR115777. */
+ if (res && store)
+ {
+ stmt_vec_info store_info
+ = DR_GROUP_FIRST_ELEMENT (SLP_TREE_SCALAR_STMTS (store)[0]);
+ class loop *store_loop = gimple_bb (store_info->stmt)->loop_father;
+ if (! loop_outer (store_loop))
+ return res;
+ vec<loop_p> loop_nest;
+ loop_nest.create (1);
+ loop_nest.quick_push (store_loop);
+ data_reference *drs = nullptr;
+ for (slp_tree &load : SLP_INSTANCE_LOADS (instance))
+ {
+ if (! STMT_VINFO_GROUPED_ACCESS (SLP_TREE_SCALAR_STMTS (load)[0]))
+ continue;
+ stmt_vec_info load_info
+ = DR_GROUP_FIRST_ELEMENT (SLP_TREE_SCALAR_STMTS (load)[0]);
+ if (gimple_bb (load_info->stmt)->loop_father != store_loop)
+ continue;
+
+ /* For now concern ourselves with write-after-read as we also
+ only look for re-use of the store within the same SLP instance.
+ We can still get a RAW here when the instance contais a PHI
+ with a backedge though, thus this test. */
+ if (! vect_stmt_dominates_stmt_p (STMT_VINFO_STMT (load_info),
+ STMT_VINFO_STMT (store_info)))
+ continue;
+
+ if (! drs)
+ {
+ drs = create_data_ref (loop_preheader_edge (store_loop),
+ store_loop,
+ DR_REF (STMT_VINFO_DATA_REF (store_info)),
+ store_info->stmt, false, false);
+ if (! DR_BASE_ADDRESS (drs)
+ || TREE_CODE (DR_STEP (drs)) != INTEGER_CST)
+ break;
+ }
+ data_reference *drl
+ = create_data_ref (loop_preheader_edge (store_loop),
+ store_loop,
+ DR_REF (STMT_VINFO_DATA_REF (load_info)),
+ load_info->stmt, true, false);
+
+ /* See whether the DRs have a known constant distance throughout
+ the containing loop iteration. */
+ if (! DR_BASE_ADDRESS (drl)
+ || ! operand_equal_p (DR_STEP (drs), DR_STEP (drl))
+ || ! operand_equal_p (DR_BASE_ADDRESS (drs),
+ DR_BASE_ADDRESS (drl))
+ || ! operand_equal_p (DR_OFFSET (drs), DR_OFFSET (drl)))
+ {
+ free_data_ref (drl);
+ continue;
+ }
+
+ /* If the next iteration load overlaps with a non-power-of-two offset
+ we are surely failing any STLF attempt. */
+ HOST_WIDE_INT step = TREE_INT_CST_LOW (DR_STEP (drl));
+ unsigned HOST_WIDE_INT sizes
+ = (TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drs))))
+ * DR_GROUP_SIZE (store_info));
+ unsigned HOST_WIDE_INT sizel
+ = (TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drl))))
+ * DR_GROUP_SIZE (load_info));
+ if (ranges_overlap_p (TREE_INT_CST_LOW (DR_INIT (drl)) + step, sizel,
+ TREE_INT_CST_LOW (DR_INIT (drs)), sizes))
+ {
+ unsigned HOST_WIDE_INT dist
+ = absu_hwi (TREE_INT_CST_LOW (DR_INIT (drl)) + step
+ - TREE_INT_CST_LOW (DR_INIT (drs)));
+ poly_uint64 loadsz = tree_to_poly_uint64
+ (TYPE_SIZE_UNIT (SLP_TREE_VECTYPE (load)));
+ poly_uint64 storesz = tree_to_poly_uint64
+ (TYPE_SIZE_UNIT (SLP_TREE_VECTYPE (store)));
+ /* When the overlap aligns with vector sizes used for the loads
+ and the vector stores are larger or equal to the loads
+ forwarding should work. */
+ if (maybe_gt (loadsz, storesz) || ! multiple_p (dist, loadsz))
+ load->avoid_stlf_fail = true;
+ }
+ free_data_ref (drl);
+ }
+ if (drs)
+ free_data_ref (drs);
+ loop_nest.release ();
+ }
+
return res;
}
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index 9bf142d..562e222 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -122,6 +122,7 @@ _slp_tree::_slp_tree ()
SLP_TREE_DEF_TYPE (this) = vect_uninitialized_def;
SLP_TREE_CODE (this) = ERROR_MARK;
this->ldst_lanes = false;
+ this->avoid_stlf_fail = false;
SLP_TREE_VECTYPE (this) = NULL_TREE;
SLP_TREE_REPRESENTATIVE (this) = NULL;
SLP_TREE_MEMORY_ACCESS_TYPE (this) = VMAT_INVARIANT;
@@ -3104,7 +3105,8 @@ vect_print_slp_tree (dump_flags_t dump_kind, dump_location_t loc,
SLP_TREE_REF_COUNT (node));
if (SLP_TREE_VECTYPE (node))
dump_printf (metadata, " %T", SLP_TREE_VECTYPE (node));
- dump_printf (metadata, "\n");
+ dump_printf (metadata, "%s\n",
+ node->avoid_stlf_fail ? " (avoid-stlf-fail)" : "");
if (SLP_TREE_DEF_TYPE (node) == vect_internal_def)
{
if (SLP_TREE_CODE (node) == VEC_PERM_EXPR)
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 537ae6c..ea0b426 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -2134,6 +2134,14 @@ get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
: vect_store_lanes_supported (vectype, group_size,
masked_p))) != IFN_LAST)
*memory_access_type = VMAT_LOAD_STORE_LANES;
+ else if (!loop_vinfo && slp_node->avoid_stlf_fail)
+ {
+ *memory_access_type = VMAT_ELEMENTWISE;
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "using element-wise load to avoid disrupting "
+ "cross iteration store-to-load forwarding\n");
+ }
else
*memory_access_type = VMAT_CONTIGUOUS;
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 63991c3..3d11559 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -266,6 +266,9 @@ struct _slp_tree {
/* Whether uses of this load or feeders of this store are suitable
for load/store-lanes. */
bool ldst_lanes;
+ /* For BB vect, flag to indicate this load node should be vectorized
+ as to avoid STLF fails because of related stores. */
+ bool avoid_stlf_fail;
int vertex;