mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Support associated types in must_root lint (#34163)
* Support associated types in must_root lint Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fix Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixups Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Fix crown violations Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fix eng Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * make new test use RUSTC_BOOTSTRAP=1 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
2d3b46670f
commit
6c2b840e37
7 changed files with 144 additions and 21 deletions
|
@ -55,6 +55,7 @@ pub trait Castable: IDLInterface + DomObject + Sized {
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub trait HasParent {
|
pub trait HasParent {
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
type Parent;
|
type Parent;
|
||||||
fn as_parent(&self) -> &Self::Parent;
|
fn as_parent(&self) -> &Self::Parent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ use crate::script_runtime::{CanGc, JSContext};
|
||||||
|
|
||||||
pub trait PermissionAlgorithm {
|
pub trait PermissionAlgorithm {
|
||||||
type Descriptor;
|
type Descriptor;
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
type Status;
|
type Status;
|
||||||
fn create_descriptor(
|
fn create_descriptor(
|
||||||
cx: JSContext,
|
cx: JSContext,
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub trait WebGLExtension: Sized
|
||||||
where
|
where
|
||||||
Self::Extension: DomObject + JSTraceable,
|
Self::Extension: DomObject + JSTraceable,
|
||||||
{
|
{
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
type Extension;
|
type Extension;
|
||||||
|
|
||||||
/// Creates the DOM object of the WebGL extension.
|
/// Creates the DOM object of the WebGL extension.
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use rustc_ast::ast::{AttrKind, Attribute};
|
|
||||||
use rustc_hir::{self as hir, intravisit as visit, ExprKind};
|
use rustc_hir::{self as hir, intravisit as visit, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass, LintStore};
|
use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass, LintStore};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
@ -52,19 +51,6 @@ impl UnrootedPass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_lint_attr(sym: &Symbols, attrs: &[Attribute], name: Symbol) -> bool {
|
|
||||||
attrs.iter().any(|attr| {
|
|
||||||
matches!(
|
|
||||||
&attr.kind,
|
|
||||||
AttrKind::Normal(normal)
|
|
||||||
if normal.item.path.segments.len() == 3 &&
|
|
||||||
normal.item.path.segments[0].ident.name == sym.crown &&
|
|
||||||
normal.item.path.segments[1].ident.name == sym.unrooted_must_root_lint &&
|
|
||||||
normal.item.path.segments[2].ident.name == name
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a type is unrooted or contains any owned unrooted types
|
/// Checks if a type is unrooted or contains any owned unrooted types
|
||||||
fn is_unrooted_ty<'tcx>(
|
fn is_unrooted_ty<'tcx>(
|
||||||
sym: &'_ Symbols,
|
sym: &'_ Symbols,
|
||||||
|
@ -82,10 +68,12 @@ fn is_unrooted_ty<'tcx>(
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
let has_attr = |did, name| {
|
||||||
|
cx.tcx
|
||||||
|
.has_attrs_with_path(did, &[sym.crown, sym.unrooted_must_root_lint, name])
|
||||||
|
};
|
||||||
let recur_into_subtree = match t.kind() {
|
let recur_into_subtree = match t.kind() {
|
||||||
ty::Adt(did, substs) => {
|
ty::Adt(did, substs) => {
|
||||||
let has_attr =
|
|
||||||
|did, name| has_lint_attr(sym, cx.tcx.get_attrs_unchecked(did), name);
|
|
||||||
if has_attr(did.did(), sym.must_root) {
|
if has_attr(did.did(), sym.must_root) {
|
||||||
ret = true;
|
ret = true;
|
||||||
false
|
false
|
||||||
|
@ -159,7 +147,17 @@ fn is_unrooted_ty<'tcx>(
|
||||||
ty::Ref(..) => false, // don't recurse down &ptrs
|
ty::Ref(..) => false, // don't recurse down &ptrs
|
||||||
ty::RawPtr(..) => false, // don't recurse down *ptrs
|
ty::RawPtr(..) => false, // don't recurse down *ptrs
|
||||||
ty::FnDef(..) | ty::FnPtr(_) => false,
|
ty::FnDef(..) | ty::FnPtr(_) => false,
|
||||||
|
ty::Alias(
|
||||||
|
ty::AliasTyKind::Projection | ty::AliasTyKind::Inherent | ty::AliasTyKind::Weak,
|
||||||
|
ty,
|
||||||
|
) => {
|
||||||
|
if has_attr(ty.def_id, sym.must_root) {
|
||||||
|
ret = true;
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
if !recur_into_subtree {
|
if !recur_into_subtree {
|
||||||
|
@ -179,8 +177,11 @@ impl<'tcx> LateLintPass<'tcx> for UnrootedPass {
|
||||||
/// All structs containing #[crown::unrooted_must_root_lint::must_root] types
|
/// All structs containing #[crown::unrooted_must_root_lint::must_root] types
|
||||||
/// must be #[crown::unrooted_must_root_lint::must_root] themselves
|
/// must be #[crown::unrooted_must_root_lint::must_root] themselves
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item) {
|
||||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
let sym = &self.symbols;
|
||||||
if has_lint_attr(&self.symbols, attrs, self.symbols.must_root) {
|
if cx.tcx.has_attrs_with_path(
|
||||||
|
item.hir_id().expect_owner(),
|
||||||
|
&[sym.crown, sym.unrooted_must_root_lint, sym.must_root],
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let hir::ItemKind::Struct(def, ..) = &item.kind {
|
if let hir::ItemKind::Struct(def, ..) = &item.kind {
|
||||||
|
@ -204,8 +205,11 @@ impl<'tcx> LateLintPass<'tcx> for UnrootedPass {
|
||||||
fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant) {
|
fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant) {
|
||||||
let map = &cx.tcx.hir();
|
let map = &cx.tcx.hir();
|
||||||
let parent_item = map.expect_item(map.get_parent_item(var.hir_id).def_id);
|
let parent_item = map.expect_item(map.get_parent_item(var.hir_id).def_id);
|
||||||
let attrs = cx.tcx.hir().attrs(parent_item.hir_id());
|
let sym = &self.symbols;
|
||||||
if !has_lint_attr(&self.symbols, attrs, self.symbols.must_root) {
|
if !cx.tcx.has_attrs_with_path(
|
||||||
|
parent_item.hir_id().expect_owner(),
|
||||||
|
&[sym.crown, sym.unrooted_must_root_lint, sym.must_root],
|
||||||
|
) {
|
||||||
match var.data {
|
match var.data {
|
||||||
hir::VariantData::Tuple(fields, ..) => {
|
hir::VariantData::Tuple(fields, ..) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
@ -226,6 +230,53 @@ impl<'tcx> LateLintPass<'tcx> for UnrootedPass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// for trait_type_impl_must_root test
|
||||||
|
fn check_trait_item(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
trait_item: &'tcx rustc_hir::TraitItem<'tcx>,
|
||||||
|
) {
|
||||||
|
let hir::TraitItemKind::Type(_, _) = trait_item.kind else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let sym = &self.symbols;
|
||||||
|
if cx.tcx.has_attrs_with_path(
|
||||||
|
trait_item.hir_id().expect_owner(),
|
||||||
|
&[sym.crown, sym.unrooted_must_root_lint, sym.must_root],
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let trait_id = cx
|
||||||
|
.tcx
|
||||||
|
.trait_of_item(trait_item.hir_id().expect_owner().to_def_id())
|
||||||
|
.unwrap();
|
||||||
|
// we need to make sure that all impl do not have any must_root type binded
|
||||||
|
let impls = cx.tcx.trait_impls_of(trait_id);
|
||||||
|
for (_ty, impl_def_ids) in impls.non_blanket_impls() {
|
||||||
|
for impl_def_id in impl_def_ids {
|
||||||
|
let type_impl = cx
|
||||||
|
.tcx
|
||||||
|
.associated_items(impl_def_id)
|
||||||
|
.find_by_name_and_kind(cx.tcx, trait_item.ident, ty::AssocKind::Type, trait_id)
|
||||||
|
.unwrap();
|
||||||
|
let mir_ty = cx.tcx.type_of(type_impl.def_id).skip_binder();
|
||||||
|
if is_unrooted_ty(&self.symbols, cx, mir_ty, false) {
|
||||||
|
cx.lint(UNROOTED_MUST_ROOT, |lint| {
|
||||||
|
lint.primary_message(
|
||||||
|
"Type trait declaration must be marked with \
|
||||||
|
#[crown::unrooted_must_root_lint::must_root] \
|
||||||
|
to allow binding must_root types in associated types",
|
||||||
|
);
|
||||||
|
lint.span(trait_item.span);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Function arguments that are #[crown::unrooted_must_root_lint::must_root] types are not allowed
|
/// Function arguments that are #[crown::unrooted_must_root_lint::must_root] types are not allowed
|
||||||
fn check_fn(
|
fn check_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
//@rustc-env:RUSTC_BOOTSTRAP=1
|
||||||
|
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type F;
|
||||||
|
//~^ ERROR: Type trait declaration must be marked with #[crown::unrooted_must_root_lint::must_root] to allow binding must_root types in associated types
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypeHolder;
|
||||||
|
|
||||||
|
impl Trait for TypeHolder {
|
||||||
|
// type F in trait must be also marked as must_root if we want to do this
|
||||||
|
type F = Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
//@rustc-env:RUSTC_BOOTSTRAP=1
|
||||||
|
|
||||||
|
struct Foo(i32);
|
||||||
|
|
||||||
|
struct Bar<TH: TypeHolderTrait>(TH::F);
|
||||||
|
//~^ ERROR: Type must be rooted, use #[crown::unrooted_must_root_lint::must_root] on the struct definition to propagate
|
||||||
|
|
||||||
|
trait TypeHolderTrait {
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
|
type F;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypeHolder;
|
||||||
|
|
||||||
|
impl TypeHolderTrait for TypeHolder {
|
||||||
|
type F = Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
26
support/crown/tests/run-pass/type_holder_must_root.rs
Normal file
26
support/crown/tests/run-pass/type_holder_must_root.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
//@rustc-env:RUSTC_BOOTSTRAP=1
|
||||||
|
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
|
struct Foo(i32);
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
|
struct Bar<TH: TypeHolderTrait>(TH::F, TH::B);
|
||||||
|
|
||||||
|
struct Baz(i32);
|
||||||
|
|
||||||
|
trait TypeHolderTrait {
|
||||||
|
#[crown::unrooted_must_root_lint::must_root]
|
||||||
|
type F;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypeHolder;
|
||||||
|
|
||||||
|
impl TypeHolderTrait for TypeHolder {
|
||||||
|
type F = Foo;
|
||||||
|
type B = Baz;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue