248 lines
8.8 KiB
Diff
248 lines
8.8 KiB
Diff
From ab8884cbf3712f939556fc7789bbf32132c7ff1a Mon Sep 17 00:00:00 2001
|
||
From: York Jasper Niebuhr <yjnworkstation@gmail.com>
|
||
Date: Fri, 17 Oct 2025 22:04:41 +0200
|
||
Subject: [PATCH] PLUGIN_BUILD_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 | 12 ++++++++++
|
||
gcc/doc/plugins.texi | 6 +++++
|
||
gcc/plugin.cc | 2 ++
|
||
gcc/plugin.def | 6 +++++
|
||
7 files changed, 66 insertions(+), 13 deletions(-)
|
||
|
||
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
|
||
index 587d76461e9..d34edfaa688 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..aff6dce36fb 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,16 @@ 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..312f178fab4 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
|
||
|