refactor: compare foreign function declarations by resolved type - #1936
Open
ahomescu wants to merge 3 commits into
Conversation
ahomescu
changed the base branch from
ahomescu/fix_reorganize_definitions/preserve_extern_link_name
to
ahomescu/fix_reorganize_definitions/mismatched_extern_arity
July 25, 2026 00:57
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 01:40
3e52313 to
af3c69c
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 01:57
af3c69c to
fedfec1
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 02:08
fedfec1 to
f4c8e2f
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 02:11
f4c8e2f to
47b3cf0
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
2 times, most recently
from
July 25, 2026 02:35
732a60c to
10990b4
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 05:09
10990b4 to
60a774f
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 05:33
60a774f to
2bff68f
Compare
ahomescu
changed the base branch from
ahomescu/fix_reorganize_definitions/mismatched_extern_arity
to
ahomescu/fix_reorganize_definitions/deterministic_externs
July 25, 2026 05:41
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 05:41
2bff68f to
2d099d0
Compare
ahomescu
changed the base branch from
ahomescu/fix_reorganize_definitions/deterministic_externs
to
ahomescu/fix_reorganize_definitions/mismatched_extern_arity
July 25, 2026 05:42
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 25, 2026 05:42
2d099d0 to
0380037
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
3 times, most recently
from
July 25, 2026 06:16
f423c43 to
8e87153
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
2 times, most recently
from
July 25, 2026 06:43
15e6ee0 to
7bb56b6
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
2 times, most recently
from
July 30, 2026 00:19
1499b5b to
25aef51
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 30, 2026 00:31
25aef51 to
82e9b1b
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 30, 2026 22:54
82e9b1b to
00ecfb8
Compare
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 30, 2026 22:56
00ecfb8 to
43f8815
Compare
Regression test: `test_reorganize_foreign_fn_type_identity`
(`tests/snapshots/reorganize_foreign_fn_type_identity.rs`). Each translation
unit has its own `buf`, and the two differ in field visibility, so the
transform correctly keeps them apart and renames the second to `buf_1`. Both
units then declare `fill(b: *mut buf)` — spelled identically, but naming a
different type in each unit.
`find_foreign_item` compares the two with `compatible_fn_prototypes`, which
resolves the parameter types through `opt_node_type`. A foreign item has no
body and so no typeck results to resolve against, and the comparison falls
through to `unnamed_equiv`, a purely syntactic check that sees `*mut buf`
against `*mut buf` and reports a match. The second declaration is dropped
and both call sites are pointed at the first, so the caller written against
`buf_1` now passes it to a function taking `*mut buf`:
error[E0308]: mismatched types
This is the same defect that makes the output of `test_reorganize_definitions`
fail to compile, reduced to the two types and one function that cause it.
Comparing foreign functions by resolved type routed the comparison through `structural_eq_tys_impl`, whose array arm lets a zero-length array match an array of any length. That leniency is there for an `extern` array declaration, which C lets omit the length that the definition gives, and which we translate to a zero length; it does not hold inside a function signature. `*mut [c_int; 0]` and `*mut [c_int; 4]` are distinct Rust types with no coercion between them, so two declarations that differ only there are not interchangeable at a call site. `test_reorganize_foreign_fn_rename` regressed on exactly that: its two `compute` declarations were collapsed into one and `b_call` was rewritten to call a function it cannot pass its argument to, an `E0308` in the output. The syntactic path this replaced happened to reject the pair because it compared the written-out lengths. `TypeCompare` now carries an `exact_array_lens` flag, off by default so that the `extern` array declaration it exists for keeps matching its definition, and on for `compatible_fn_sigs` and `compatible_fn_prototypes`. An array length reached through a signature, including one nested in a pointed-to struct, has to match exactly. No snapshot changed: the `statfs64` unification and the `statvfs` separation from the previous commit both still hold.
`find_foreign_item` decided whether two foreign functions were the same by handing their `FnDecl`s to `compatible_fn_prototypes`. That resolves each parameter through `opt_node_type`, but a foreign item has no body and so no typeck results, so every lookup came back empty and the comparison fell through to `unnamed_equiv` — a syntactic check with no notion of what a name resolves to. Two declarations from different modules whose parameters were merely spelled alike were reported identical, one was dropped, and its callers were rewritten to a function taking a different type. `compatible_foreign_fns` now asks `tcx` for each declaration's signature and compares those with `compatible_fn_sigs`, which resolves the types properly. `match_exports` already compared foreign functions against external ones this way; this brings the crate-local comparison in line with it. The syntactic path is kept as a fallback for a signature that will not resolve, which is also why the arity check added earlier still matters. Structurally identical types from different modules still compare equal, so this only separates declarations that genuinely differ: the `statfs64` declarations in `test_reorganize_definitions` are still unified with libc's, while its two `statvfs` declarations are now kept apart, and its output loses the two `E0308` errors. The remaining `E0603` there is a separate defect, fixed next.
ahomescu
force-pushed
the
ahomescu/fix_reorganize_definitions/compare_extern_fn_sigs
branch
from
July 30, 2026 22:58
43f8815 to
a7399e5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack created with GitHub Stacks CLI • Give Feedback 💬