diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 29d37af30fc4..300b9aaf1006 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -26,9 +26,6 @@
//! a `pub fn new()`.
use self::MethodContext::*;
-
-use fmt_macros::{Parser, Piece, Position};
-
use metadata::csearch;
use middle::def::*;
use middle::subst::Substs;
@@ -1924,63 +1921,3 @@ impl LintPass for UnstableFeatures {
}
}
}
-
-/// Checks usage of `#[on_unimplemented]`
-#[derive(Copy)]
-pub struct BadOnUnimplemented;
-
-declare_lint!(BAD_ON_UNIMPLEMENTED, Deny,
- "Checks usage of `#[on_unimplemented]`");
-
-impl LintPass for BadOnUnimplemented {
- fn get_lints(&self) -> LintArray {
- lint_array!(BAD_ON_UNIMPLEMENTED)
- }
- fn check_item(&mut self, ctx: &Context, item: &ast::Item) {
- match item.node {
- ast::ItemTrait(_, ref generics, _, _) => {
- if let Some(ref attr) = item.attrs.iter().find(|&: a| {
- a.check_name("on_unimplemented")
- }) {
- if let Some(ref istring) = attr.value_str() {
- let mut parser = Parser::new(istring.get());
- let types = generics.ty_params.as_slice();
- for token in parser {
- match token {
- Piece::String(_) => (), // Normal string, no need to check it
- Piece::NextArgument(a) => match a.position {
- // `{Self}` is allowed
- Position::ArgumentNamed(s) if s == "Self" => (),
- // So is `{A}` if A is a type parameter
- Position::ArgumentNamed(s) => match types.iter().find(|t| {
- t.ident.as_str() == s
- }) {
- Some(_) => (),
- None => {
- ctx.span_lint(BAD_ON_UNIMPLEMENTED, attr.span,
- format!("there is no type parameter \
- {} on trait {}",
- s, item.ident.as_str())
- .as_slice());
- }
- },
- // `{:1}` and `{}` are not to be used
- Position::ArgumentIs(_) | Position::ArgumentNext => {
- ctx.span_lint(BAD_ON_UNIMPLEMENTED, attr.span,
- "only named substitution \
- parameters are allowed");
- }
- }
- }
- }
- } else {
- ctx.span_lint(BAD_ON_UNIMPLEMENTED, attr.span,
- "this attribute must have a value, \
- eg `#[on_unimplemented = \"foo\"]`")
- }
- }
- },
- _ => () // Not a trait def, move along
- }
- }
-}
\ No newline at end of file
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index b50c505a3ace..95e1e8d44bfc 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -211,7 +211,6 @@ impl LintStore {
UnusedAllocation,
MissingCopyImplementations,
UnstableFeatures,
- BadOnUnimplemented,
);
add_builtin_with_new!(sess,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1d184131dede..de6c884d6d71 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -83,6 +83,7 @@ use self::TupleArgumentsFlag::*;
use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv};
use check::_match::pat_ctxt;
+use fmt_macros::{Parser, Piece, Position};
use middle::{const_eval, def};
use middle::infer;
use middle::lang_items::IteratorItem;
@@ -113,6 +114,7 @@ use std::mem::replace;
use std::rc::Rc;
use std::iter::repeat;
use syntax::{self, abi, attr};
+use syntax::attr::AttrMetaMethods;
use syntax::ast::{self, ProvidedMethod, RequiredMethod, TypeTraitItem, DefId};
use syntax::ast_util::{self, local_def, PostExpansionMethod};
use syntax::codemap::{self, Span};
@@ -726,7 +728,8 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
}
}
- ast::ItemTrait(_, _, _, ref trait_methods) => {
+ ast::ItemTrait(_, ref generics, _, ref trait_methods) => {
+ check_trait_on_unimplemented(ccx, generics, it);
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
for trait_method in trait_methods.iter() {
match *trait_method {
@@ -776,6 +779,51 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
}
}
+fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ generics: &ast::Generics,
+ item: &ast::Item) {
+ if let Some(ref attr) = item.attrs.iter().find(|&: a| {
+ a.check_name("on_unimplemented")
+ }) {
+ if let Some(ref istring) = attr.value_str() {
+ let mut parser = Parser::new(istring.get());
+ let types = generics.ty_params.as_slice();
+ for token in parser {
+ match token {
+ Piece::String(_) => (), // Normal string, no need to check it
+ Piece::NextArgument(a) => match a.position {
+ // `{Self}` is allowed
+ Position::ArgumentNamed(s) if s == "Self" => (),
+ // So is `{A}` if A is a type parameter
+ Position::ArgumentNamed(s) => match types.iter().find(|t| {
+ t.ident.as_str() == s
+ }) {
+ Some(_) => (),
+ None => {
+ ccx.tcx.sess.span_err(attr.span,
+ format!("there is no type parameter \
+ {} on trait {}",
+ s, item.ident.as_str())
+ .as_slice());
+ }
+ },
+ // `{:1}` and `{}` are not to be used
+ Position::ArgumentIs(_) | Position::ArgumentNext => {
+ ccx.tcx.sess.span_err(attr.span,
+ "only named substitution \
+ parameters are allowed");
+ }
+ }
+ }
+ }
+ } else {
+ ccx.tcx.sess.span_err(attr.span,
+ "this attribute must have a value, \
+ eg `#[on_unimplemented = \"foo\"]`")
+ }
+ }
+}
+
/// Type checks a method body.
///
/// # Parameters
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index f15d53290e76..68b152dee233 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -84,6 +84,7 @@ This API is completely unstable and subject to change.
#[macro_use] extern crate syntax;
extern crate arena;
+extern crate fmt_macros;
extern crate rustc;
pub use rustc::lint;
diff --git a/src/test/compile-fail/on-unimplemented.rs b/src/test/compile-fail/on-unimplemented.rs
index 3f899288f50d..20b4448ea777 100644
--- a/src/test/compile-fail/on-unimplemented.rs
+++ b/src/test/compile-fail/on-unimplemented.rs
@@ -26,16 +26,6 @@ fn collect, B: MyFromIterator>(it: I) -> B {
MyFromIterator::my_from_iter(it)
}
-#[on_unimplemented] //~ ERROR the #[on_unimplemented] attribute on trait definition for BadAnnotation1 must have a value, eg `#[on_unimplemented = "foo"]`
-trait BadAnnotation1 {}
-
-#[on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
-//~^ ERROR the #[on_unimplemented] attribute on trait definition for BadAnnotation2 refers to non-existent type parameter C
-trait BadAnnotation2 {}
-
-fn trigger1(t: T) {}
-fn trigger2>(t: T) {}
-
pub fn main() {
let x = vec!(1u8, 2, 3, 4);
let y: Option> = collect(x.iter()); // this should give approximately the same error for x.iter().collect()
@@ -43,9 +33,4 @@ pub fn main() {
//~^^ NOTE a collection of type `core::option::Option>` cannot be built from an iterator over elements of type `&u8`
let x: String = foobar(); //~ ERROR
//~^ NOTE test error `collections::string::String` with `u8` `_` `u32`
-
- // The following two have errors in their annotations, so the regular error should be thrown
- trigger1(1u8); //~ ERROR the trait `BadAnnotation1` is not implemented for the type `u8`
- trigger2::(1u8); //~ ERROR the trait `BadAnnotation2` is not implemented
-
}