refactor: compare foreign function declarations by resolved type - #1936
refactor: compare foreign function declarations by resolved type#1936ahomescu wants to merge 3 commits into
Conversation
3e52313 to
af3c69c
Compare
af3c69c to
fedfec1
Compare
fedfec1 to
f4c8e2f
Compare
f4c8e2f to
47b3cf0
Compare
732a60c to
10990b4
Compare
10990b4 to
60a774f
Compare
60a774f to
2bff68f
Compare
2bff68f to
2d099d0
Compare
2d099d0 to
0380037
Compare
f423c43 to
8e87153
Compare
15e6ee0 to
7bb56b6
Compare
1499b5b to
25aef51
Compare
25aef51 to
82e9b1b
Compare
82e9b1b to
00ecfb8
Compare
00ecfb8 to
43f8815
Compare
43f8815 to
a7399e5
Compare
|
The commit message for
|
fw-immunant
left a comment
There was a problem hiding this comment.
I think this is functionally reasonable, modulo various comments. That said, the newly-added test does appear to be failing. I'd also prefer if commit messages generated by an LLM were demarcated as quotation (if included at all) rather than appearing like a message from the committer.
| type DefMapping = HashMap<DefId, DefId>; | ||
|
|
||
| #[derive(Clone, Copy)] | ||
| pub struct TypeCompare<'a, 'tcx: 'a, 'b> { |
There was a problem hiding this comment.
A doc comment explaining the purpose of this type would be good to have, as the name TypeCompare is not entirely clear about how the data stored here relates to comparing types--is it a pass over source code which compares types, guidance for which types to compare, a specification of what to compare about types, the contextual information required to compare types, etc.
In practice it seems like it's the latter, and now being augmented with the penultimate.
There was a problem hiding this comment.
That seems independent of the current change, TypeCompare is a really old type. I'll make a separate PR for that.
There was a problem hiding this comment.
Re this line: I'm not sure why we needed the new derive, so I deleted it.
Update: I found out why we needed it, it's because with_exact_array_lens takes a reference but produces a new object.
| // We allow 0 length arrays to match any length arrays. This | ||
| // isn't exactly the C definition of compatible extern global | ||
| // array types with global array definitions, but it should be | ||
| // apply in practice as we translate empty extern array lengths | ||
| // into 0 length extern arrays. | ||
| if len1 != len2 && len1 != Some(0) && len2 != Some(0) { | ||
| let lenient = !self.exact_array_lens && (len1 == Some(0) || len2 == Some(0)); | ||
| if len1 != len2 && !lenient { |
There was a problem hiding this comment.
Is there any way we could avoid translating incomplete array types to zero-length arrays, e.g. by translating to a pointer to a DST or such? Our test coverage of what we currently do here seems pretty minimal (e.g. our c2rust-transpile/tests/snapshots/incomplete_arrays.c snapshot generates no code), but in practice I don't see how Rust code using elements from a zero-length array (even if its actual definition is foreign) can be sound.
There was a problem hiding this comment.
We might need to do different things for each of the following cases:
externarray, e.g.extern int foo[];. I'm not sure we can use a DST here, since a pointer or reference to it becomes a fat pointer.- Function argument:
void foo(int arg[]);. This is an array-to-pointer decay, so replacing it withint *argmight be fine. - Flexible array member at the end of a structure. I think this is the only one that could be a DST, but we would have to detect it.
I'm not sure the transpiler handles these cases differently, I'll have to go check.
a7399e5 to
a7355b9
Compare
e00fe34 to
7899fc2
Compare
|
I need to investigate what happened here with all the rebasing, because the test and the fix don't seem to match anymore. |
Add a regression test for a bug where foreign function declarations get
merged based purely on how their types are spelled.
Two translation units each define their own struct named `buf`, and since
the structs differ, the transform correctly renames the second one to
`buf_1`. But both units also declare `fill(b: *mut buf)`. When
`find_foreign_item` compares these declarations via
`compatible_fn_prototypes`, it cannot resolve the types semantically
(foreign items have no body, hence no typeck results), so it falls back to
a syntactic comparison: `*mut buf` vs `*mut buf` looks identical, even
though each refers to a different struct. The duplicate declaration is
dropped and all callers are pointed at the first one, so code written
against `buf_1` ends up passing it to a function expecting `*mut buf`:
error[E0308]: mismatched types
Type comparison lets a zero-length array match an array of any length. That leniency exists so an `extern` array declaration, whose omitted C length we translate as 0, can match its definition — but it also leaked into function signature comparison, where `*mut [c_int; 0]` and `*mut [c_int; 4]` are distinct, non-coercible types. As a result, `test_reorganize_foreign_fn_rename` merged two different `compute` declarations and rewrote a call to pass an argument of the wrong type. Add an `exact_array_lens` flag to `TypeCompare`: off by default so extern arrays still match their definitions, and turned on by `compatible_fn_sigs` and `compatible_fn_prototypes` so array lengths anywhere in a signature must match exactly.
`find_foreign_item` compared foreign functions via `compatible_fn_prototypes`, which resolves parameters through `opt_node_type` — but foreign items have no typeck results, so declarations from different modules that were merely spelled alike merged, and callers of the dropped one were rewritten to a function taking a different type. Compare with `compatible_fn_sigs` instead, matching what `match_exports` already does for external functions. The syntactic path remains as a fallback for signatures that will not resolve, which is why the earlier arity check still matters.
7899fc2 to
b19824c
Compare
There are now more details in the comment that cover this case.
Is that relevant? Anyway, E0308 is |
| /// after types were resolved. | ||
| def_mapping: Option<&'b DefMapping>, | ||
|
|
||
| /// Require array lengths to match exactly, instead of letting a |
There was a problem hiding this comment.
This is a fix for a pre-existing array issue that is now exposed by the more accurate signature comparison. I'm starting to think it should be its own separate PR, but in either case it needs to lands first. Thoughts?
Stack created with GitHub Stacks CLI • Give Feedback 💬
Some relevant output from Claude: