diff --git a/components/plugins/lints/unrooted_must_root.rs b/components/plugins/lints/unrooted_must_root.rs index be6175c2cce..073212eabe6 100644 --- a/components/plugins/lints/unrooted_must_root.rs +++ b/components/plugins/lints/unrooted_must_root.rs @@ -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)) + } } } diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs index 595153f1fc3..cc4dc346c3f 100644 --- a/components/script/dom/browsercontext.rs +++ b/components/script/dom/browsercontext.rs @@ -30,6 +30,7 @@ use std::default::Default; #[derive(JSTraceable)] #[privatize] #[allow(raw_pointer_derive)] +#[must_root] pub struct BrowsingContext { history: Vec, active_index: usize, diff --git a/components/script/page.rs b/components/script/page.rs index 563cbae1006..3d9dc1d8da7 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -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, diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 5b91fe8c5ac..51937350df2 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -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>>,