selfpatch-slr/gcc_component_ref_v2.patch
2025-10-30 13:07:39 +01:00

256 lines
8.9 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 474c2208836a447bb2452a45a0e76453b1d9c56c Mon Sep 17 00:00:00 2001
From: York Jasper Niebuhr <yjnworkstation@gmail.com>
Date: Thu, 30 Oct 2025 13:04:18 +0100
Subject: [PATCH] c_parse_component_ref callback
---
gcc/c-family/c-common.cc | 48 ++++++++++++++++++++-------
gcc/c-family/c-common.h | 3 +-
gcc/c/c-parser.cc | 70 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 108 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..5410b9dc003 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -11354,6 +11354,62 @@ get_counted_by_ref (tree array_ref)
return NULL_TREE;
}
+/* Callback type for notifying plugins when the C parser constructs
+ a COMPONENT_REF expression.
+
+ The callback receives the COMPONENT_REF tree that has just been parsed.
+ It may optionally return a replacement tree, which will be used instead
+ of the original if it is type-compatible. Returning NULL_TREE leaves
+ the expression unchanged.
+
+ This callback is intended for plugins that wish to observe or transform
+ member-access expressions (such as 'a.b' or 'a->b') or at parse time. */
+using c_parse_component_ref_cb_t = tree (*)(tree ref);
+
+/* Plugin-registered callback for COMPONENT_REF parse notifications.
+ Initialized to NULL when no plugin has registered a callback. */
+static c_parse_component_ref_cb_t c_parse_component_ref_cb = nullptr;
+
+/* Register a plugin callback to be invoked for each parsed COMPONENT_REF.
+
+ Only a single callback is supported; registering a new one replaces
+ any previously registered callback. */
+void
+register_c_parse_component_ref_cb (c_parse_component_ref_cb_t cb)
+{
+ c_parse_component_ref_cb = cb;
+}
+
+/* Helper to notify the registered plugin callback that a COMPONENT_REF
+ has been parsed.
+
+ If a plugin has registered a callback, this function invokes it with
+ the given COMPONENT_REF tree. If the callback returns a non-NULL
+ tree whose type is compatible with the original (as determined by
+ comptypes), the COMPONENT_REF is replaced with that tree.
+
+ This preserves parser invariants and prevents type inconsistencies
+ in subsequent compilation stages. */
+static void
+notify_plugin_parse_component_ref (tree* ref)
+{
+ if (!ref || !c_parse_component_ref_cb)
+ return;
+
+ tree repl = c_parse_component_ref_cb (*ref);
+ if (!repl)
+ return;
+
+ if (comptypes (TREE_TYPE (*ref), TREE_TYPE (repl)))
+ {
+ *ref = repl;
+ return;
+ }
+
+ warning (0, "plugin: tree returned from %<c_parse_component_ref_cb%> "
+ "has incompatible type; ignored");
+}
+
/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2,
C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to
call c_parser_postfix_expression_after_paren_type on encountering them.
@@ -11766,6 +11822,9 @@ c_parser_postfix_expression (c_parser *parser)
= build_component_ref (loc, offsetof_ref, comp_tok->value,
comp_tok->location, UNKNOWN_LOCATION,
false);
+
+ notify_plugin_parse_component_ref (&offsetof_ref);
+
c_parser_consume_token (parser);
while (c_parser_next_token_is (parser, CPP_DOT)
|| c_parser_next_token_is (parser,
@@ -11800,6 +11859,9 @@ c_parser_postfix_expression (c_parser *parser)
comp_tok->location,
UNKNOWN_LOCATION,
false);
+
+ notify_plugin_parse_component_ref (&offsetof_ref);
+
c_parser_consume_token (parser);
}
else
@@ -11823,7 +11885,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;
@@ -13771,6 +13833,9 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
c_parser_consume_token (parser);
expr.value = build_component_ref (op_loc, expr.value, ident,
comp_loc, UNKNOWN_LOCATION);
+
+ notify_plugin_parse_component_ref (&expr.value);
+
set_c_expr_source_range (&expr, start, finish);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) != COMPONENT_REF)
@@ -13813,6 +13878,9 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
RO_ARROW),
ident, comp_loc,
expr.get_location ());
+
+ notify_plugin_parse_component_ref (&expr.value);
+
set_c_expr_source_range (&expr, start, finish);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) != COMPONENT_REF)
--
2.43.0