Skip to content

lint on core::ffi::c_void as a return type - #156379

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
euclio:c-void-returns
Jul 1, 2026
Merged

lint on core::ffi::c_void as a return type#156379
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
euclio:c-void-returns

Conversation

@euclio

@euclio euclio commented May 10, 2026

Copy link
Copy Markdown
Contributor

View all comments

Fixes #100972.

This PR introduces a new deny-by-default warn-by-default lint c_void_returns that fires on usage of core::ffi::c_void as a return type. This is never correct, and is a potential stumbling block for users coming from C.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 10, 2026
@rustbot

rustbot commented May 10, 2026

Copy link
Copy Markdown
Collaborator

r? @TaKO8Ki

rustbot has assigned @TaKO8Ki.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 18 candidates

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Kivooeo

Kivooeo commented May 10, 2026

Copy link
Copy Markdown
Member

why is deny by default? what about things like bindgen that generates bindgings from c code?

@Urgau Urgau added the I-lang-nominated Nominated for discussion during a lang team meeting. label May 10, 2026
@asquared31415

Copy link
Copy Markdown
Contributor

You're never meant to have a value of type c_void, it's only meant to be used in raw pointers, as an equivalent to void*. () is the equivalent to returning void.

in fact I expect that UB arises from the internal implementation details if you have a void meow() and call it as fn meow() -> c_void because the rust c_void type actually is not zero sized for Internal Reasons.

@Kivooeo

Kivooeo commented May 10, 2026

Copy link
Copy Markdown
Member

I'd suggest warn rather than deny by default for a few reasons:

  • Using c_void as a return type in extern blocks is extremely common pattern in existing FFI code and bindgen output
  • Even outside extern blocks, there are plenty cases show real-world code that would break, and while the pattern is incorrect, making it a hard error seems like a high bar for ecosystem disruption
  • warn would still surface the issue without being a breaking change. In a future edition it could be escalated to deny, but only for functions outside extern blocks, the cascading wrapper case shows that blindly denying it everywhere creates unnecessary churn in FFI-heavy codebases

@asquared31415

asquared31415 commented May 11, 2026

Copy link
Copy Markdown
Contributor

I believe that every single one of those cases that are defining a -> c_void { ... } function are relying on internal details and so it's not currently UB, but could be in the future.

All the cases that are declaring a -> c_void; function are currently UB (and will almost certainly always remain UB) to link to a -> () (or C -> void), and on top of that, this UB cannot be detected in most of those cases, because miri won't support the typical use cases. I believe that a deny by default lint here is more than warranted.

Additionally, the c_void docs explicitly say "this is not the same as C’s void return type, which is Rust’s () type."

here is an example of a case where miri can detect the UB, but this is rarely possible.

@Kivooeo

Kivooeo commented May 11, 2026

Copy link
Copy Markdown
Member

As I noted earlier, I agree this pattern is incorrect. My concern is primarily about ecosystem impact - a GitHub search returns over 1,000 instances of this pattern, including in production codebases from organizations like Microsoft and Azure.

Making this deny by default would break these codebases on the next compiler update with no warning period. warn by default would still surface the issue while giving the ecosystem time to adapt.

@traviscross traviscross added P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang I-lang-radar Items that are on lang's radar and will need eventual work or consideration. T-lang Relevant to the language team labels May 13, 2026
Comment thread compiler/rustc_lint/src/c_void_returns.rs Outdated
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 13, 2026
@rustbot

rustbot commented May 13, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@joshtriplett

Copy link
Copy Markdown
Member

Looks reasonable. We'd like to start with warn at first, and ramp up to deny after a couple of releases.

@rfcbot merge lang

@rust-rfcbot

rust-rfcbot commented May 13, 2026

Copy link
Copy Markdown
Collaborator

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rust-rfcbot rust-rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels May 13, 2026
@traviscross

Copy link
Copy Markdown
Contributor

Thanks @euclio.

@rfcbot reviewed

