-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add new lint macros_hiding_unsafe_code
#7469
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
Conversation
This lint only triggers if the `unsafe_op_in_unsafe_fn` lint is enabled. This lint is placed in the restriction group, since it suggests code, that requires to allow the `unused_unsafe` lint locally. Instead of allowing this lint, the unsafe block in the macro could be removed.
b409333
to
eba8a3a
Compare
r? @camsteffen (highfive down again? 🤔) |
) { | ||
if is_unsafe_fn(fn_kind) { | ||
self.in_unsafe_fn = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be adjusted for nested functions.
unsafe fn f() {
fn g() {}
unsafe_macro!();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right. Your example shouldn't break this code, but
unsafe fn f() {
unsafe fn g() {}
unsafe_macro!();
}
will.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I totally like the idea of this lint, I think its design should be thought through a bit more carefully.
This lint should not suggest anything a user normally won't do.
Additionally, if some library has such a macro already, dependent crates will have no choice but to either get rid of dependency or add a bunch of allow(...)
, since they can't directly fix the issue.
Logically, it's the macro fault that it hides unsafe
code, so the lint should be placed on the macro. Not sure whether it can be implemented though.
/// itself. This lint only triggers in functions where the `unsafe_op_in_unsafe_fn` lint is | ||
/// enabled. | ||
/// | ||
/// **Why is this bad?** This hides an unsafe operation inside a macro call. This is against |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that being against the intention of lint is a strong motivation since it's the nature of the lint to catch what it's supposed to catch. Like, chicken and egg problem.
I'd emphasize that the macro containing an unsafe can hide the fact that it uses unsafe, and thus makes it easier to use in the context where required invariants are not held.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I'll word this differently.
/// **Known problems:** | ||
/// - In some cases the intention of the macro is to actually hide the unsafety, because the | ||
/// macro itself ensures the safety of the `unsafe` operation. | ||
/// - For local macros, either an `#[allow(unused_unsafe)]` has to be added to the new unsafe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, suggesting introducing an unused unsafe block is not a good thing to do; and suggesting allow(unused_unsafe)
is worse.
Imagine the following chain of actions:
- Someone introduces a macro with an unsafe code.
- In the use places it gets wrapped with
#[allow(unused_unsafe)] unsafe { ... }
. - Unsafe code is removed from macro.
There is a good chance that this unused_unsafe
will remain there unnoticed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I also think this isn't nice. But I don't really see how else to handle this, without rendering the lint completely useless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When implementing the lint and noticing, that this is necessary, I also thought about whether we should allow lints that contradict rustc
lints at all. We have lints contradicting other Clippy lints in the restriction
group. But we don't have lints that contradict rustc
lints (yet).
☔ The latest upstream changes (presumably #7403) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm also not really satisfied with how the lint currently behaves.
I don't think this is a problem. I placed this lint in We could just not lint on external macros, but as I just explained, this lint is supposed to restrict what you can and cannot do with macros that hide unsafe code, no matter the origin.
With that, I think you would run into the problem with dependent crates. If you would lint a macro definition and tell the user to remove an We could just not lint exported macros, but I'm not even sure if we're able to lint macro definitions at all, since Clippy is run after macro expansion. |
I'll address all comments and further lint design decisions once we have consensus on how the lint should behave. |
Actually, I think that's the way it should work. If the crate author thinks that |
I see this lint as an extra precaution for macro users. Library authors with macros should not worry about triggering the lint, and they should not For the lint suggestion, I'm not sure it makes sense to add an unsafe block to appease this lint when it will be deemed unused by rustc. I think it would be better to just allow the lint? This also can be a lint that you run manually to see what you see and just ignore the false positives. I see this lint as being in conflict with rustc's unsafe rules, in its false positive cases, so there is no "fix" to be made. |
Another reason to not suggest adding |
Thanks for all the input! What do you think about suggesting to add an
But for local macros the correct fix would be to either remove the |
Sounds reasonable to me. |
For local macros, yes I agree. For external macros, I guess it is more reasonable to add
|
I think |
The
Ah yes, thanks for the better name! Now I know what irritated me with the name that I chose 😄 |
Huh. Isn't that a bug? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This has been open way to long with no update by me. This is pretty low on my priority list, so I'm closing it for now, maybe I'll get back to it some time in the future. |
This lint only triggers if the
unsafe_op_in_unsafe_fn
lint is enabled.This lint is placed in the restriction group, since it suggests code,
that requires to allow the
unused_unsafe
lint locally. Instead ofallowing this lint, the unsafe block in the macro could be removed.
Closes #7323
changelog: Add new lint [
macros_hiding_unsafe_code
]