diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 604bc7c10dea0..62bd90c53c2b1 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -35,7 +35,7 @@ fn power_of_ten(e: i16) -> Fp { // precision of the computation is determined on a per-operation basis. #[cfg(any(not(target_arch="x86"), target_feature="sse2"))] mod fpu_precision { - pub fn set_precision() { } + pub fn set_precision<_T>() { } } // On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available. diff --git a/src/libcoretest/any.rs b/src/libcoretest/any.rs index a9fc8913182b3..dd90e0d1f0c12 100644 --- a/src/libcoretest/any.rs +++ b/src/libcoretest/any.rs @@ -121,7 +121,7 @@ fn any_fixed_vec() { #[test] fn any_unsized() { - fn is_any() {} + fn is_any<_T: Any + ?Sized>() {} is_any::<[i32]>(); } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 02c1ece163497..92af6bec2b17d 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -28,6 +28,12 @@ declare_lint! { "imports that are never used" } +declare_lint! { + pub UNUSED_TYPE_PARAMETERS, + Warn, + "type parameters that are never used" +} + declare_lint! { pub UNUSED_EXTERN_CRATES, Allow, @@ -226,6 +232,7 @@ impl LintPass for HardwiredLints { fn get_lints(&self) -> LintArray { lint_array!( UNUSED_IMPORTS, + UNUSED_TYPE_PARAMETERS, UNUSED_EXTERN_CRATES, UNUSED_QUALIFICATIONS, UNKNOWN_LINTS, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 6c9a3e99a0458..9a601e68f35ae 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -158,6 +158,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { add_lint_group!(sess, "unused", UNUSED_IMPORTS, + UNUSED_TYPE_PARAMETERS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ea5aa5be0132e..4aeb566732d03 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -49,6 +49,7 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet}; +use syntax::abi::Abi; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, Ident, SpannedIdent, IntTy, UintTy}; @@ -559,7 +560,14 @@ impl ::std::ops::IndexMut for PerNS { impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { fn visit_item(&mut self, item: &'tcx Item) { + let is_lang_item = item.attrs.iter().any(|attr| attr.name() == "lang"); + if is_lang_item { + self.check_unused_type_parameters = false; + } + self.resolve_item(item); + + self.check_unused_type_parameters = true; } fn visit_arm(&mut self, arm: &'tcx Arm) { self.resolve_arm(arm); @@ -722,6 +730,8 @@ enum RibKind<'a> { struct Rib<'a> { bindings: FxHashMap, kind: RibKind<'a>, + sources: FxHashMap, + used_names: RefCell>, } impl<'a> Rib<'a> { @@ -729,8 +739,26 @@ impl<'a> Rib<'a> { Rib { bindings: FxHashMap(), kind: kind, + sources: FxHashMap(), + used_names: RefCell::new(FxHashSet()), } } + + fn insert(&mut self, ident: Ident, def: Def) { + self.bindings.insert(ident, def); + } + + fn insert_with_source(&mut self, ident: Ident, id: NodeId, span: Span, def: Def) { + self.bindings.insert(ident, def); + self.sources.insert(ident, (id, span)); + } + + fn get(&self, ident: Ident) -> Option { + self.bindings.get(&ident).map(|def| { + self.used_names.borrow_mut().insert(ident); + def.clone() + }) + } } /// A definition along with the index of the rib it was found on @@ -1114,6 +1142,10 @@ pub struct Resolver<'a> { // Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap, + + // Whether unused type parameters should be warned. Default true, + // false for intrinsics and lang items. + check_unused_type_parameters: bool, } pub struct ResolverArenas<'a> { @@ -1289,6 +1321,7 @@ impl<'a> Resolver<'a> { macro_exports: Vec::new(), invocations: invocations, name_already_seen: FxHashMap(), + check_unused_type_parameters: true, } } @@ -1394,7 +1427,7 @@ impl<'a> Resolver<'a> { // Walk backwards up the ribs in scope. for i in (0 .. self.ribs[ns].len()).rev() { - if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { + if let Some(def) = self.ribs[ns][i].get(ident) { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Def(if let Some(span) = record_used { self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, span) @@ -1502,7 +1535,7 @@ impl<'a> Resolver<'a> { return None; } } - let result = rib.bindings.get(&ident).cloned(); + let result = rib.get(ident); if result.is_some() { return result; } @@ -1577,10 +1610,22 @@ impl<'a> Resolver<'a> { }); } - ItemKind::Mod(_) | ItemKind::ForeignMod(_) => { + ItemKind::Mod(_) => { + self.with_scope(item.id, |this| { + visit::walk_item(this, item); + }); + } + + ItemKind::ForeignMod(ref m) => { + if m.abi == Abi::RustIntrinsic { + self.check_unused_type_parameters = false; + } + self.with_scope(item.id, |this| { visit::walk_item(this, item); }); + + self.check_unused_type_parameters = true; } ItemKind::Const(..) | ItemKind::Static(..) => { @@ -1637,7 +1682,7 @@ impl<'a> Resolver<'a> { { match type_parameters { HasTypeParameters(generics, rib_kind) => { - let mut function_type_rib = Rib::new(rib_kind); + let mut type_rib = Rib::new(rib_kind); let mut seen_bindings = FxHashMap(); for type_parameter in &generics.ty_params { let name = type_parameter.ident.name; @@ -1653,12 +1698,13 @@ impl<'a> Resolver<'a> { seen_bindings.entry(name).or_insert(type_parameter.span); // plain insert (no renaming) + let ident = Ident::with_empty_ctxt(name); let def_id = self.definitions.local_def_id(type_parameter.id); let def = Def::TyParam(def_id); - function_type_rib.bindings.insert(Ident::with_empty_ctxt(name), def); + type_rib.insert_with_source(ident, type_parameter.id, type_parameter.span, def); self.record_def(type_parameter.id, PathResolution::new(def)); } - self.ribs[TypeNS].push(function_type_rib); + self.ribs[TypeNS].push(type_rib); } NoTypeParameters => { @@ -1669,6 +1715,20 @@ impl<'a> Resolver<'a> { f(self); if let HasTypeParameters(..) = type_parameters { + if self.check_unused_type_parameters { + let type_rib = self.ribs[TypeNS].last().unwrap(); + for (&name, &(id, span)) in &type_rib.sources { + if name.to_string().starts_with('_') { + continue; + } + if !type_rib.used_names.borrow().contains(&name) { + self.session.add_lint(lint::builtin::UNUSED_TYPE_PARAMETERS, + id, span, + "unused type parameter".to_string()); + } + } + } + self.ribs[TypeNS].pop(); } } @@ -1784,7 +1844,7 @@ impl<'a> Resolver<'a> { let mut self_type_rib = Rib::new(NormalRibKind); // plain insert (no renaming, types are not currently hygienic....) - self_type_rib.bindings.insert(keywords::SelfType.ident(), self_def); + self_type_rib.insert(keywords::SelfType.ident(), self_def); self.ribs[TypeNS].push(self_type_rib); f(self); self.ribs[TypeNS].pop(); @@ -2098,7 +2158,7 @@ impl<'a> Resolver<'a> { // A completely fresh binding, add to the lists if it's valid. if ident.node.name != keywords::Invalid.name() { bindings.insert(ident.node, outer_pat_id); - self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident.node, def); + self.ribs[ValueNS].last_mut().unwrap().insert(ident.node, def); } } } @@ -2605,7 +2665,7 @@ impl<'a> Resolver<'a> { if let Some(label) = label { let def = Def::Label(id); self.with_label_rib(|this| { - this.label_ribs.last_mut().unwrap().bindings.insert(label.node, def); + this.label_ribs.last_mut().unwrap().insert(label.node, def); this.visit_block(block); }); } else { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index c4613c661a84b..c9f7f5ba3542e 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -674,8 +674,8 @@ pub trait SpecializationError { /// `T` is the type being encoded/decoded, and /// the arguments are the names of the trait /// and method that should've been overriden. - fn not_found(trait_name: &'static str, - method_name: &'static str) -> Self; + fn not_found<_S, _T: ?Sized>(trait_name: &'static str, + method_name: &'static str) -> Self; } impl SpecializationError for E { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index e91e808c5489a..acdc4e91adb3d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2684,7 +2684,7 @@ mod tests { #[test] fn _assert_send_sync() { - fn _assert_send_sync() {} + fn _assert_send_sync<_T: Send + Sync>() {} _assert_send_sync::(); } diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 795c89c000747..05a58d75d9905 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -545,7 +545,7 @@ impl error::Error for Error { } fn _assert_error_is_sync_send() { - fn _is_sync_send() {} + fn _is_sync_send<_T: Sync+Send>() {} _is_sync_send::(); } diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index 25a9d5720d933..eaff18dcf8242 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -235,8 +235,8 @@ impl Drop for Key { mod tests { use super::{Key, StaticKey}; - fn assert_sync() {} - fn assert_send() {} + fn assert_sync<_T: Sync>() {} + fn assert_send<_T: Send>() {} #[test] fn smoke() { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 255cd2a9bc0f1..22c9aa49b82b7 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -789,7 +789,7 @@ impl IntoInner for JoinHandle { } fn _assert_sync_and_send() { - fn _assert_both() {} + fn _assert_both<_T: Send + Sync>() {} _assert_both::>(); _assert_both::(); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2a911aceb9d94..91b588b85e8c1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1981,7 +1981,7 @@ mod tests { // are ASTs encodable? #[test] fn check_asts_encodable() { - fn assert_encodable() {} + fn assert_encodable<_T: serialize::Encodable>() {} assert_encodable::(); } } diff --git a/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs b/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs index 020c9e5e1db59..f09e0e73faf20 100644 --- a/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs +++ b/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs @@ -11,6 +11,7 @@ // revisions: angle paren ok elision #![allow(dead_code)] +#![allow(unused_type_parameters)] #![feature(rustc_attrs)] #![feature(unboxed_closures)] #![deny(hr_lifetime_in_assoc_type)] diff --git a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs index 6ba09acc0e799..3ebe43b46bc7c 100644 --- a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs +++ b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs @@ -16,10 +16,6 @@ use std::str::Chars; -pub trait HasOutput { - type Output; -} - #[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Debug)] pub enum Token<'a> { Begin(&'a str) diff --git a/src/test/compile-fail/coherence-projection-ok-orphan.rs b/src/test/compile-fail/coherence-projection-ok-orphan.rs index a52af0873a823..e8f604d70b8c5 100644 --- a/src/test/compile-fail/coherence-projection-ok-orphan.rs +++ b/src/test/compile-fail/coherence-projection-ok-orphan.rs @@ -10,6 +10,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] // Here we do not get a coherence conflict because `Baz: Iterator` // does not hold and (due to the orphan rules), we can rely on that. diff --git a/src/test/compile-fail/coherence-projection-ok.rs b/src/test/compile-fail/coherence-projection-ok.rs index af88f3744eaeb..974662863ac8d 100644 --- a/src/test/compile-fail/coherence-projection-ok.rs +++ b/src/test/compile-fail/coherence-projection-ok.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(rustc_attrs)] +#![allow(unused_type_parameters)] pub trait Foo

{} diff --git a/src/test/compile-fail/generic-no-mangle.rs b/src/test/compile-fail/generic-no-mangle.rs index 2cb73cf2ef79b..f85fbd2de6cbc 100644 --- a/src/test/compile-fail/generic-no-mangle.rs +++ b/src/test/compile-fail/generic-no-mangle.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_type_parameters)] #![deny(no_mangle_generic_items)] #[no_mangle] diff --git a/src/test/compile-fail/issue-29857.rs b/src/test/compile-fail/issue-29857.rs index 661579f52b684..56036d466035c 100644 --- a/src/test/compile-fail/issue-29857.rs +++ b/src/test/compile-fail/issue-29857.rs @@ -10,6 +10,7 @@ #![feature(rustc_attrs)] +#![allow(unused_type_parameters)] use std::marker::PhantomData; diff --git a/src/test/compile-fail/lint-dead-code-1.rs b/src/test/compile-fail/lint-dead-code-1.rs index f45e80f5252e3..63848cd32d124 100644 --- a/src/test/compile-fail/lint-dead-code-1.rs +++ b/src/test/compile-fail/lint-dead-code-1.rs @@ -9,6 +9,7 @@ // except according to those terms. #![no_std] +#![allow(unused_type_parameters)] #![allow(unused_variables)] #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] diff --git a/src/test/compile-fail/lint-unused-type-parameters.rs b/src/test/compile-fail/lint-unused-type-parameters.rs new file mode 100644 index 0000000000000..27f836c1f9e04 --- /dev/null +++ b/src/test/compile-fail/lint-unused-type-parameters.rs @@ -0,0 +1,42 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(unused_type_parameters)] + +pub fn f() {} //~ ERROR unused type parameter + +pub struct S; +impl S { + pub fn m() {} //~ ERROR unused type parameter +} + +trait Trait { + fn m() {} //~ ERROR unused type parameter +} + +// Now test allow attributes + +pub mod allow { + #[allow(unused_type_parameters)] + pub fn f() {} + + pub struct S; + impl S { + #[allow(unused_type_parameters)] + pub fn m() {} + } + + trait Trait { + #[allow(unused_type_parameters)] + fn m() {} + } +} + +fn main() {} diff --git a/src/test/compile-fail/object-safety-phantom-fn.rs b/src/test/compile-fail/object-safety-phantom-fn.rs index 518c45ac9dff6..c80d2863b0ff3 100644 --- a/src/test/compile-fail/object-safety-phantom-fn.rs +++ b/src/test/compile-fail/object-safety-phantom-fn.rs @@ -12,6 +12,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] trait Baz { } diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs index b3037a1e187f4..f46a3c55db871 100644 --- a/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs @@ -14,6 +14,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] #![allow(unused_variables)] trait Trait1<'x> { diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs index a2e6de2137696..db1e6ffaf51c6 100644 --- a/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs @@ -14,6 +14,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] #![allow(unused_variables)] trait Trait1<'x> { diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs index b8582f8c26b31..c5aa491244705 100644 --- a/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs @@ -14,6 +14,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] #![allow(unused_variables)] trait Trait1<'x> { diff --git a/src/test/compile-fail/regions-outlives-projection-hrtype.rs b/src/test/compile-fail/regions-outlives-projection-hrtype.rs index 2d271b7be73e0..cae914438ff09 100644 --- a/src/test/compile-fail/regions-outlives-projection-hrtype.rs +++ b/src/test/compile-fail/regions-outlives-projection-hrtype.rs @@ -17,6 +17,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(unused_type_parameters)] trait TheTrait { type TheType; diff --git a/src/test/ui/compare-method/proj-outlives-region.rs b/src/test/ui/compare-method/proj-outlives-region.rs index 54cfe4be9c101..b5925c07af5c6 100644 --- a/src/test/ui/compare-method/proj-outlives-region.rs +++ b/src/test/ui/compare-method/proj-outlives-region.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![allow(unused_type_parameters)] #![deny(extra_requirement_in_impl)] // Test that we elaborate `Type: 'region` constraints and infer various important things. diff --git a/src/test/ui/compare-method/proj-outlives-region.stderr b/src/test/ui/compare-method/proj-outlives-region.stderr index 79293e0deed60..a449993dbd6f7 100644 --- a/src/test/ui/compare-method/proj-outlives-region.stderr +++ b/src/test/ui/compare-method/proj-outlives-region.stderr @@ -1,18 +1,18 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/proj-outlives-region.rs:22:5 + --> $DIR/proj-outlives-region.rs:23:5 | -17 | fn foo() where T: 'a; +18 | fn foo() where T: 'a; | --------------------- definition of `foo` from trait ... -22 | fn foo() where U: 'a { } //~ ERROR E0276 +23 | fn foo() where U: 'a { } //~ ERROR E0276 | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a` | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #37166 note: lint level defined here - --> $DIR/proj-outlives-region.rs:12:9 + --> $DIR/proj-outlives-region.rs:13:9 | -12 | #![deny(extra_requirement_in_impl)] +13 | #![deny(extra_requirement_in_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/compare-method/region-unrelated.rs b/src/test/ui/compare-method/region-unrelated.rs index 8f79b30bd5f31..69319d069683e 100644 --- a/src/test/ui/compare-method/region-unrelated.rs +++ b/src/test/ui/compare-method/region-unrelated.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![allow(unused_type_parameters)] #![deny(extra_requirement_in_impl)] // Test that we elaborate `Type: 'region` constraints and infer various important things. diff --git a/src/test/ui/compare-method/region-unrelated.stderr b/src/test/ui/compare-method/region-unrelated.stderr index b7cfdf799bc9d..5c820ae5e323e 100644 --- a/src/test/ui/compare-method/region-unrelated.stderr +++ b/src/test/ui/compare-method/region-unrelated.stderr @@ -1,18 +1,18 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/region-unrelated.rs:22:5 + --> $DIR/region-unrelated.rs:23:5 | -17 | fn foo() where T: 'a; +18 | fn foo() where T: 'a; | --------------------- definition of `foo` from trait ... -22 | fn foo() where V: 'a { } +23 | fn foo() where V: 'a { } | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `V: 'a` | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #37166 note: lint level defined here - --> $DIR/region-unrelated.rs:12:9 + --> $DIR/region-unrelated.rs:13:9 | -12 | #![deny(extra_requirement_in_impl)] +13 | #![deny(extra_requirement_in_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error