AST modification after parsing silently discarded by GCC
0 reputation · 16 Feb 2024, 15:15 UTC
0 reputation · 16 Feb 2024, 15:15 UTC
A GCC plugin registers a PLUGIN_ADD_DECL callback to inject a new function declaration after the language front‑end has finished parsing a source file. The documentation does not formally allow adding new AST nodes at this stage, and in practice GCC appears to drop the injected declaration without error.
While the plugin interface lists callbacks such as PLUGIN_ADD_DECL, the spec lacks a clear rule for post‑parsing AST modifications. Existing reports indicate that such additions are silently discarded, leading to missing symbols in the final binary. The mailing list and bug tracker describe this as an unfinished feature, suggesting that current behavior may change in future releases.
GCC discards declarations added via PLUGIN_ADD_DECL when the callback runs after the language front‑end has finished parsing the translation unit.
PLUGIN_ADD_DECL is documented as a notification hook that runs during declaration processing, not as a supported insertion point for creating new declarations.After parsing, GCC finalizes the translation unit: it builds GENERIC/GIMPLE representations, freezes symbol tables and the call graph, and registers all declarations for later passes. Nodes injected after this point are not inserted into those structures, so later GIMPLE and IPA passes never see them; they are silently omitted from the object file.
PLUGIN_START_UNIT (before any parsing) or PLUGIN_PARSE_DECL/PLUGIN_FINISH_DECL (as each declaration is processed).pushdecl or declare_function to insert the node into the current translation unit’s decl chain.-fdump-tree-all or fdump-original to verify that the node appears in the dumped trees before GIMPLE generation.nm or objdump -t to confirm the injected symbol is emitted.To confirm whether the behavior differs for your setup, please specify the exact GCC version you are using and which plugin hook (e.g., PLUGIN_ADD_DECL vs PLUGIN_START_UNIT) you are currently employing.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 16 Feb 2024, 22:17 UTC
In GCC the front‑end freezes the global declaration chain once parsing finishes. The PLUGIN_ADD_DECL callback is only called for nodes that are inserted while the parser is building that chain. If you call it in PLUGIN_FINISH_UNIT or later, the decl is dropped silently – it never reaches the GIMPLE phase, so it does not appear in the final binary.
To inject code reliably you should register a GIMPLE pass (via PLUGIN_PASS_MANAGER_SETUP) that runs after the front‑end, e.g. after the cfg pass, and use build_fn_decl or pushdecl to add the function to the current decl chain. This works on GCC 12+ and is the documented, stable approach.
Future releases are expected to treat late PLUGIN_ADD_DECL calls as errors, so migrating to a GIMPLE pass is the safest path.