-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Added lint for #[deriving] structs and enums with unsafe pointers #13108
Conversation
Awesome work! (I'll review.) (Don't worry about the travis failure, it seems unrelated.) |
fn check_struct_def(cx: &Context, def: &ast::StructDef) { | ||
for field in def.fields.iter() { | ||
match field.node.ty.node { | ||
ast::TyPtr(..) => cx.span_lint(RawPointerDeriving, field.span, "use of #[deriving] with a raw pointer"), |
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.
This line is too long; maybe you could factor out the error message to a static like
fn check_raw_pointer_deriving(...) {
static MSG: &'static str = "use of `#[deriving]` with a raw pointer";
fn check_struct_def(...) {
/* ... */
ast::TyPtr(..) => cx.span_lint(RawPointerDeriving, field.span, MSG)
/* ... */
}
/* ... */
}
(Even with this factored out the line below will be too long, you can break it over multiple lines via
ast::TyPtr(..) => {
cx.span_lint(RawPointerDeriving, variant.span, MSG);
}
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.
Oh, also, this would preferably point to the type itself, i.e., field.node.ty.span
, rather than field.span
. (And below with var_arg.ty.span
.)
Looks pretty good; although I have some comments, and this needs some tests, example; it should be a test that includes the for casts: structs, tuple structs, enums and struct enum variants, i.e. #[feature(struct_variants)];
#[allow(dead_code)];
#[deny(raw_pointer_deriving)];
#[deriving(Clone)]
struct Foo {
x: *int //~ ERROR #[deriving] with raw pointer
}
#[deriving(Clone)]
struct Bar(*mut int); //~ ERROR #[deriving] with raw pointer
enum Baz {
A(*int), //~ ERROR #[deriving] with raw pointer
B { x: *mut int } //~ ERROR #[deriving] with raw pointer
}
fn main() {} |
Oh something I just thought about: I guess this really needs to walk the types, not just look at their outer layers, e.g. the following should probably be warned about struct Foo {
x: (*int, *uint)
} This could be done by creating a new struct RawPtrDerivingVisitor<'a> {
cx: &'a mut Context
}
impl<'a> Visitor<()> for RawPtrDerivingVisitor<'a> {
fn visit_ty(&mut self, ty: &ast::Ty, _: ()) {
/* check `ty` is a TyPtr, if so, span_lint on this type */
// recurse, to walk the interiors of other types
visit::walk_ty(self, ty, ());
}
// explicit override to a no-op these to reduce code bloat
fn visit_expr(&mut self, e: &ast::Expr, _: ()) {}
fn visit_block(&mut self, e: &ast::Block, _: ()) {}
}
fn check_raw_ptr_deriving(cx: &mut Context, item: &Item) {
// ... do the attribute check ...
match item {
ItemStruct(..) | ItemEnum(..) => {
let mut visitor = RawPtrDerivingVisitor { cx: cx };
visit::walk_item(&mut visitor, item, ());
}
}
} This has a few advantages:
(Sorry for changing to a completely different tack to the one I talked to you about on IRC. :( ) |
@huonw I'll work on these the next time I have free time :D. By the way, if I have structs A and B, both of which contain struct X. Will X be visited once or three times (X itself, through A, then through B)? If ti's three times, we might get exponential run time... I don't know enough about Visitor to tell. |
Oh, sorry, I wasn't clear: it's just visiting the AST itself, not resolving the definitions and then visiting those too, so for something like struct X { r: int }
struct A { s: X, t: *int }
struct B { u: Option<*uint>, v: X, w: A } A visitor would, in order (sorry for the hard-to-read formatting, I've tried to write it to look like the tree of calls that the visitor would perform):
( That is, the visitor only visits things written directly inline in the The "shallow-visiting" is exactly what we want here: we assume that raw pointers that are "hidden" inside some other struct/enum definitions are managed by a correct (This new scheme does create a some rare false positives, for example: #[deriving(Clone)]
struct Foo {
x: Rc<*int>
} The |
Fixed! |
Fix `redundant_closure` false positive with closures has return type contains `'static` Fix rust-lang#13073 . Please enable "ignore white-space change" settings in github UI for easy reviewing. HACK: The third commit contains a hack to check if a type `T: 'static` when `fn() -> U where U: 'static`. I don't have a clean way to check for it. changelog: [`redundant_closure`] Fix false positive with closures has return type contains `'static`
Fixes #13032