From 27183a903034b1fc3aa3296e497a520508493911 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 6 May 2018 22:50:35 +0100 Subject: [PATCH] Feature gate trivial bounds --- src/librustc/traits/error_reporting.rs | 8 ++ src/librustc/traits/mod.rs | 3 + src/librustc/traits/structural_impls.rs | 1 + src/librustc_typeck/check/wfcheck.rs | 41 ++++++ src/libsyntax/feature_gate.rs | 3 + src/test/ui/feature-gate-trivial_bounds.rs | 78 +++++++++++ .../ui/feature-gate-trivial_bounds.stderr | 127 ++++++++++++++++++ 7 files changed, 261 insertions(+) create mode 100644 src/test/ui/feature-gate-trivial_bounds.rs create mode 100644 src/test/ui/feature-gate-trivial_bounds.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 25be4a2ff5c..040d738b98f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1475,6 +1475,14 @@ fn note_obligation_cause_code(&self, } 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", + ); + } + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index ca62b421b32..cfc4532a8f2 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -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)] diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 822ea17009b..b9593047af4 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -243,6 +243,7 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option Some(super::IntrinsicType), super::MethodReceiver => Some(super::MethodReceiver), super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), + super::TrivialBound => Some(super::TrivialBound), } } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d0ff44c8e7e..1a1076f74b2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -46,6 +46,12 @@ fn with_fcx(&'tcx mut self, f: F) where 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); + } let wf_tys = f(&fcx, fcx.tcx.global_tcx()); fcx.select_all_obligations_or_error(); fcx.regionck_item(id, span, &wf_tys); @@ -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>, } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index cb5125fe9ef..bf78723e413 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -463,6 +463,9 @@ pub fn walk_feature_fields(&self, mut f: F) // 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! ( diff --git a/src/test/ui/feature-gate-trivial_bounds.rs b/src/test/ui/feature-gate-trivial_bounds.rs new file mode 100644 index 00000000000..ecc6896b754 --- /dev/null +++ b/src/test/ui/feature-gate-trivial_bounds.rs @@ -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 or the MIT license +// , 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: 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 { //~ ERROR + -s +} + +fn use_for() where i32: Iterator { //~ ERROR + for _ in 2i32 {} +} + +trait A {} + +impl A for i32 {} + +struct Dst { + x: X, +} + +struct TwoStrs(str, str) where str: Sized; //~ ERROR + +fn unsized_local() where Dst: Sized { //~ ERROR + let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); +} + +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() {} diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr new file mode 100644 index 00000000000..0794e86175b --- /dev/null +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -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 { //~ 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` + --> $DIR/feature-gate-trivial_bounds.rs:64:1 + | +LL | / fn unsized_local() where Dst: Sized { //~ ERROR +LL | | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); +LL | | } + | |_^ `A + 'static` does not have a constant size known at compile-time + | + = help: within `Dst`, the trait `std::marker::Sized` is not implemented for `A + 'static` + = note: required because it appears within the type `Dst` + = 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`. -- GitLab