rustc: Add some more checks to the stability lint

This catches uses of unstable traits in

```
trait Foo: UnstableTrait { }
```

and

```
impl UnstableTrait for Foo { }
```
This commit is contained in:
Brian Anderson 2014-11-05 15:49:37 -08:00
parent 68ac44cb97
commit f383ce62e8
3 changed files with 72 additions and 27 deletions

View File

@ -1581,6 +1581,36 @@ impl Stability {
cx.span_lint(lint, span, msg.as_slice());
}
fn is_internal(&self, cx: &Context, span: Span) -> bool {
// first, check if the given expression was generated by a macro or not
// we need to go back the expn_info tree to check only the arguments
// of the initial macro call, not the nested ones.
let mut expnid = span.expn_id;
let mut is_internal = false;
while cx.tcx.sess.codemap().with_expn_info(expnid, |expninfo| {
match expninfo {
Some(ref info) => {
// save the parent expn_id for next loop iteration
expnid = info.call_site.expn_id;
if info.callee.span.is_none() {
// it's a compiler built-in, we *really* don't want to mess with it
// so we skip it, unless it was called by a regular macro, in which case
// we will handle the caller macro next turn
is_internal = true;
true // continue looping
} else {
// was this expression from the current macro arguments ?
is_internal = !( span.lo > info.call_site.lo &&
span.hi < info.call_site.hi );
true // continue looping
}
},
_ => false // stop looping
}
}) { /* empty while loop body */ }
return is_internal;
}
}
impl LintPass for Stability {
@ -1605,33 +1635,7 @@ impl LintPass for Stability {
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
// first, check if the given expression was generated by a macro or not
// we need to go back the expn_info tree to check only the arguments
// of the initial macro call, not the nested ones.
let mut expnid = e.span.expn_id;
let mut is_internal = false;
while cx.tcx.sess.codemap().with_expn_info(expnid, |expninfo| {
match expninfo {
Some(ref info) => {
// save the parent expn_id for next loop iteration
expnid = info.call_site.expn_id;
if info.callee.span.is_none() {
// it's a compiler built-in, we *really* don't want to mess with it
// so we skip it, unless it was called by a regular macro, in which case
// we will handle the caller macro next turn
is_internal = true;
true // continue looping
} else {
// was this expression from the current macro arguments ?
is_internal = !( e.span.lo > info.call_site.lo &&
e.span.hi < info.call_site.hi );
true // continue looping
}
},
_ => false // stop looping
}
}) { /* empty while loop body */ }
if is_internal { return; }
if self.is_internal(cx, e.span) { return; }
let mut span = e.span;
@ -1677,6 +1681,29 @@ impl LintPass for Stability {
};
self.lint(cx, id, span);
}
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
if self.is_internal(cx, item.span) { return }
match item.node {
ast::ItemTrait(_, _, ref supertraits, _) => {
for t in supertraits.iter() {
match *t {
ast::TraitTyParamBound(ref t) => {
let id = ty::trait_ref_to_def_id(cx.tcx, t);
self.lint(cx, id, t.path.span);
}
_ => (/* pass */)
}
}
}
ast::ItemImpl(_, Some(ref t), _, _) => {
let id = ty::trait_ref_to_def_id(cx.tcx, t);
self.lint(cx, id, t.path.span);
}
_ => (/* pass */)
}
}
}
declare_lint!(pub UNUSED_IMPORTS, Warn,

View File

@ -118,6 +118,9 @@ pub trait Trait {
impl Trait for MethodTester {}
#[experimental]
pub trait ExperimentalTrait {}
#[deprecated]
pub struct DeprecatedStruct { pub i: int }
#[experimental]

View File

@ -141,6 +141,12 @@ mod cross_crate {
foo.trait_unmarked(); //~ ERROR use of unmarked item
foo.trait_stable();
}
struct S;
impl ExperimentalTrait for S { } //~ ERROR use of experimental item
trait LocalTrait : ExperimentalTrait { } //~ ERROR use of experimental item
}
mod inheritance {
@ -444,6 +450,15 @@ mod this_crate {
foo.trait_unmarked();
foo.trait_stable();
}
#[deprecated]
pub trait DeprecatedTrait {}
struct S;
impl DeprecatedTrait for S { } //~ ERROR use of deprecated item
trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item
}
fn main() {}