@tmandry

tmandry commented May 13, 2026

Copy link
Copy Markdown
Member

@rfcbot reviewed

@rust-rfcbot rust-rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels May 13, 2026
@rust-rfcbot

Copy link
Copy Markdown
Collaborator

🔔 This is now entering its final comment period, as per the review above. 🔔

@rust-rfcbot rust-rfcbot added the to-announce Announce this issue on triage meeting label May 23, 2026
@rust-rfcbot

Copy link
Copy Markdown
Collaborator

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

@rust-bors

This comment has been minimized.

@rustbot

This comment has been minimized.

@rust-bors

This comment has been minimized.

@theemathas

Copy link
Copy Markdown
Contributor

@rustbot reroll

@rustbot rustbot assigned mati865 and unassigned TaKO8Ki Jun 28, 2026

@mati865 mati865 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, looks good but needs a rebase.

View changes since this review

@rustbot

rustbot commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@euclio

euclio commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@mati865 Rebased.

@mati865

mati865 commented Jun 30, 2026

Copy link
Copy Markdown
Member

@bors r+

@rust-bors

rust-bors Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

📌 Commit b268dee has been approved by mati865

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 1. This pull request will be tested once the tree is reopened.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 30, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jun 30, 2026
lint on `core::ffi::c_void` as a return type

Fixes rust-lang#100972.

This PR introduces a new ~deny-by-default~ warn-by-default lint `c_void_returns` that fires on usage of `core::ffi::c_void` as a return type. This is never correct, and is a potential stumbling block for users coming from C.
rust-bors Bot pushed a commit that referenced this pull request Jun 30, 2026
…uwer

Rollup of 3 pull requests

Successful merges:

 - #156379 (lint on `core::ffi::c_void` as a return type)
 - #157347 (Implement `Box::as_non_null()`.)
 - #158614 (Fix error message when rejecting implicit stage != 2 in CI)
rust-bors Bot pushed a commit that referenced this pull request Jun 30, 2026
…uwer

Rollup of 7 pull requests

Successful merges:

 - #156379 (lint on `core::ffi::c_void` as a return type)
 - #157347 (Implement `Box::as_non_null()`.)
 - #157650 (rustc_target: Add OpenEmbedded/Yocto Linux base targets)
 - #158569 ([rustdoc] Fix handling of inlining of `no_inline` of foreign items)
 - #158573 (stabilize `feature(atomic_from_mut)`)
 - #158614 (Fix error message when rejecting implicit stage != 2 in CI)
 - #158616 (Remove dependency from `rustc_metadata` on `rustc_incremental`)
@rust-bors
rust-bors Bot merged commit 0c72496 into rust-lang:main Jul 1, 2026
13 checks passed
rust-timer added a commit that referenced this pull request Jul 1, 2026
Rollup merge of #156379 - euclio:c-void-returns, r=mati865

lint on `core::ffi::c_void` as a return type

Fixes #100972.

