Make struct part of unrooted_must_root handle type parameters

This commit is contained in:
Manish Goregaokar 2015-07-21 23:24:42 +05:30
parent 511e3337fb
commit fda3eb6327
4 changed files with 40 additions and 28 deletions

View file

@ -57,6 +57,35 @@ fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) {
};
}
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
let mut ret = false;
ty.maybe_walk(|t| {
match t.sty {
ty::TyStruct(did, _) |
ty::TyEnum(did, _) => {
if cx.tcx.has_attr(did, "must_root") {
ret = true;
false
} else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
false
} else if match_def_path(cx, did, &["core", "cell", "Ref"])
|| match_def_path(cx, did, &["core", "cell", "RefMut"]) {
// Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
// since it will be rooted elsewhere
false
} else {
true
}
},
ty::TyBox(..) if in_new_function => false, // box in new() is okay
ty::TyRef(..) => false, // don't recurse down &ptrs
ty::TyRawPtr(..) => false, // don't recurse down *ptrs
_ => true
}
});
ret
}
impl LintPass for UnrootedPass {
fn get_lints(&self) -> LintArray {
lint_array!(UNROOTED_MUST_ROOT)
@ -74,8 +103,9 @@ impl LintPass for UnrootedPass {
};
if item.attrs.iter().all(|a| !a.check_name("must_root")) {
for ref field in def.fields.iter() {
lint_unrooted_ty(cx, &*field.node.ty,
"Type must be rooted, use #[must_root] on the struct definition to propagate");
if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
cx.span_lint(UNROOTED_MUST_ROOT, field.span, "Type must be rooted, use #[must_root] on the struct definition to propagate")
}
}
}
}
@ -168,31 +198,9 @@ impl LintPass for UnrootedPass {
};
let ty = cx.tcx.expr_ty(&*expr);
ty.maybe_walk(|t| {
match t.sty {
ty::TyStruct(did, _) |
ty::TyEnum(did, _) => {
if cx.tcx.has_attr(did, "must_root") {
cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
&format!("Expression of type {:?} in type {:?} must be rooted", t, ty));
false
} else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
false
} else if match_def_path(cx, did, &["core", "cell", "Ref"])
|| match_def_path(cx, did, &["core", "cell", "RefMut"]) {
// Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
// since it will be rooted elsewhere
false
} else {
true
}
},
ty::TyBox(..) if self.in_new_function => false, // box in new() is okay
ty::TyRef(..) => false, // don't recurse down &ptrs
ty::TyRawPtr(..) => false, // don't recurse down *ptrs
_ => true
}
})
if is_unrooted_ty(cx, ty, self.in_new_function) {
cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
&format!("Expression of type {:?} must be rooted", ty))
}
}
}

View file

@ -30,6 +30,7 @@ use std::default::Default;
#[derive(JSTraceable)]
#[privatize]
#[allow(raw_pointer_derive)]
#[must_root]
pub struct BrowsingContext {
history: Vec<SessionHistoryEntry>,
active_index: usize,

View file

@ -14,6 +14,7 @@ use std::rc::Rc;
/// Encapsulates a handle to a frame in a frame tree.
#[derive(JSTraceable)]
#[allow(unrooted_must_root)] // FIXME(#6686) this is wrong
pub struct Page {
/// Pipeline id associated with this page.
id: PipelineId,

View file

@ -287,6 +287,8 @@ impl Drop for StackRootTLS {
/// Information for an entire page. Pages are top-level browsing contexts and can contain multiple
/// frames.
#[derive(JSTraceable)]
// ScriptTask instances are rooted on creation, so this is okay
#[allow(unrooted_must_root)]
pub struct ScriptTask {
/// A handle to the information pertaining to page layout
page: DOMRefCell<Option<Rc<Page>>>,