Skip to content

Commit 49abd87

Browse files
committed
make bounds on higher-kinded lifetimes a hard error in ast_validation
Also move the check for not having type parameters into ast_validation. I was not sure what to do with compile-fail/issue-23046.rs: The issue looks like maybe the bounds actually played a role in triggering the ICE, but that seems unlikely given that the compiler seems to entirely ignore them. However, I couldn't find a testcase without the bounds, so I figured the best I could do is to just remove the bounds and make sure at least that keeps working.
1 parent 30b5be0 commit 49abd87

File tree

11 files changed

+160
-161
lines changed

11 files changed

+160
-161
lines changed

src/librustc_lint/builtin.rs

+22-69
Original file line numberDiff line numberDiff line change
@@ -1404,79 +1404,32 @@ impl LintPass for IgnoredGenericBounds {
14041404
}
14051405
}
14061406

1407-
impl IgnoredGenericBounds {
1408-
fn ensure_no_param_bounds(
1409-
cx: &EarlyContext,
1410-
generics: &Vec<ast::GenericParam>,
1411-
thing: &'static str,
1412-
) {
1413-
for param in generics.iter() {
1414-
match param {
1415-
&ast::GenericParam::Lifetime(ref lifetime) => {
1416-
if !lifetime.bounds.is_empty() {
1417-
let spans : Vec<_> = lifetime.bounds.iter().map(|b| b.span).collect();
1418-
cx.span_lint(
1419-
IGNORED_GENERIC_BOUNDS,
1420-
spans,
1421-
format!("bounds on generic lifetime parameters are ignored in {}",
1422-
thing).as_ref()
1423-
);
1424-
}
1425-
}
1426-
&ast::GenericParam::Type(ref ty) => {
1427-
if !ty.bounds.is_empty() {
1428-
let spans : Vec<_> = ty.bounds.iter().map(|b| b.span()).collect();
1429-
cx.span_lint(
1430-
IGNORED_GENERIC_BOUNDS,
1431-
spans,
1432-
format!("bounds on generic type parameters are ignored in {}", thing)
1433-
.as_ref()
1434-
);
1435-
}
1436-
}
1437-
}
1438-
}
1439-
}
1440-
}
1441-
14421407
impl EarlyLintPass for IgnoredGenericBounds {
14431408
fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
1444-
match item.node {
1445-
ast::ItemKind::Ty(_, ref generics) => {
1446-
if !generics.where_clause.predicates.is_empty() {
1447-
let spans : Vec<_> = generics.where_clause.predicates.iter()
1448-
.map(|pred| pred.span()).collect();
1449-
cx.span_lint(IGNORED_GENERIC_BOUNDS, spans,
1450-
"where clauses are ignored in type aliases");
1451-
}
1452-
IgnoredGenericBounds::ensure_no_param_bounds(cx, &generics.params,
1453-
"type aliases");
1454-
}
1455-
_ => {}
1456-
}
1457-
}
1458-
1459-
fn check_where_predicate(&mut self, cx: &EarlyContext, p: &ast::WherePredicate) {
1460-
if let &ast::WherePredicate::BoundPredicate(ref bound_predicate) = p {
1461-
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
1462-
IgnoredGenericBounds::ensure_no_param_bounds(cx,
1463-
&bound_predicate.bound_generic_params, "higher-ranked trait bounds (i.e., `for`)");
1409+
let type_alias_generics = match item.node {
1410+
ast::ItemKind::Ty(_, ref generics) => generics,
1411+
_ => return,
1412+
};
1413+
// There must not be a where clause
1414+
if !type_alias_generics.where_clause.predicates.is_empty() {
1415+
let spans : Vec<_> = type_alias_generics.where_clause.predicates.iter()
1416+
.map(|pred| pred.span()).collect();
1417+
cx.span_lint(IGNORED_GENERIC_BOUNDS, spans,
1418+
"where clauses are ignored in type aliases");
14641419
}
1465-
}
1466-
1467-
fn check_poly_trait_ref(&mut self, cx: &EarlyContext, t: &ast::PolyTraitRef,
1468-
_: &ast::TraitBoundModifier) {
1469-
IgnoredGenericBounds::ensure_no_param_bounds(cx, &t.bound_generic_params,
1470-
"higher-ranked trait bounds (i.e., `for`)");
1471-
}
1472-
1473-
fn check_ty(&mut self, cx: &EarlyContext, ty: &ast::Ty) {
1474-
match ty.node {
1475-
ast::TyKind::BareFn(ref fn_ty) => {
1476-
IgnoredGenericBounds::ensure_no_param_bounds(cx, &fn_ty.generic_params,
1477-
"higher-ranked function types (i.e., `for`)");
1420+
// The parameters must not have bounds
1421+
for param in type_alias_generics.params.iter() {
1422+
let spans : Vec<_> = match param {
1423+
&ast::GenericParam::Lifetime(ref l) => l.bounds.iter().map(|b| b.span).collect(),
1424+
&ast::GenericParam::Type(ref ty) => ty.bounds.iter().map(|b| b.span()).collect(),
1425+
};
1426+
if !spans.is_empty() {
1427+
cx.span_lint(
1428+
IGNORED_GENERIC_BOUNDS,
1429+
spans,
1430+
"bounds on generic parameters are ignored in type aliases",
1431+
);
14781432
}
1479-
_ => {}
14801433
}
14811434
}
14821435
}

src/librustc_passes/ast_validation.rs

+41
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,33 @@ impl<'a> AstValidator<'a> {
136136
in patterns")
137137
}
138138
}
139+
140+
fn check_late_bound_lifetime_defs(&self, params: &Vec<GenericParam>) {
141+
// Check: Only lifetime parameters
142+
let non_lifetime_param_spans : Vec<_> = params.iter()
143+
.filter_map(|param| match *param {
144+
GenericParam::Lifetime(_) => None,
145+
GenericParam::Type(ref t) => Some(t.span),
146+
}).collect();
147+
if !non_lifetime_param_spans.is_empty() {
148+
self.err_handler().span_err(non_lifetime_param_spans,
149+
"only lifetime parameters can be used in this context");
150+
}
151+
152+
// Check: No bounds on lifetime parameters
153+
for param in params.iter() {
154+
match *param {
155+
GenericParam::Lifetime(ref l) => {
156+
if !l.bounds.is_empty() {
157+
let spans : Vec<_> = l.bounds.iter().map(|b| b.span).collect();
158+
self.err_handler().span_err(spans,
159+
"lifetime bounds cannot be used in this context");
160+
}
161+
}
162+
GenericParam::Type(_) => {}
163+
}
164+
}
165+
}
139166
}
140167