This PR introduces a new ~deny-by-default~ warn-by-default lint `c_void_returns` that fires on usage of `core::ffi::c_void` as a return type. This is never correct, and is a potential stumbling block for users coming from C.
@rustbot rustbot added this to the 1.98.0 milestone Jul 1, 2026
bjorn3 pushed a commit to bjorn3/miri that referenced this pull request Jul 1, 2026
…uwer

Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#156379 (lint on `core::ffi::c_void` as a return type)
 - rust-lang/rust#157347 (Implement `Box::as_non_null()`.)
 - rust-lang/rust#157650 (rustc_target: Add OpenEmbedded/Yocto Linux base targets)
 - rust-lang/rust#158569 ([rustdoc] Fix handling of inlining of `no_inline` of foreign items)
 - rust-lang/rust#158573 (stabilize `feature(atomic_from_mut)`)
 - rust-lang/rust#158614 (Fix error message when rejecting implicit stage != 2 in CI)
 - rust-lang/rust#158616 (Remove dependency from `rustc_metadata` on `rustc_incremental`)
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Aug 21, 2026
This MR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [rust](https://github.com/rust-lang/rust) | tools | minor | `1.97.1` → `1.98.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>rust-lang/rust (rust)</summary>

### [`v1.98.0`](https://github.com/rust-lang/rust/blob/HEAD/RELEASES.md#Version-1980-2026-08-20)

[Compare Source](rust-lang/rust@1.97.1...1.98.0)

\==========================

<a id="1.98.0-Language"></a>

## Language

- [Allow shortening lifetime of `&mut` when unsize-coercing, even in an invariant position.](rust-lang/rust#149219) For example, you can now coerce a `Cell<&'long mut i32>` to a `Cell<&'short mut dyn Send>`. Such shortenings were already previously allowed when coercing a `&mut` to a `&`, or coercing a `&` to a `&`.
- [Add deny-by-default `invalid_runtime_symbol_definitions` lint and warn-by-default `suspicious_runtime_symbol_definitions` lint](rust-lang/rust#155521)
  - The lints currently specifically targets `core` runtime symbols like `memcmp`, `memset`, `strlen`, ... and is planned to be expanded in the next few releases.
- [Add warn-by-default `c_void_returns` lint to check `core::ffi::c_void` as a return type](rust-lang/rust#156379)

<a id="1.98.0-Platform-Support"></a>

## Platform Support

- [Add `powerpc64-unknown-linux-gnuelfv2` as Tier 3](rust-lang/rust#144220)
- [Add `aarch64-unknown-linux-pauthtest` as Tier 3 target](rust-lang/rust#155722)
- [Promote `thumbv7a-none-eabi` to Tier 2](rust-lang/rust#155763)
- [Promote `thumbv7a-none-eabihf` to Tier 2](rust-lang/rust#155763)
- [Promote `thumbv7r-none-eabi` to Tier 2](rust-lang/rust#155763)
- [Promote `thumbv7r-none-eabihf` to Tier 2](rust-lang/rust#155763)
- [Promote `thumbv8r-none-eabihf` to Tier 2](rust-lang/rust#155763)

Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.

[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html

<a id="1.98.0-Libraries"></a>

## Libraries

- [Change `Location<'_>` lifetime to `'static` in `Panic[Hook]Info`](rust-lang/rust#146561)
- [Document panic in `RangeInclusive::from(legacy::RangeInclusive)`](rust-lang/rust#155421)
- [Document that `ManuallyDrop`'s `Box` interaction has been fixed](rust-lang/rust#155750)
- [Stabilize LoongArch CRC Intrinsics](rust-lang/rust#156908)
- [The `derive` macro is available at `{core,std}::derive`.](rust-lang/rust#154645) This was previously [unintentionally stabilized in 1.96](rust-lang/rust#159856), but is now [explicitly accepted](rust-lang/rust#154645) as a stabilized API.
  - Please note that the MSRV for `{core,std}::derive` will be 1.96, and not 1.98.

<a id="1.98.0-Stabilized-APIs"></a>

## Stabilized APIs

- [`str::substr_range`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.substr_range)
- [`[T]::subslice_range`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.subslice_range)
- [`core::fmt::NumBuffer`](https://doc.rust-lang.org/stable/core/fmt/struct.NumBuffer.html)
- [`<{integer}>::format_into`](https://doc.rust-lang.org/stable/core/primitive.usize.html#method.format_into)
- [`Send/Sync for std::process::CommandArgs`](https://doc.rust-lang.org/stable/std/process/struct.CommandArgs.html#impl-Send-for-CommandArgs%3C'a%3E)
- [`{fN}::algebraic_add`](https://doc.rust-lang.org/stable/core/primitive.f32.html#method.algebraic_add)
- [`{fN}::algebraic_sub`](https://doc.rust-lang.org/stable/core/primitive.f32.html#method.algebraic_sub)
- [`{fN}::algebraic_mul`](https://doc.rust-lang.org/stable/core/primitive.f32.html#method.algebraic_mul)
- [`{fN}::algebraic_div`](https://doc.rust-lang.org/stable/core/primitive.f32.html#method.algebraic_div)
- [`{fN}::algebraic_rem`](https://doc.rust-lang.org/stable/core/primitive.f32.html#method.algebraic_rem)
- [`NonZero<{integer}>::from_str_radix`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html#method.from_str_radix-4)
- [`String::from_utf16le`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf16le)
- [`String::from_utf16le_lossy`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf16le_lossy)
- [`String::from_utf16be`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf16be)
- [`String::from_utf16be_lossy`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf16be_lossy)
- [`[T]::strip_circumfix`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.strip_circumfix)
- [`str::strip_circumfix`](https://doc.rust-lang.org/stable/core/primitive.str.html#method.strip_circumfix)
- [`Atomic<T>::from_mut`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.Atomic.html#method.from_mut)
- [`Atomic<T>::get_mut_slice`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.Atomic.html#method.get_mut_slice)
- [`Atomic<T>::from_mut_slice`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.Atomic.html#method.from_mut_slice)
- [`std::range::legacy`](https://doc.rust-lang.org/stable/std/range/legacy/index.html)

<a id="1.98.0-Compatibility-Notes"></a>

## Compatibility Notes

- [If fully elided, lifetime bounds of trait object types may now resolve differently or even get rejected in very specific niche scenarios](rust-lang/rust#129543)
- [Error in more cases of ambiguous imports](rust-lang/rust#145108)
- [Switch the destructors implementation for thread locals on Windows to use Fiber Local Storage (FLS)](rust-lang/rust#148799)
- [Convert some cases of the `ambiguous_glob_imports` lint into a hard error](rust-lang/rust#149195)
- [Where-bounds of the form `Type = Type` and `Type == Type` are no longer syntactically allowed](rust-lang/rust#153513)
- [Ensure Send/Sync is not implemented for std::env::Vars{,Os}](rust-lang/rust#155153)
- [Fix that in some attributes, arguments were not properly rejected](rust-lang/rust#155193)
- [`repr(transparent)` is now more strict about which fields have "trivial" layout and hence can be ignored: `repr(C)` types, types with private fields, and `#[non_exhaustive]` types are no longer considered "trivial"](rust-lang/rust#155299)
- [Correctly check whether types have equal size in `transmute()` when some `repr` attributes are involved.](rust-lang/rust#155418)
- [More characters are escaped when printing strings and chars](rust-lang/rust#155527)
- [Implement fast path for `derive(PartialOrd)` when deriving `Ord`](rust-lang/rust#155598)
  This can break crates in practice where a type's PartialOrd and Ord impls were inconsistent with each other.
- [Add temporary scope to `assert_eq` and `assert_ne`](rust-lang/rust#155739)
- Closed a hole in the pattern matching [structural equality](https://doc.rust-lang.org/reference/patterns.html#constant-patterns) check, preventing cases where a match of a constant would be allowed, despite disagreeing with a manually written `PartialEq` implementation, when a `derive(PartialEq)` implementation for that type also exists.
- [On Emscripten the WASM exception handling ABI is now unconditionally used](rust-lang/rust#156928) The `-Zemscripten-wasm-eh=false` flag to switch back to JS exceptions has been removed.
- [The UNSAFE\_CODE lint is now consistently emitted for all unsafe attributes](rust-lang/rust#157201)
- [Solaris: remove `File::lock` implementation, it has the wrong semantics (return "unsupported" instead)](rust-lang/rust#157509)
- [Windows-gnu targets now specify baseline tools versions](rust-lang/rust#158020)
- [rustfmt now discovers module files that are defined in `cfg_select!`](rust-lang/rust#158372)
  This may cause more code to be formatted which was previously ignored.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODguMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team to-announce Announce this issue on triage meeting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trying to return c_void should suggest to return () instead