GCC patch v2
This commit is contained in:
parent
94ad5b5090
commit
156da90260
@ -31,7 +31,7 @@ Warning: Rough road ahead.
|
||||
|
||||
Now to the annoying part: The GNU front-end for the C language folds offsetof-like expressions into constants. In the parser. IN. THE. PARSER. Any hooks/events available to plugins happen significantly later in the pipeline. Thus, SPSLR can not detect offsetofs, be it \_\_builtin\_offsetof or the DIY variants (`((size\_t)&((struct S\*)0)-\>m)`), using current GCC versions.
|
||||
|
||||
To deal with this reliably, using a custom GCC build is necessary. The required patch is provided in this repo. To use it and install the custom gcc, use these commands:
|
||||
To deal with this reliably, using a custom GCC build is necessary. The required patch is provided in this repo (do NOT use the v2 yet!). To use it and install the custom gcc, use these commands:
|
||||
|
||||
```bash
|
||||
git clone git://gcc.gnu.org/git/gcc.git
|
||||
|
||||
255
gcc_component_ref_v2.patch
Normal file
255
gcc_component_ref_v2.patch
Normal file
@ -0,0 +1,255 @@
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user