Skip to content

Conversation

anforowicz
Copy link
Contributor

PTAL?

This PR fixes https://crbug.com/433254489 (/cc @ShabbyX as FYI - IIUC they've patched this PR onto their local machine and verified that it does indeed unblock them).

The first commit fixes some existing code duplication and prevents more code duplication around how fn syntax::parse_items consumes a syntax::Module. I think this commit is okay and moves things in a reasonable direction, but I acknowledge that adding more partial consumption/destructuring/taking is a bit icky. More discussion about this aspect of the changes can be found in a comment from a semi-internal review at anforowicz#2 (comment) and anforowicz#2 (comment).

I also note that some existing variants of syntax::Api enum have Rust and C++ versions - e.g. RustFunction and CxxFunction as well as RustType and CxxType. We could also do that for the TypeAlias variant which this PR doesn't touch just yet. Please provide feedback on whether I should also submit an additional commit into this or a separate PR - see https://github.com/anforowicz/cxx/tree/api-rust-type-alias-separate-variant

/cc @zetafunction who has kindly provided initial, semi-internal feedback at anforowicz#2

`syntax::parse::parse_items` is currently called from two places:
from `macro/src/expand.rs` and from `gen/src/mod.rs`.  (In the future
it may be also called from a `syntax/test_support.rs` helper.)

Before this commit, all those places had to destructure/interpret
a `syntax::file::Module` into `content`, `namespace`, and `trusted`.

After this commit, this destructuring/interpretation is deduplicated
into `syntax::parse::parse_items`.  This requires some minor gymnastics:

* `gen/src/mod.rs` has to call `std::mem::take(&mut bridge.attrs)`
  instead of doing a partial destructuring and passing `bridge.attrs`
  directly.  This is an extra complexity, but we already do the same
  thing in `macro/src/expand.rs` before this commit, so hopefully this
  is ok.
* `fn parse_items` takes `&mut Module` rather than `Module` and
  "consumes" / `std::mem::take`s `module.content`, because
  `macro/src/expand.rs` needs to retain ownership of other `Module`
  fields.  This also seems like an unfortunate extra complexity, but
  (again) before this commit we already do this for `bridge.attrs` in
  `macro/src/expand.rs`.
Before this commit `fn parse_apis` in `syntax/test_support.rs` would
ignore the namespace in `#[cxx::bridge(namespace = "ignored")]`.
In other words, the new test added in `syntax/namespace.rs` would
fail before this commit.  This commit fixes this.

At a high-level this commit:

* Moves two pieces of code from `gen/src/file.rs` into `syntax/...`
  to make them reusable from `syntax/test_support.rs`:
    - `fn find_cxx_bridge_attr` (moved into `syntax/attrs.rs`)
    - `Namespace::parse_attr` (moved into
      `syntax/namespace.rs`)
* Reuses these pieces of code from `syntax/test_support.rs`
* Renames `Namespace::parse_bridge_attr_namespace` to
  `Namespace::parse_stream` so that all 3 parse methods are named
  after their input: `parse_attr`, `parse_stream`, `parse_meta`.
* Adds a `syntax/`-level unit test that verifies that the namespace
  is indeed getting correctly parsed and propagated
@@ -163,3 +163,46 @@ mod ffi {

Bounds on a lifetime (like `<'a, 'b: 'a>`) are not currently supported. Nor are
type parameters or where-clauses.

## Reusing existing binding types
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reusing an existing defined pair of C++ and Rust type is already supported. I don't understand the distinction between the extern C++ type aliases which are already supported, and the extern Rust type aliases in this PR. What is the situation where it would be correct to write extern "Rust" { type T = path::to::U; } and not extern "C++" { type T = path::to::U; }?

verify
verify
}
Lang::Rust => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not sufficient for safety. Consider adding:

        // inside extern "Rust"
        type Any = crate::module::CrossModuleRustType;
        fn repro(bad: &mut CrossModuleRustType) -> &mut Any;
...

fn repro(bad: &mut ffi::CrossModuleRustType) -> &mut ffi::Any {
    bad
}

Nothing here enforces what type the C++ Any is. We can make it anything:

namespace tests {
using Any = std::array<char, 1000>;
}

and arbitrarily stomp on memory.

repro(*r_boxed_cross_module_rust_type(123)).fill('?');
     Running tests/test.rs (target/debug/deps/test-f2f5723622a08a56)

running 15 tests
free(): invalid next size (fast)
malloc(): corrupted top size
error: test failed, to rerun pass `--test test`

Caused by:
  process didn't exit successfully: `target/debug/deps/test-f2f5723622a08a56` (signal: 6, SIGABRT: process abort signal)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants