Skip to content

Don't bridge a layout-compatible std::string by value. - #2043

Open
copybara-service[bot] wants to merge 1 commit into
mainfrom
test_982803522
Open

copybara-service[bot] wants to merge 1 commit into
mainfrom
test_982803522

Conversation

@copybara-service

Copy link
Copy Markdown

Don't bridge a layout-compatible std::string by value.

Under layout_compat_string, a C++ std::string is spelled in Rust as
cc_std::std::string: a !Unpin, PinnedDrop type which lives in place and is
only ever produced through a Ctor.

Bridging works by memcpy'ing a value through a byte buffer, so every part of a
bridged type has to be Rust-movable. cc_std::std::string is not. Until now,
the two halves of the decision disagreed: the spelling of the type honored
layout_compat_string and said string, while the ABI ignored the feature
and boxed, producing a string_wrapper. A std::string nested inside a bridged
container -- std::optional<std::string>, std::pair<std::string, T> -- would
therefore emit generated code which does not compile, taking the whole target
down with it.

Refuse to bind those functions instead. This mirrors what already happens for a
user-defined non-Rust-movable type in the same position:

Type `Foo` must be Rust-movable in order to memcpy through a bridge buffer.

std::string was the one type that silently boxed rather than reporting the
problem. Now the cost of a nested layout-compatible std::string is limited to
the individual functions which mention it, and, as always, an API annotated with
CRUBIT_MUST_BIND still escalates it to a hard error.

The fix for an API caught by this is to make the containing type
layout-compatible as well, so that it is never bridged by value. For
absl::StatusOr<std::string> that is CRUBIT_NEW_STATUS, which the new test
covers.

Under `layout_compat_string`, a C++ `std::string` is spelled in Rust as
`cc_std::std::string`: a `!Unpin`, `PinnedDrop` type which lives in place and is
only ever produced through a `Ctor`.

Bridging works by memcpy'ing a value through a byte buffer, so every part of a
bridged type has to be Rust-movable. `cc_std::std::string` is not. Until now,
the two halves of the decision disagreed: the *spelling* of the type honored
`layout_compat_string` and said `string`, while the *ABI* ignored the feature
and boxed, producing a `string_wrapper`. A `std::string` nested inside a bridged
container -- `std::optional<std::string>`, `std::pair<std::string, T>` -- would
therefore emit generated code which does not compile, taking the whole target
down with it.

Refuse to bind those functions instead. This mirrors what already happens for a
user-defined non-Rust-movable type in the same position:

    Type `Foo` must be Rust-movable in order to memcpy through a bridge buffer.

`std::string` was the one type that silently boxed rather than reporting the
problem. Now the cost of a nested layout-compatible `std::string` is limited to
the individual functions which mention it, and, as always, an API annotated with
`CRUBIT_MUST_BIND` still escalates it to a hard error.

The fix for an API caught by this is to make the *containing* type
layout-compatible as well, so that it is never bridged by value. For
`absl::StatusOr<std::string>` that is `CRUBIT_NEW_STATUS`, which the new test
covers.

PiperOrigin-RevId: 982803522
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.

1 participant