Skip to content

Commit 27183a9

Browse files
committed
Feature gate trivial bounds
1 parent d0ec8ea commit 27183a9

File tree

7 files changed

+261
-0
lines changed

7 files changed

+261
-0
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
14751475
}
14761476
ObligationCauseCode::ReturnType(_) |
14771477
ObligationCauseCode::BlockTailExpression(_) => (),
1478+
ObligationCauseCode::TrivialBound => {
1479+
err.help("see issue #48214");
1480+
if tcx.sess.opts.unstable_features.is_nightly_build() {
1481+
err.help("add #![feature(trivial_bounds)] to the \
1482+
crate attributes to enable",
1483+
);
1484+
}
1485+
}
14781486
}
14791487
}
14801488

src/librustc/traits/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ pub enum ObligationCauseCode<'tcx> {
243243

244244
/// Block implicit return
245245
BlockTailExpression(ast::NodeId),
246+
247+
/// #[feature(trivial_bounds)] is not enabled
248+
TrivialBound,
246249
}
247250

248251
#[derive(Clone, Debug, PartialEq, Eq, Hash)]

src/librustc/traits/structural_impls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
243243
super::IntrinsicType => Some(super::IntrinsicType),
244244
super::MethodReceiver => Some(super::MethodReceiver),
245245
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
246+
super::TrivialBound => Some(super::TrivialBound),
246247
}
247248
}
248249
}

src/librustc_typeck/check/wfcheck.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
4646
let param_env = self.param_env;
4747
self.inherited.enter(|inh| {
4848
let fcx = FnCtxt::new(&inh, param_env, id);
49+
if !inh.tcx.features().trivial_bounds {
50+
// As predicates are cached rather than obligations, this
51+
// needsto be called first so that they are checked with an
52+
// empty param_env.
53+
check_false_global_bounds(&fcx, span, id);
54+
}
4955
let wf_tys = f(&fcx, fcx.tcx.global_tcx());
5056
fcx.select_all_obligations_or_error();
5157
fcx.regionck_item(id, span, &wf_tys);
@@ -660,6 +666,41 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
660666
}
661667
}
662668

669+
/// Feature gates RFC 2056 - trivial bounds, checking for global bounds that
670+
/// aren't true.
671+
fn check_false_global_bounds<'a, 'gcx, 'tcx>(
672+
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
673+
span: Span,
674+
id: ast::NodeId,
675+
) {
676+
use rustc::ty::TypeFoldable;
677+
678+
let empty_env = ty::ParamEnv::empty();
679+
680+
let def_id = fcx.tcx.hir.local_def_id(id);
681+
let predicates = fcx.tcx.predicates_of(def_id).predicates;
682+
// Check elaborated bounds
683+
let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
684+
685+
for pred in implied_obligations {
686+
// HAS_LOCAL_NAMES is used to match the existing behvaiour.
687+
if !pred.has_type_flags(ty::TypeFlags::HAS_LOCAL_NAMES) {
688+
let obligation = traits::Obligation::new(
689+
traits::ObligationCause::new(
690+
span,
691+
id,
692+
traits::TrivialBound,
693+
),
694+
empty_env,
695+
pred,
696+
);
697+
fcx.register_predicate(obligation);
698+
}
699+
}
700+
701+
fcx.select_all_obligations_or_error();
702+
}
703+
663704
pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
664705
tcx: TyCtxt<'a, 'tcx, 'tcx>,
665706
}

src/libsyntax/feature_gate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,9 @@ declare_features! (
463463

464464
// Allows use of the :literal macro fragment specifier (RFC 1576)
465465
(active, macro_literal_matcher, "1.27.0", Some(35625), None),
466+
467+
// inconsistent bounds in where clauses
468+
(active, trivial_bounds, "1.28.0", Some(48214), None),
466469
);
467470

