From f383ce62e80592b1c46d0c259733efc38f695352 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 5 Nov 2014 15:49:37 -0800 Subject: [PATCH] rustc: Add some more checks to the stability lint This catches uses of unstable traits in ``` trait Foo: UnstableTrait { } ``` and ``` impl UnstableTrait for Foo { } ``` --- src/librustc/lint/builtin.rs | 81 ++++++++++++++++--------- src/test/auxiliary/lint_stability.rs | 3 + src/test/compile-fail/lint-stability.rs | 15 +++++ 3 files changed, 72 insertions(+), 27 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index f084c8caea5..ec522d70784 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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, diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 06031eb6c6c..0be2f31e282 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -118,6 +118,9 @@ pub trait Trait { impl Trait for MethodTester {} +#[experimental] +pub trait ExperimentalTrait {} + #[deprecated] pub struct DeprecatedStruct { pub i: int } #[experimental] diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index babf12e97f2..2074d007502 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -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() {}