Added early gcc component_ref callback patch

This commit is contained in:
York Jasper Niebuhr 2025-10-17 21:20:00 +02:00
parent 81ba4bc112
commit f0f800d1c4

244
gcc_component_ref.patch Normal file
View File

@ -0,0 +1,244 @@
From 4c2d49dcf5e9a1090313cd9d922b63e280fc4d54 Mon Sep 17 00:00:00 2001
From: York Jasper Niebuhr <yjnworkstation@gmail.com>
Date: Fri, 17 Oct 2025 21:17:30 +0200
Subject: [PATCH] unformatted component ref callback
---
gcc/c-family/c-common.cc | 48 +++++++++++++++++++++++++++++++---------
gcc/c-family/c-common.h | 3 ++-
gcc/c/c-parser.cc | 2 +-
gcc/c/c-typeck.cc | 9 ++++++++
gcc/doc/plugins.texi | 6 +++++
gcc/plugin.cc | 2 ++
gcc/plugin.def | 6 +++++
7 files changed, 63 insertions(+), 13 deletions(-)
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9..f23093f5a66 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -7076,43 +7076,48 @@ c_common_to_target_charset (HOST_WIDE_INT c)
the whole expression. Return the folded result. */
tree
-fold_offsetof (tree expr, tree type, enum tree_code ctx)
+fold_offsetof (tree expr, tree type, enum tree_code ctx, bool may_fail)
{
tree base, off, t;
tree_code code = TREE_CODE (expr);
+
switch (code)
{
case ERROR_MARK:
return expr;
case VAR_DECL:
- error ("cannot apply %<offsetof%> to static data member %qD", expr);
+ if (!may_fail)
+ error ("cannot apply %<offsetof%> to static data member %qD", expr);
return error_mark_node;
case CALL_EXPR:
case TARGET_EXPR:
- error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
+ if (!may_fail)
+ error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
return error_mark_node;
case NOP_EXPR:
case INDIRECT_REF:
if (!TREE_CONSTANT (TREE_OPERAND (expr, 0)))
{
- error ("cannot apply %<offsetof%> to a non constant address");
+ if (!may_fail)
+ error ("cannot apply %<offsetof%> to a non constant address");
return error_mark_node;
}
return convert (type, TREE_OPERAND (expr, 0));
case COMPONENT_REF:
- base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
+ base = fold_offsetof (TREE_OPERAND (expr, 0), type, code, may_fail);
if (base == error_mark_node)
return base;
t = TREE_OPERAND (expr, 1);
if (DECL_C_BIT_FIELD (t))
{
- error ("attempt to take address of bit-field structure "
- "member %qD", t);
+ if (!may_fail)
+ error ("attempt to take address of bit-field structure "
+ "member %qD", t);
return error_mark_node;
}
off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t),
@@ -7121,7 +7126,7 @@ fold_offsetof (tree expr, tree type, enum tree_code ctx)
break;
case ARRAY_REF:
- base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
+ base = fold_offsetof (TREE_OPERAND (expr, 0), type, code, may_fail);
if (base == error_mark_node)
return base;
@@ -7178,17 +7183,38 @@ fold_offsetof (tree expr, tree type, enum tree_code ctx)
case COMPOUND_EXPR:
/* Handle static members of volatile structs. */
t = TREE_OPERAND (expr, 1);
- gcc_checking_assert (VAR_P (get_base_address (t)));
- return fold_offsetof (t, type);
+ if (!VAR_P (get_base_address (t)))
+ return error_mark_node;
+ return fold_offsetof (t, type, ERROR_MARK, may_fail);
default:
- gcc_unreachable ();
+ return error_mark_node;
}
if (!POINTER_TYPE_P (type))
return size_binop (PLUS_EXPR, base, convert (type, off));
return fold_build_pointer_plus (base, off);
}
+
+/* Tries folding expr using fold_offsetof. On success, the folded offsetof
+ is returned. On failure, the original expr is wrapped in an ADDR_EXPR
+ and converted to the desired expression type. The resulting expression
+ may or may not be constant! */
+
+tree
+fold_offsetof_maybe (tree expr, tree type)
+{
+ /* expr might not have the correct structure, thus folding may fail */
+ tree maybe_folded = fold_offsetof(expr, type, ERROR_MARK, true);
+ if (maybe_folded != error_mark_node)
+ return maybe_folded;
+
+ tree ptr_type = build_pointer_type (TREE_TYPE (expr));
+ tree ptr = build1 (ADDR_EXPR, ptr_type, expr);
+
+ return fold_convert (type, ptr);
+}
+
/* *PTYPE is an incomplete array. Complete it with a domain based on
INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ea6c2975056..70fcfeb6661 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1174,7 +1174,8 @@ extern bool c_dump_tree (void *, tree);
extern void verify_sequence_points (tree);
extern tree fold_offsetof (tree, tree = size_type_node,
- tree_code ctx = ERROR_MARK);
+ tree_code ctx = ERROR_MARK, bool may_fail = false);
+extern tree fold_offsetof_maybe (tree, tree = size_type_node);
extern int complete_array_type (tree *, tree, bool);
extern void complete_flexible_array_elts (tree);
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 22ec0f849b7..6a8a5d58e6d 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -11823,7 +11823,7 @@ c_parser_postfix_expression (c_parser *parser)
location_t end_loc = c_parser_peek_token (parser)->get_finish ();
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
- expr.value = fold_offsetof (offsetof_ref);
+ expr.value = fold_offsetof_maybe (offsetof_ref);
set_c_expr_source_range (&expr, loc, end_loc);
}
break;
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 55d896e02df..e76002151bd 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
#include "realmpfr.h"
#include "tree-pretty-print-markup.h"
#include "gcc-urlifier.h"
+#include "plugin.h"
/* Possible cases of implicit conversions. Used to select diagnostic messages
and control folding initializers in convert_for_assignment. */
@@ -133,6 +134,7 @@ static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
static void record_maybe_used_decl (tree);
static bool comptypes_internal (const_tree, const_tree,
struct comptypes_data *data);
+
/* Return true if EXP is a null pointer constant, false otherwise. */
@@ -3174,6 +3176,13 @@ build_component_ref (location_t loc, tree datum, tree component,
else if (TREE_DEPRECATED (subdatum))
warn_deprecated_use (subdatum, NULL_TREE);
+ tree pre_cb_type = TREE_TYPE (ref);
+ if (invoke_plugin_callbacks (PLUGIN_BUILD_COMPONENT_REF, &ref) == PLUGEVT_SUCCESS &&
+ !comptypes (TREE_TYPE (ref), pre_cb_type))
+ {
+ error_at (EXPR_LOCATION (ref), "PLUGIN_BUILD_COMPONENT_REF callback returned expression of incompatible type");
+ }
+
datum = ref;
field = TREE_CHAIN (field);
diff --git a/gcc/doc/plugins.texi b/gcc/doc/plugins.texi
index c11167a34ef..942e2e41b90 100644
--- a/gcc/doc/plugins.texi
+++ b/gcc/doc/plugins.texi
@@ -222,6 +222,12 @@ enum plugin_event
ana::plugin_analyzer_init_iface *. */
PLUGIN_ANALYZER_INIT,
+ /* Called by the C front end when a COMPONENT_REF node is built.
+ The callback receives a pointer to the COMPONENT_REF tree (of type 'tree *').
+ Plugins may replace the node by assigning through the pointer, but any
+ replacement must be type-compatible with the original node. */
+ PLUGIN_BUILD_COMPONENT_REF,
+
PLUGIN_EVENT_FIRST_DYNAMIC /* Dummy event used for indexing callback
array. */
@};
diff --git a/gcc/plugin.cc b/gcc/plugin.cc
index 0de2cc2dd2c..975e8c4e291 100644
--- a/gcc/plugin.cc
+++ b/gcc/plugin.cc
@@ -500,6 +500,7 @@ register_callback (const char *plugin_name,
case PLUGIN_NEW_PASS:
case PLUGIN_INCLUDE_FILE:
case PLUGIN_ANALYZER_INIT:
+ case PLUGIN_BUILD_COMPONENT_REF:
{
struct callback_info *new_callback;
if (!callback)
@@ -581,6 +582,7 @@ invoke_plugin_callbacks_full (int event, void *gcc_data)
case PLUGIN_NEW_PASS:
case PLUGIN_INCLUDE_FILE:
case PLUGIN_ANALYZER_INIT:
+ case PLUGIN_BUILD_COMPONENT_REF:
{
/* Iterate over every callback registered with this event and
call it. */
diff --git a/gcc/plugin.def b/gcc/plugin.def
index 94e012a1e00..b0335178762 100644
--- a/gcc/plugin.def
+++ b/gcc/plugin.def
@@ -103,6 +103,12 @@ DEFEVENT (PLUGIN_INCLUDE_FILE)
ana::plugin_analyzer_init_iface *. */
DEFEVENT (PLUGIN_ANALYZER_INIT)
+/* Called by the C front end when a COMPONENT_REF node is built.
+ The callback receives a pointer to the COMPONENT_REF tree (of type 'tree *').
+ Plugins may replace the node by assigning through the pointer, but any
+ replacement must be type-compatible with the original node. */
+DEFEVENT (PLUGIN_BUILD_COMPONENT_REF)
+
/* When adding a new hard-coded plugin event, don't forget to edit in
file plugin.cc the functions register_callback and
invoke_plugin_callbacks_full accordingly! */
--
2.43.0