Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Feature gate trivial bounds
  • Loading branch information
matthewjasper committed May 15, 2018
commit 27183a903034b1fc3aa3296e497a520508493911
8 changes: 8 additions & 0 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
ObligationCauseCode::ReturnType(_) |
ObligationCauseCode::BlockTailExpression(_) => (),
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
if tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add #![feature(trivial_bounds)] to the \
crate attributes to enable",
);
}
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ pub enum ObligationCauseCode<'tcx> {

/// Block implicit return
BlockTailExpression(ast::NodeId),

/// #[feature(trivial_bounds)] is not enabled
TrivialBound,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Expand Down
1 change: 1 addition & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let param_env = self.param_env;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, param_env, id);
if !inh.tcx.features().trivial_bounds {
// As predicates are cached rather than obligations, this
// needsto be called first so that they are checked with an
// empty param_env.
check_false_global_bounds(&fcx, span, id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it matter if there is something in the cache, actually? It shouldn't, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add some more explanation to this comment. But the reason is that predicates are cached, rather than obligations. The param_env gets emptied for this check but not for the remaining checks, so the usual wf checks will cache any global bounds as true.

}
let wf_tys = f(&fcx, fcx.tcx.global_tcx());
fcx.select_all_obligations_or_error();
fcx.regionck_item(id, span, &wf_tys);
Expand Down Expand Up @@ -660,6 +666,41 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
}
}

/// Feature gates RFC 2056 - trivial bounds, checking for global bounds that
/// aren't true.
fn check_false_global_bounds<'a, 'gcx, 'tcx>(
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
span: Span,
id: ast::NodeId,
) {
use rustc::ty::TypeFoldable;

let empty_env = ty::ParamEnv::empty();

let def_id = fcx.tcx.hir.local_def_id(id);
let predicates = fcx.tcx.predicates_of(def_id).predicates;
// Check elaborated bounds
let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);

for pred in implied_obligations {
// HAS_LOCAL_NAMES is used to match the existing behvaiour.
if !pred.has_type_flags(ty::TypeFlags::HAS_LOCAL_NAMES) {
let obligation = traits::Obligation::new(
traits::ObligationCause::new(
span,
id,
traits::TrivialBound,
),
empty_env,
pred,
);
fcx.register_predicate(obligation);
}
}

fcx.select_all_obligations_or_error();
}

pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,9 @@ declare_features! (

// Allows use of the :literal macro fragment specifier (RFC 1576)
(active, macro_literal_matcher, "1.27.0", Some(35625), None),

// inconsistent bounds in where clauses
(active, trivial_bounds, "1.28.0", Some(48214), None),
);

declare_features! (
Expand Down
78 changes: 78 additions & 0 deletions src/test/ui/feature-gate-trivial_bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2018 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.

#![allow(unused)]
#![allow(type_alias_bounds)]

pub trait Foo {
fn test(&self);
}

fn generic_function<X: Foo>(x: X) {}

enum E where i32: Foo { V } //~ ERROR

struct S where i32: Foo; //~ ERROR

trait T where i32: Foo {} //~ ERROR

union U where i32: Foo { f: i32 } //~ ERROR

type Y where i32: Foo = (); // OK - bound is ignored

impl Foo for () where i32: Foo { //~ ERROR
fn test(&self) {
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}
}

fn f() where i32: Foo //~ ERROR
{
let s = S;
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}

fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
-s
}

fn use_for() where i32: Iterator { //~ ERROR
for _ in 2i32 {}
}

trait A {}

impl A for i32 {}

struct Dst<X: ?Sized> {
x: X,
}

struct TwoStrs(str, str) where str: Sized; //~ ERROR

fn unsized_local() where Dst<A>: Sized { //~ ERROR
let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
}

fn return_str() -> str where str: Sized { //~ ERROR
*"Sized".to_string().into_boxed_str()
}

// This is currently accepted because the function pointer isn't
// considered global.
fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
x.test();
}

fn main() {}
127 changes: 127 additions & 0 deletions src/test/ui/feature-gate-trivial_bounds.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:20:1
|
LL | enum E where i32: Foo { V } //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:22:1
|
LL | struct S where i32: Foo; //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:24:1
|
LL | trait T where i32: Foo {} //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:26:1
|
LL | union U where i32: Foo { f: i32 } //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:30:1
|
LL | / impl Foo for () where i32: Foo { //~ ERROR
LL | | fn test(&self) {
LL | | 3i32.test();
LL | | Foo::test(&4i32);
LL | | generic_function(5i32);
LL | | }
LL | | }
| |_^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:38:1
|
LL | / fn f() where i32: Foo //~ ERROR
LL | | {
LL | | let s = S;
LL | | 3i32.test();
LL | | Foo::test(&4i32);
LL | | generic_function(5i32);
LL | | }
| |_^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:46:1
|
LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
LL | | -s
LL | | }
| |_^ the trait `std::ops::Neg` is not implemented for `std::string::String`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:50:1
|
LL | / fn use_for() where i32: Iterator { //~ ERROR
LL | | for _ in 2i32 {}
LL | | }
| |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `i32`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:62:1
|
LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst<A + 'static>`
--> $DIR/feature-gate-trivial_bounds.rs:64:1
|
LL | / fn unsized_local() where Dst<A>: Sized { //~ ERROR
LL | | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
LL | | }
| |_^ `A + 'static` does not have a constant size known at compile-time
|
= help: within `Dst<A + 'static>`, the trait `std::marker::Sized` is not implemented for `A + 'static`
= note: required because it appears within the type `Dst<A + 'static>`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:68:1
|
LL | / fn return_str() -> str where str: Sized { //~ ERROR
LL | | *"Sized".to_string().into_boxed_str()
LL | | }
| |_^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error: aborting due to 11 previous errors

For more information about this error, try `rustc --explain E0277`.