-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dead code pass no longer considers enum used in pub extern "C" fn
as used
#126706
Comments
Also tagging T-lang on this because this involves user-observable changes to the |
Just updated to the latest nightly and came across another similar regression: // src/lib.rs
pub mod module {
#[repr(C)]
pub struct Foo(u32);
} No warning on stable 1.79.0 Has a warning on latest nightly (I haven't bisected) Stable (no warning) -> https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=08aa241f1e1544fae1c50f66d16c94f6 Here is the output on Compiling playground v0.0.1 (/playground)
warning: struct `Foo` is never constructed
--> src/main.rs:4:16
|
4 | pub struct Foo(u32);
| ^^^
|
= note: `#[warn(dead_code)]` on by default
warning: `playground` (bin "playground") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.38s
Running `target/debug/playground` Ah, actually the Here's an illustration of code that we don't want to lead to a warning, but does on latest nightly. // crate `foo`'s src/lib.rs
#[repr(C)]
pub struct Foo(u32);
impl Foo{
pub fn print(&self) {
println!("{}", self.0)
}
} It isn't dead code because another crate might use // In another crate that depends on crate `foo` above
#[no_mangle)
pub extern "C" fn print_foo(foo: Foo) {
foo.print();
} |
Regarding the original report, this doesn't seem related to mod private_mod {
pub enum MyEnum {
Variant(u32)
//~^ WARN field `0` is never read
}
pub fn some_function() -> MyEnum {
MyEnum::Variant(5)
}
}
fn main() {
let _ = private_mod::some_function();
} And the warning is correct. The field is never read. If you read the field, the warning goes away, both here and in your original example. Regarding your second example, the warning there also seems correct. The // lib.rs
pub struct Foo(pub u32); //~ No warning If this analysis understands your report correctly and you agree there's no issue here, then please close the issue. |
The analysis misunderstands the problem. In both my first and second example there is a dead code warning for code that is not dead (note that this is the The reason that the In your example code that removes the If you add Recall that the error says:
When the I'm going to add a mod foo {
#[repr(C)]
pub struct Foo(pub u32);
impl Foo {
pub fn new(val: u32) -> Self {
Self(val)
}
}
pub extern "C" fn return_foo() -> Foo {
Foo(5);
}
// Doubles the value held inside `Foo`
extern "C" {
fn double_foo(foo: Foo) -> Foo;
}
}
fn main() {
let foo = Foo::new(10);
// Good. We only want Rust callers to be able to double `Foo`.
// We don't want them to be able to do anything else.
let foo = unsafe { foo::double_foo(foo) };
// BAD: We don't want `Foo`'s internal to be accessible outside of `mod foo`.
// To solve this, we need to change `pub struct Foo(pub u32)` to `pub struct Foo(u32)`.
foo.0 = 18;
} In this example your suggestion changes the semantics of the program.
The simplify: The reason that this // src/lib.rs
pub function bazz() {} Similarly, the reason that the |
Note that this gives us warning: mod foo {
#[repr(C)]
pub enum MyEnum {
Variant(u32)
}
#[no_mangle]
pub extern "C" fn make_enum() -> MyEnum {
MyEnum::Variant(10)
}
}
fn main() { But this does not warn: // src/lib.rs
pub enum MyEnum {
Variant(u32)
} In the second example Similarly, the Hoping that all of the above clearly illustrates the problem. |
Regarding your first example, is it correct to say that you believe that this should not warn?: // lib.rs
#[repr(C, u8)]
enum MyEnum {
Variant { inner: u8 },
//~^ WARN field `inner` is never read
}
#[no_mangle]
extern "C" fn some_function() -> MyEnum {
MyEnum::Variant { inner: 0 }
} ...under the interpretation that the (According to Godbolt, this program has always produced a warning, which isn't to say whether that's correct or not.) |
Regarding your second example, is it correct to say that you believe that this should not warn: // lib.rs
#[repr(transparent)]
pub struct Foo {
//~^ WARN struct `Foo` is never constructed
inner: u8,
}
impl Foo {
pub fn print(&self) {
println!("{}", self.inner)
}
} ...because a downstream crate could do this?: fn main() {
let x: Foo = unsafe { core::mem::transmute(0u8) };
x.print();
} Note that this warning is in beta as well as nightly. |
You are getting The following does not give a warning: [toolchain]
# arbitrarily chosen nightly from before this regression
channel = "nightly-2024-03-01" // src/lib.rs
// This DOES NOT give a warning (`nightly-2024-03-01`)
#[repr(C, u8)]
pub enum MyEnum {
Variant { inner: u8 },
}
#[no_mangle]
pub extern "C" fn some_function() -> MyEnum {
MyEnum::Variant { inner: 0 }
} I also checked So, this has all worked properly for at least the last 6 years until a recent regression. For your second question about the According to the nomicon, "the goal of repr(transparent) is to make it possible to transmute between the single field and the struct/enum". So, since More simply:
Note that your The following does not warn in // lib.rs
pub struct Foo {
inner: u8,
}
impl Foo {
pub fn print(&self) {
println!("{}", self.inner)
}
} This is an improvement. The following would solve the original issue:
Then to fix
|
Regarding the first example, with your revision: // lib.rs
#[repr(C, u8)]
pub enum MyEnum {
Variant { inner: u8 },
}
#[no_mangle]
pub extern "C" fn some_function() -> MyEnum {
MyEnum::Variant { inner: 0 }
} This does not warn in the latest nightly either: So I'm unclear what you're trying to say here, and I'm still curious if you think the version I gave should warn, as that's spiritually similar to your original example that used a private module. Regarding the second example: // lib.rs
#[repr(transparent)]
pub struct Foo {
//~^ WARN struct `Foo` is never constructed
inner: u8,
}
impl Foo {
pub fn print(&self) {
println!("{}", self.inner)
}
} Since
Can you point us at any documentation or earlier decisions that we've made that would suggest that this should be supported? |
Oops, I meant: // warns on 2024-07-01
// does not warn on 2024-03-01
mod private_mod {
#[repr(C, u8)]
pub enum MyEnum {
Variant { inner: u8 },
}
#[no_mangle]
pub extern "C" fn some_function() -> MyEnum {
MyEnum::Variant { inner: 0 }
}
} The above warns in Regarding your question about
I don't not whether a non-pub I can't point to earlier documentation or decisions. Your counterpoint is reasonable. I would have to think more deeply about this to know where I stand. This is not a problem that I have faced. I do not currently have evidence of real code that would run into this I'd like to remain focused on Reasons:
So, here is exactly what I would prefer this issue to remain focused on: // This should not warn
mod private_mod {
#[repr(C)]
pub enum MyEnum {
Variant(u8)
}
#[no_mangle]
pub extern "C" fn some_function() -> MyEnum {
MyEnum::Variant(5)
}
} If we agree that this should not produce a warning, then I'd like to move forward to selecting a solution. If you believe that this should produce a warning, please state why. I am unclear on where you stand on this specific example. |
Here's a comparison of the behaviors of some different cases: I would expect I'd be interested to hear whether there are any reasons that the first set ( I'm interested to hear what others think here about the situation and the proper behavior. |
cc @mu001999 |
Before reading the comments deeply, these are my opinions:
|
There is a related issue (#126169) about the example in #126706 (comment) |
@shepmaster IIUC, this is not true, there is some logic for In short, fields will be marked live if there is a |
You are right, I should have been more specific — I wish that the lint's logic did not involve |
@shepmaster oic, I agree with #126706 (comment). And in fact |
It seems like having As in
@mu001999 would you be willing to mentor me towards implementing this? I could start by submitting a PR that either gets it working or gets close, and then you could review and answer any questions that I might leave for you in the PR? Then if this issue reaches a clear consensus on the |
This is not the mindset I would use: Footnotes
|
It does seem unfortunate to have |
Shepmaster I'm not sure that we're on the same page. Are you suggesting that once a type is exposed by a For instance, are you suggesting that the following should not produce a "field // This SHOULD warn that field 0 is never read
mod private_mod {
pub enum MyEnum {
Variant(Vec<u8>)
}
#[no_mangle]
pub fn new_bar() -> MyEnum {
MyEnum::Variant(vec![5])
}
} I am suggesting that the above code snippet should still produce a warning (of some sort .. maybe a different one ..), If it is being read it's because the user is depending on an unspecified memory layout. The reason that // This SHOULD NOT warn that field 0 is never read
mod private_mod {
#[repr(C)]
pub enum MyEnumC {
Variant(u32)
}
#[no_mangle]
pub extern "C" fn new_bar() -> MyEnumC {
MyEnumC::Variant(5)
}
} I am suggesting that in this second code snippet we have given enough of a signal for the linter to treat the So, it should treat the The reason that I'm treating The other cases like having no repr at all, having Of course I'm a bit biased towards carving out a solution for If you can point to where you disagree with the above then I think we'll be on the same page. It seems like you've addressed something like this before, so feel free to link me to previous discussions and I'll happily read them. |
@chinedufn thanks, I am not the member of compiler team so I don't have the access to approve. But I will have a look if you open such a PR. I think So And for current dead code lint, |
I'm not entirely sure, but it seems like #128404 will close this issue. Conversation that led to that PR -> #127104 (comment) |
that's not true, those changes are not in 1.79 |
A repository that I maintain recently received a bug report about our proc macro generating a warning after they upgraded to
1.79.0
.I haven't bisected for the exact commit that introduces the warning, but I have been able to reproduce it in
1.79.0
.Minimal Reproduction
In the playground -> https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3f5c81c0749130a6e46fbea14cbb055f
Potential Candidates
This comment links to some
rustc
commits that may have introduced the issue chinedufn/swift-bridge#278 (comment)As mentioned, I haven't taken the time to bisect since I know that it's possible that a core maintainer already has a good sense of when/how this regression could have been introduced.
The text was updated successfully, but these errors were encountered: