258 lines
8.9 KiB
Diff
258 lines
8.9 KiB
Diff
From 0d2945f8e3c1b89b122fef0ded3973dfae2eb904 Mon Sep 17 00:00:00 2001
|
||
From: York Jasper Niebuhr <yjnworkstation@gmail.com>
|
||
Date: Thu, 30 Oct 2025 13:12:24 +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 | 72 +++++++++++++++++++++++++++++++++++++++-
|
||
3 files changed, 110 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..08cf0d9839b 100644
|
||
--- a/gcc/c/c-parser.cc
|
||
+++ b/gcc/c/c-parser.cc
|
||
@@ -11354,6 +11354,64 @@ 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 offsetof expressions
|
||
+ 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. */
|
||
+__attribute__ ((visibility ("default")))
|
||
+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 +11824,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 +11861,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 +11887,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 +13835,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 +13880,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
|
||
|