From f0f800d1c48cb4609708f511c654eba0fc3b8902 Mon Sep 17 00:00:00 2001 From: York Jasper Niebuhr Date: Fri, 17 Oct 2025 21:20:00 +0200 Subject: [PATCH] Added early gcc component_ref callback patch --- gcc_component_ref.patch | 244 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 gcc_component_ref.patch diff --git a/gcc_component_ref.patch b/gcc_component_ref.patch new file mode 100644 index 0000000..7d020cb --- /dev/null +++ b/gcc_component_ref.patch @@ -0,0 +1,244 @@ +From 4c2d49dcf5e9a1090313cd9d922b63e280fc4d54 Mon Sep 17 00:00:00 2001 +From: York Jasper Niebuhr +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 % to static data member %qD", expr); ++ if (!may_fail) ++ error ("cannot apply % to static data member %qD", expr); + return error_mark_node; + + case CALL_EXPR: + case TARGET_EXPR: +- error ("cannot apply % when % is overloaded"); ++ if (!may_fail) ++ error ("cannot apply % when % is overloaded"); + return error_mark_node; + + case NOP_EXPR: + case INDIRECT_REF: + if (!TREE_CONSTANT (TREE_OPERAND (expr, 0))) + { +- error ("cannot apply % to a non constant address"); ++ if (!may_fail) ++ error ("cannot apply % 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 +