468471
declare_features! (
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2018 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+
#![allow(unused)]
12+
#![allow(type_alias_bounds)]
13+
14+
pub trait Foo {
15+
fn test(&self);
16+
}
17+
18+
fn generic_function<X: Foo>(x: X) {}
19+
20+
enum E where i32: Foo { V } //~ ERROR
21+
22+
struct S where i32: Foo; //~ ERROR
23+
24+
trait T where i32: Foo {} //~ ERROR
25+
26+
union U where i32: Foo { f: i32 } //~ ERROR
27+
28+
type Y where i32: Foo = (); // OK - bound is ignored
29+
30+
impl Foo for () where i32: Foo { //~ ERROR
31+
fn test(&self) {
32+
3i32.test();
33+
Foo::test(&4i32);
34+
generic_function(5i32);
35+
}
36+
}
37+
38+
fn f() where i32: Foo //~ ERROR
39+
{
40+
let s = S;
41+
3i32.test();
42+
Foo::test(&4i32);
43+
generic_function(5i32);
44+
}
45+
46+
fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
47+
-s
48+
}
49+
50+
fn use_for() where i32: Iterator { //~ ERROR
51+
for _ in 2i32 {}
52+
}
53+
54+
trait A {}
55+
56+
impl A for i32 {}
57+
58+
struct Dst<X: ?Sized> {
59+
x: X,
60+
}
61+
62+
struct TwoStrs(str, str) where str: Sized; //~ ERROR
63+
64+
fn unsized_local() where Dst<A>: Sized { //~ ERROR
65+
let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
66+
}
67+
68+
fn return_str() -> str where str: Sized { //~ ERROR
69+
*"Sized".to_string().into_boxed_str()
70+
}
71+
72+
// This is currently accepted because the function pointer isn't
73+
// considered global.
74+
fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
75+
x.test();
76+
}
77+
78+
fn main() {}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
error[E0277]: the trait bound `i32: Foo` is not satisfied
2+
--> $DIR/feature-gate-trivial_bounds.rs:20:1
3+
|
4+
LL | enum E where i32: Foo { V } //~ ERROR
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
6+
|
7+
= help: see issue #48214
8+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
9+
10+
error[E0277]: the trait bound `i32: Foo` is not satisfied
11+
--> $DIR/feature-gate-trivial_bounds.rs:22:1
12+
|
13+
LL | struct S where i32: Foo; //~ ERROR
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
15+
|
16+
= help: see issue #48214
17+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
18+
19+
error[E0277]: the trait bound `i32: Foo` is not satisfied
20+
--> $DIR/feature-gate-trivial_bounds.rs:24:1
21+
|
22+
LL | trait T where i32: Foo {} //~ ERROR
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
24+
|
25+
= help: see issue #48214
26+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
27+
28+
error[E0277]: the trait bound `i32: Foo` is not satisfied
29+
--> $DIR/feature-gate-trivial_bounds.rs:26:1
30+
|
31+
LL | union U where i32: Foo { f: i32 } //~ ERROR
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
33+
|
34+
= help: see issue #48214
35+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
36+
37+
error[E0277]: the trait bound `i32: Foo` is not satisfied
38+
--> $DIR/feature-gate-trivial_bounds.rs:30:1
39+
|
40+
LL | / impl Foo for () where i32: Foo { //~ ERROR
41+
LL | | fn test(&self) {
42+
LL | | 3i32.test();
43+
LL | | Foo::test(&4i32);
44+
LL | | generic_function(5i32);
45+
LL | | }
46+
LL | | }
47+
| |_^ the trait `Foo` is not implemented for `i32`
48+
|
49+
= help: see issue #48214
50+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
51+
52+
error[E0277]: the trait bound `i32: Foo` is not satisfied
53+
--> $DIR/feature-gate-trivial_bounds.rs:38:1
54+
|
55+
LL | / fn f() where i32: Foo //~ ERROR
56+
LL | | {
57+
LL | | let s = S;
58+
LL | | 3i32.test();
59+
LL | | Foo::test(&4i32);
60+
LL | | generic_function(5i32);
61+
LL | | }
62+
| |_^ the trait `Foo` is not implemented for `i32`
63+
|
64+
= help: see issue #48214
65+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
66+
67+
error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied
68+
--> $DIR/feature-gate-trivial_bounds.rs:46:1
69+
|
70+
LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
71+
LL | | -s
72+
LL | | }
73+
| |_^ the trait `std::ops::Neg` is not implemented for `std::string::String`
74+
|
75+
= help: see issue #48214
76+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
77+
78+
error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
79+
--> $DIR/feature-gate-trivial_bounds.rs:50:1
80+
|
81+
LL | / fn use_for() where i32: Iterator { //~ ERROR
82+
LL | | for _ in 2i32 {}
83+
LL | | }
84+
| |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
85+
|
86+
= help: the trait `std::iter::Iterator` is not implemented for `i32`
87+
= help: see issue #48214
88+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
89+
90+
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
91+
--> $DIR/feature-gate-trivial_bounds.rs:62:1
92+
|
93+
LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR
94+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time
95+
|
96+
= help: the trait `std::marker::Sized` is not implemented for `str`
97+
= help: see issue #48214
98+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
99+
100+
error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst<A + 'static>`
101+
--> $DIR/feature-gate-trivial_bounds.rs:64:1
102+
|
103+
LL | / fn unsized_local() where Dst<A>: Sized { //~ ERROR
104+
LL | | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
105+
LL | | }
106+
| |_^ `A + 'static` does not have a constant size known at compile-time
107+
|
108+
= help: within `Dst<A + 'static>`, the trait `std::marker::Sized` is not implemented for `A + 'static`
109+
= note: required because it appears within the type `Dst<A + 'static>`
110+
= help: see issue #48214
111+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
112+
113+
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
114+
--> $DIR/feature-gate-trivial_bounds.rs:68:1
115+
|
116+
LL | / fn return_str() -> str where str: Sized { //~ ERROR
117+
LL | | *"Sized".to_string().into_boxed_str()
118+
LL | | }
119+
| |_^ `str` does not have a constant size known at compile-time
120+
|
121+
= help: the trait `std::marker::Sized` is not implemented for `str`
122+
= help: see issue #48214
123+
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
124+
125+
error: aborting due to 11 previous errors
126+
127+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)