If the #[derive(Debug)] line is removed out, like so:
#![deny(unused)]
fn main() {
struct NotNeeded;
}
then the compile fails with this error, as expected.
error: struct is never constructed: `NotNeeded`
--> src/main.rs:3:12
|
3 | struct NotNeeded;
| ^^^^^^^^^
|
It appears at first that rustc cannot tell that the struct is used if the struct implements a trait. But I tried the following and I get a compile error as expected:
These results leads me to think that the compiler cannot tell a struct is unused, if it implements an external trait.
Why is this the case? Is this an as yet undiscovered bug, a known limitation that is meant to be fixed eventually, or is there some reason that it has to be this way?
I personally think this might be considered a bug, but I’m not sure. What I am sure about is that I need to correct your observations: the difference between Default and Foo in your example is not about external vs non-external traits but that Default contains a method that constructs a value of type NotNeeded if it is ever called (which it isn’t and that’s what the compiler seems to be missing).
which does complain about bothbar()andNotNeeded being unused, my conclusion is that Rust seems to never interpret trait methods as being unused.
I can make sense of this since especially for an external trait, you might never call a particular one (of many) trait methods on a private type, but you still need to define it to make your type instance that trait. In this case you wouldn’t want an unused warning. I guess some improvement could be made by changing the analysis to just not report a trait method being unused but still do the analysis so that the compiler could still conclusions such as, in particular, that a type is never constructed.
Additionally or alternatively I could imagine an analysis that creates a warning whenever a trait implementation on a private type is not actually needed/used anywhere, although that might be problematic, too, since then the compiler would give you warnings about unused Debug impl’s on your private types all the time, etc. But still, such an analysis might be an alternative to a potentially difficult method-by-method analysis, which allows the compiler, even if it doesn’t produce any warnings, to conclude that a type is actually unused if it is only constructed in an unused trait-impl.
But I must still admit that you are correct that a trait does not need to be external to cause a lack of warnings, and that I had missed that. However, that doesn't explain why #[derive(Debug)] also caused a lack of warnings. If I implement Debug manually like so:
So, at this point I think that no warnings are produced if a struct implements a trait where one of the methods takes as a parameter or returns an instance of the struct in question.