141168
impl<'a> Visitor<'a> for AstValidator<'a> {
@@ -157,6 +184,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
157184
struct_span_err!(self.session, span, E0561,
158185
"patterns aren't allowed in function pointer types").emit();
159186
});
187+
self.check_late_bound_lifetime_defs(&bfty.generic_params);
160188
}
161189
TyKind::TraitObject(ref bounds, ..) => {
162190
let mut any_lifetime_bounds = false;
@@ -417,6 +445,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
417445

418446
visit::walk_pat(self, pat)
419447
}
448+
449+
fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
450+
if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
451+
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
452+
self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
453+
}
454+
visit::walk_where_predicate(self, p);
455+
}
456+
457+
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
458+
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
459+
visit::walk_poly_trait_ref(self, t, m);
460+
}
420461
}
421462

422463
// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.

src/libsyntax/parse/parser.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -5484,18 +5484,8 @@ impl<'a> Parser<'a> {
54845484
self.expect_lt()?;
54855485
let params = self.parse_generic_params()?;
54865486
self.expect_gt()?;
5487-
5488-
let first_non_lifetime_param_span = params.iter()
5489-
.filter_map(|param| match *param {
5490-
ast::GenericParam::Lifetime(_) => None,
5491-
ast::GenericParam::Type(ref t) => Some(t.span),
5492-
})
5493-
.next();
5494-
5495-
if let Some(span) = first_non_lifetime_param_span {
5496-
self.span_err(span, "only lifetime parameters can be used in this context");
5497-
}
5498-
5487+
// We rely on AST validation to rule out invalid cases: There must not be type
5488+
// parameters, and the lifetime parameters must not have bounds.
54995489
Ok(params)
55005490
} else {
55015491
Ok(Vec::new())
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
type A = for<'b, 'a: 'b> fn(); //~ ERROR lifetime bounds cannot be used in this context
12+
type B = for<'b, 'a: 'b,> fn(); //~ ERROR lifetime bounds cannot be used in this context
13+
type C = for<'b, 'a: 'b +> fn(); //~ ERROR lifetime bounds cannot be used in this context
14+
type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context
15+
type E = for<T> Fn(); //~ ERROR only lifetime parameters can be used in this context
16+
17+
fn main() {}

src/test/compile-fail/issue-23046.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,17 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![allow(ignored_generic_bounds)]
12-
1311
pub enum Expr<'var, VAR> {
1412
Let(Box<Expr<'var, VAR>>,
15-
Box<for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR> + 'var>)
13+
Box<for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR> + 'var>)
1614
}
1715

1816
pub fn add<'var, VAR>
1917
(a: Expr<'var, VAR>, b: Expr<'var, VAR>) -> Expr<'var, VAR> {
2018
loop {}
2119
}
2220

