Auto merge of #30724 - nikomatsakis:feature-gate-defaulted-type-parameters, r=pnkfelix

It was recently realized that we accept defaulted type parameters everywhere, without feature gate, even though the only place that we really *intended* to accept them were on types. This PR adds a lint warning unless the "type-parameter-defaults" feature is enabled. This should eventually become a hard error.

This is a [breaking-change] in that new feature gates are required (or simply removing the defaults, which is probably a better choice as they have little effect at this time). Results of a [crater run][crater] suggest that approximately 5-15 crates are affected. I didn't do the measurement quite right so that run cannot distinguish "true" regressions from "non-root" regressions, but even the upper bound of 15 affected crates seems relatively minimal.

[crater]: https://gist.github.com/nikomatsakis/760c6a67698bd24253bf

cc @rust-lang/lang
r? @pnkfelix
This commit is contained in:
bors 2016-01-07 06:32:56 +00:00
commit 91b27ec9be
11 changed files with 76 additions and 19 deletions

View file

@ -1591,10 +1591,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
#[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27787")]
pub fn range<Min: ?Sized + Ord = K, Max: ?Sized + Ord = K>(&self,
min: Bound<&Min>,
max: Bound<&Max>)
-> Range<K, V>
pub fn range<Min: ?Sized + Ord, Max: ?Sized + Ord>(&self,
min: Bound<&Min>,
max: Bound<&Max>)
-> Range<K, V>
where K: Borrow<Min> + Borrow<Max>
{
range_impl!(&self.root,
@ -1633,10 +1633,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
#[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27787")]
pub fn range_mut<Min: ?Sized + Ord = K, Max: ?Sized + Ord = K>(&mut self,
min: Bound<&Min>,
max: Bound<&Max>)
-> RangeMut<K, V>
pub fn range_mut<Min: ?Sized + Ord, Max: ?Sized + Ord>(&mut self,
min: Bound<&Min>,
max: Bound<&Max>)
-> RangeMut<K, V>
where K: Borrow<Min> + Borrow<Max>
{
range_impl!(&mut self.root,

View file

@ -154,10 +154,10 @@ impl<T: Ord> BTreeSet<T> {
#[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27787")]
pub fn range<'a, Min: ?Sized + Ord = T, Max: ?Sized + Ord = T>(&'a self,
min: Bound<&Min>,
max: Bound<&Max>)
-> Range<'a, T>
pub fn range<'a, Min: ?Sized + Ord, Max: ?Sized + Ord>(&'a self,
min: Bound<&Min>,
max: Bound<&Max>)
-> Range<'a, T>
where T: Borrow<Min> + Borrow<Max>
{
fn first<A, B>((a, _): (A, B)) -> A {

View file

@ -2132,7 +2132,7 @@ pub trait Iterator {
/// ```
#[unstable(feature = "iter_arith", reason = "bounds recently changed",
issue = "27739")]
fn sum<S=<Self as Iterator>::Item>(self) -> S where
fn sum<S>(self) -> S where
S: Add<Self::Item, Output=S> + Zero,
Self: Sized,
{
@ -2157,7 +2157,7 @@ pub trait Iterator {
/// ```
#[unstable(feature="iter_arith", reason = "bounds recently changed",
issue = "27739")]
fn product<P=<Self as Iterator>::Item>(self) -> P where
fn product<P>(self) -> P where
P: Mul<Self::Item, Output=P> + One,
Self: Sized,
{

View file

@ -16,6 +16,9 @@
use lint::{LintPass, LateLintPass, LintArray};
// name of the future-incompatible group
pub const FUTURE_INCOMPATIBLE: &'static str = "future_incompatible";
declare_lint! {
pub CONST_ERR,
Warn,
@ -124,6 +127,12 @@ declare_lint! {
"detect private items in public interfaces not caught by the old implementation"
}
declare_lint! {
pub INVALID_TYPE_PARAM_DEFAULT,
Warn,
"type parameter default erroneously allowed in invalid location"
}
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
@ -149,6 +158,7 @@ impl LintPass for HardwiredLints {
TRIVIAL_CASTS,
TRIVIAL_NUMERIC_CASTS,
PRIVATE_IN_PUBLIC,
INVALID_TYPE_PARAM_DEFAULT,
CONST_ERR
)
}

View file

@ -365,14 +365,16 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
/// lints elsewhere in the compiler should call
/// `Session::add_lint()` instead.
pub fn raw_emit_lint(sess: &Session,
lints: &LintStore,
lint: &'static Lint,
lvlsrc: LevelSource,
span: Option<Span>,
msg: &str) {
raw_struct_lint(sess, lint, lvlsrc, span, msg).emit();
raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
}
pub fn raw_struct_lint<'a>(sess: &'a Session,
lints: &LintStore,
lint: &'static Lint,
lvlsrc: LevelSource,
span: Option<Span>,
@ -414,6 +416,18 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
_ => sess.bug("impossible level in raw_emit_lint"),
};
// Check for future incompatibility lints and issue a stronger warning.
let future_incompat_lints = &lints.lint_groups[builtin::FUTURE_INCOMPATIBLE];
let this_id = LintId::of(lint);
if future_incompat_lints.0.iter().any(|&id| id == this_id) {
let msg = "this lint will become a HARD ERROR in a future release!";
if let Some(sp) = span {
err.span_note(sp, msg);
} else {
err.note(msg);
}
}
if let Some(span) = def {
err.span_note(span, "lint level defined here");
}
@ -451,7 +465,7 @@ pub trait LintContext: Sized {
Some(pair) => pair,
};
raw_emit_lint(&self.sess(), lint, (level, src), span, msg);
raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
}
fn lookup(&self,
@ -464,7 +478,7 @@ pub trait LintContext: Sized {
Some(pair) => pair,
};
raw_struct_lint(&self.sess(), lint, (level, src), span, msg)
raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg)
}
/// Emit a lint at the appropriate level, for a particular span.

View file

@ -143,8 +143,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
add_lint_group!(sess, "future_incompatible",
PRIVATE_IN_PUBLIC);
add_lint_group!(sess, FUTURE_INCOMPATIBLE,
PRIVATE_IN_PUBLIC, INVALID_TYPE_PARAM_DEFAULT);
// We have one lint pass defined specially
store.register_late_pass(sess, false, box lint::GatherNodeLevels);

View file

@ -2216,6 +2216,7 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span,
// Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing
// pass for the latter already ran.
lint::raw_struct_lint(&ccx.tcx().sess,
&ccx.tcx().sess.lint_store.borrow(),
lint::builtin::VARIANT_SIZE_DIFFERENCES,
*lvlsrc.unwrap(),
Some(sp),

View file

@ -59,6 +59,7 @@ There are some shortcomings in this design:
*/
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
use lint;
use middle::def;
use middle::def_id::DefId;
use constrained_type_params as ctp;
@ -1910,6 +1911,17 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let parent = tcx.map.get_parent(param.id);
if space != TypeSpace && default.is_some() {
if !tcx.sess.features.borrow().default_type_parameter_fallback {
tcx.sess.add_lint(
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
param.id,
param.span,
format!("defaults for type parameters are only allowed \
on `struct` or `enum` definitions (see issue #27336)"));
}
}
let def = ty::TypeParameterDef {
space: space,
index: index,

View file

@ -10,6 +10,7 @@
#![crate_type = "lib"]
#![crate_name = "default_param_test"]
#![feature(default_type_parameter_fallback)]
use std::marker::PhantomData;

View file

@ -8,5 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(default_type_parameter_fallback)]
fn avg<T=T::Item>(_: T) {} //~ ERROR associated type `Item` not found for `T`
fn main() {}

View file

@ -0,0 +1,17 @@
// Copyright 2015 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(future_incompatible)]
#![allow(dead_code)]
fn avg<T=i32>(_: T) {}
//~^ ERROR defaults for type parameters are only allowed
//~| NOTE HARD ERROR
fn main() {}