Skip to content

Warn unused type parameters #37946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libcore/num/dec2flt/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>() { }
pub fn set_precision<_T>() { }
}

// On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available.
Expand Down
2 changes: 1 addition & 1 deletion src/libcoretest/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ fn any_fixed_vec() {

#[test]
fn any_unsized() {
fn is_any<T: Any + ?Sized>() {}
fn is_any<_T: Any + ?Sized>() {}
is_any::<[i32]>();
}

Expand Down
7 changes: 7 additions & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
78 changes: 69 additions & 9 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -559,7 +560,14 @@ impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {

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);
Expand Down Expand Up @@ -722,15 +730,35 @@ enum RibKind<'a> {
struct Rib<'a> {
bindings: FxHashMap<Ident, Def>,
kind: RibKind<'a>,
sources: FxHashMap<Ident, (NodeId, Span)>,
used_names: RefCell<FxHashSet<Ident>>,
}

impl<'a> Rib<'a> {
fn new(kind: RibKind<'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<Def> {
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
Expand Down Expand Up @@ -1114,6 +1142,10 @@ pub struct Resolver<'a> {

// Avoid duplicated errors for "name already defined".
name_already_seen: FxHashMap<Name, Span>,

// Whether unused type parameters should be warned. Default true,
// false for intrinsics and lang items.
check_unused_type_parameters: bool,
}

pub struct ResolverArenas<'a> {
Expand Down Expand Up @@ -1289,6 +1321,7 @@ impl<'a> Resolver<'a> {
macro_exports: Vec::new(),
invocations: invocations,
name_already_seen: FxHashMap(),
check_unused_type_parameters: true,
}
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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(..) => {
Expand Down Expand Up @@ -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;
Expand All @@ -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 => {
Expand All @@ -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();
}
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/libserialize/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<S, T: ?Sized>(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<E> SpecializationError for E {
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2684,7 +2684,7 @@ mod tests {

#[test]
fn _assert_send_sync() {
fn _assert_send_sync<T: Send + Sync>() {}
fn _assert_send_sync<_T: Send + Sync>() {}
_assert_send_sync::<OpenOptions>();
}

Expand Down
2 changes: 1 addition & 1 deletion src/libstd/io/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ impl error::Error for Error {
}

fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync+Send>() {}
fn _is_sync_send<_T: Sync+Send>() {}
_is_sync_send::<Error>();
}

Expand Down
4 changes: 2 additions & 2 deletions src/libstd/sys_common/thread_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ impl Drop for Key {
mod tests {
use super::{Key, StaticKey};

fn assert_sync<T: Sync>() {}
fn assert_send<T: Send>() {}
fn assert_sync<_T: Sync>() {}
fn assert_send<_T: Send>() {}

#[test]
fn smoke() {
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
}

fn _assert_sync_and_send() {
fn _assert_both<T: Send + Sync>() {}
fn _assert_both<_T: Send + Sync>() {}
_assert_both::<JoinHandle<()>>();
_assert_both::<Thread>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,7 @@ mod tests {
// are ASTs encodable?
#[test]
fn check_asts_encodable() {
fn assert_encodable<T: serialize::Encodable>() {}
fn assert_encodable<_T: serialize::Encodable>() {}
assert_encodable::<Crate>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@

use std::str::Chars;

pub trait HasOutput<Ch, Str> {
type Output;
}

#[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Debug)]
pub enum Token<'a> {
Begin(&'a str)
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/coherence-projection-ok-orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/coherence-projection-ok.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

#![feature(rustc_attrs)]
#![allow(unused_type_parameters)]

pub trait Foo<P> {}

Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/generic-no-mangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/issue-29857.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@


#![feature(rustc_attrs)]
#![allow(unused_type_parameters)]

use std::marker::PhantomData;

Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/lint-dead-code-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
42 changes: 42 additions & 0 deletions src/test/compile-fail/lint-unused-type-parameters.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(unused_type_parameters)]

pub fn f<T>() {} //~ ERROR unused type parameter

pub struct S;
impl S {
pub fn m<T>() {} //~ ERROR unused type parameter
}

trait Trait {
fn m<T>() {} //~ ERROR unused type parameter
}

// Now test allow attributes

pub mod allow {
#[allow(unused_type_parameters)]
pub fn f<T>() {}

pub struct S;
impl S {
#[allow(unused_type_parameters)]
pub fn m<T>() {}
}

trait Trait {
#[allow(unused_type_parameters)]
fn m<T>() {}
}
}

fn main() {}
Loading