23-
pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
21+
pub fn let_<'var, VAR, F: for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
2422
(a: Expr<'var, VAR>, b: F) -> Expr<'var, VAR> {
2523
loop {}
2624
}

src/test/compile-fail/private-in-public-warn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ mod traits {
5858
pub trait PubTr {}
5959

6060
pub type Alias<T: PrivTr> = T; //~ ERROR private trait `traits::PrivTr` in public interface
61-
//~^ WARNING bounds on generic type parameters are ignored
61+
//~^ WARNING bounds on generic parameters are ignored
6262
//~| WARNING hard error
6363
pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface
6464
//~^ WARNING hard error

src/test/parse-fail/bounds-lifetime.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// compile-flags: -Z parse-only -Z continue-parse-after-error
11+
// compile-flags: -Z parse-only
1212

13-
type A = for<'a: 'b + 'c> fn(); // OK
14-
type A = for<'a: 'b,> fn(); // OK
1513
type A = for<'a:> fn(); // OK
1614
type A = for<'a:,> fn(); // OK
1715
type A = for<'a> fn(); // OK
1816
type A = for<> fn(); // OK
19-
type A = for<'a: 'b +> fn(); // OK
20-
21-
type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context
17+
type A = for<'a: 'b + 'c> fn(); // OK (rejected later by ast_validation)
18+
type A = for<'a: 'b,> fn(); // OK(rejected later by ast_validation)
19+
type A = for<'a: 'b +> fn(); // OK (rejected later by ast_validation)
20+
type A = for<'a, T> fn(); // OK (rejected later by ast_validation)
2221
type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,`
2322

2423
fn main() {}

src/test/parse-fail/bounds-type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct S<
1515
T: Tr + 'a, // OK
1616
T: 'a, // OK
1717
T:, // OK
18-
T: ?for<'a: 'b + 'c> Trait, // OK
18+
T: ?for<'a> Trait, // OK
1919
T: Tr +, // OK
2020
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
2121
>;

src/test/run-pass/impl-trait/lifetimes.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ fn foo(x: &impl Debug) -> &impl Debug { x }
6969
fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x }
7070
fn foo_explicit_arg<T: Debug>(x: &T) -> &impl Debug { x }
7171

72-
fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
73-
fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
72+
fn mixed_lifetimes<'a>() -> impl for<'b> Fn(&'b &'a u32) { |_| () }
73+
fn mixed_as_static() -> impl Fn(&'static &'static u32) { mixed_lifetimes() }
7474

7575
trait MultiRegionTrait<'a, 'b>: Debug {}
7676

src/test/ui/param-bounds-ignored.rs

+15-16
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// must-compile-successfully
1211
#![allow(dead_code, non_camel_case_types)]
1312

1413
use std::rc::Rc;
1514

1615
type SVec<T: Send+Send> = Vec<T>;
17-
//~^ WARN bounds on generic type parameters are ignored in type aliases
16+
//~^ WARN bounds on generic parameters are ignored in type aliases
1817
type VVec<'b, 'a: 'b+'b> = Vec<&'a i32>;
19-
//~^ WARN bounds on generic lifetime parameters are ignored in type aliases
18+
//~^ WARN bounds on generic parameters are ignored in type aliases
2019
type WVec<'b, T: 'b+'b> = Vec<T>;
21-
//~^ WARN bounds on generic type parameters are ignored in type aliases
20+
//~^ WARN bounds on generic parameters are ignored in type aliases
2221
type W2Vec<'b, T> where T: 'b, T: 'b = Vec<T>;
2322
//~^ WARN where clauses are ignored in type aliases
2423

@@ -40,16 +39,16 @@ fn foo<'a>(y: &'a i32) {
4039
fn bar1<'a, 'b>(
4140
x: &'a i32,
4241
y: &'b i32,
43-
f: for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32)
44-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked function types
42+
f: for<'xa, 'xb: 'xa+'xa> fn(&'xa i32, &'xb i32) -> &'xa i32)
43+
//~^ ERROR lifetime bounds cannot be used in this context
4544
{
4645
// If the bound in f's type would matter, the call below would (have to)
4746
// be rejected.
4847
f(x, y);
4948
}
5049

5150
fn bar2<'a, 'b, F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(
52-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
51+
//~^ ERROR lifetime bounds cannot be used in this context
5352
x: &'a i32,
5453
y: &'b i32,
5554
f: F)
@@ -64,7 +63,7 @@ fn bar3<'a, 'b, F>(
6463
y: &'b i32,
6564
f: F)
6665
where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32
67-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
66+
//~^ ERROR lifetime bounds cannot be used in this context
6867
{
6968
// If the bound in f's type would matter, the call below would (have to)
7069
// be rejected.
@@ -76,29 +75,29 @@ fn bar4<'a, 'b, F>(
7675
y: &'b i32,
7776
f: F)
7877
where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32
79-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
78+
//~^ ERROR lifetime bounds cannot be used in this context
8079
{
8180
// If the bound in f's type would matter, the call below would (have to)
8281
// be rejected.
8382
f(x, y);
8483
}
8584

8685
struct S1<F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(F);
87-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
86+
//~^ ERROR lifetime bounds cannot be used in this context
8887
struct S2<F>(F) where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32;
89-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
88+
//~^ ERROR lifetime bounds cannot be used in this context
9089
struct S3<F>(F) where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32;
91-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
90+
//~^ ERROR lifetime bounds cannot be used in this context
9291

9392
struct S_fnty(for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32);
94-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked function types
93+
//~^ ERROR lifetime bounds cannot be used in this context
9594

9695
type T1 = Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>;
97-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
96+
//~^ ERROR lifetime bounds cannot be used in this context
9897

9998
fn main() {
10099
let _ : Option<for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32> = None;
101-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked function types
100+
//~^ ERROR lifetime bounds cannot be used in this context
102101
let _ : Option<Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None;
103-
//~^ WARN bounds on generic lifetime parameters are ignored in higher-ranked trait bounds
102+
//~^ ERROR lifetime bounds cannot be used in this context
104103
}

0 commit comments

Comments
 (0)