From 12ac49afc9e1c33fe94f01dfca9efda4d7fed0b2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 17 Nov 2019 18:43:26 -0500 Subject: [PATCH 01/30] Add feature gate for &mut in const fns --- src/librustc_feature/active.rs | 3 +++ src/libsyntax_pos/symbol.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 16d8ada9f24c0..706e102436517 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -527,6 +527,9 @@ declare_features! ( /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), + /// Allows using `&mut` in constant functions. + (active, const_fn_mut_refs, "1.41.0", None, None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 3059b05969106..c98063275dd34 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -203,6 +203,7 @@ symbols! { const_constructor, const_extern_fn, const_fn, + const_fn_mut_refs, const_fn_union, const_generics, const_if_match, From bb2a4238946563ef87eed6fe7e833ca731fa4c79 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 17 Nov 2019 21:11:46 -0500 Subject: [PATCH 02/30] Allow &mut in const fns when feature gate is enabled --- src/librustc_mir/transform/qualify_min_const_fn.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index e40d6a5952edb..28240f6beca71 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -80,10 +80,14 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { for ty in ty.walk() { match ty.kind { - ty::Ref(_, _, hir::Mutability::Mutable) => return Err(( - span, - "mutable references in const fn are unstable".into(), - )), + ty::Ref(_, _, hir::Mutability::Mutable) => { + if !tcx.features().const_fn_mut_refs { + return Err(( + span, + "mutable references in const fn are unstable".into(), + )) + } + } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { From 8b0f5acfcbc178680f3cbec737b13bf0da6c05bd Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 21 Nov 2019 08:45:34 -0500 Subject: [PATCH 03/30] Add tests for mutable borrows in const fns --- .../const-eval/feature-gate-const_fn_mut_refs.rs | 7 +++++++ .../feature-gate-const_fn_mut_refs.stderr | 12 ++++++++++++ src/test/ui/consts/const_fn_mut_refs.rs | 15 +++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.rs create mode 100644 src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr create mode 100644 src/test/ui/consts/const_fn_mut_refs.rs diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.rs b/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.rs new file mode 100644 index 0000000000000..2207599815ee8 --- /dev/null +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.rs @@ -0,0 +1,7 @@ +fn main() { + foo(&mut 5); +} + +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable + *x + 1 +} diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr new file mode 100644 index 0000000000000..26a61d38f8c3c --- /dev/null +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr @@ -0,0 +1,12 @@ +error[E0723]: mutable references in const fn are unstable + --> $DIR/feature-gate-const_fn_mut_refs.rs:5:14 + | +LL | const fn foo(x: &mut i32) -> i32 { + | ^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/const_fn_mut_refs.rs b/src/test/ui/consts/const_fn_mut_refs.rs new file mode 100644 index 0000000000000..764c45b386b06 --- /dev/null +++ b/src/test/ui/consts/const_fn_mut_refs.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(const_fn_mut_refs)] + +struct Foo { + x: i32 +} + +const fn bar(foo: &mut Foo) -> i32 { + foo.x + 1 +} + +fn main() { + assert_eq!(bar(&mut Foo{x: 0}), 1); +} From d24ae2577fad83d581d090816303b0f1842f1514 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 21 Nov 2019 12:38:14 -0500 Subject: [PATCH 04/30] Rename feature gate --- src/librustc_feature/active.rs | 2 +- src/librustc_mir/transform/qualify_min_const_fn.rs | 2 +- src/libsyntax_pos/symbol.rs | 2 +- src/test/ui/consts/const_fn_mut_refs.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 706e102436517..8e3ef4f3d9dca 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -528,7 +528,7 @@ declare_features! ( (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows using `&mut` in constant functions. - (active, const_fn_mut_refs, "1.41.0", None, None), + (active, const_mut_refs, "1.41.0", Some(57349), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 28240f6beca71..20bccb59a5cfb 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -81,7 +81,7 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> Mc for ty in ty.walk() { match ty.kind { ty::Ref(_, _, hir::Mutability::Mutable) => { - if !tcx.features().const_fn_mut_refs { + if !tcx.features().const_mut_refs { return Err(( span, "mutable references in const fn are unstable".into(), diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index c98063275dd34..d700f779e1773 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -203,13 +203,13 @@ symbols! { const_constructor, const_extern_fn, const_fn, - const_fn_mut_refs, const_fn_union, const_generics, const_if_match, const_indexing, const_in_array_repeat_expressions, const_let, + const_mut_refs, const_panic, const_raw_ptr_deref, const_raw_ptr_to_usize_cast, diff --git a/src/test/ui/consts/const_fn_mut_refs.rs b/src/test/ui/consts/const_fn_mut_refs.rs index 764c45b386b06..2263a130284a5 100644 --- a/src/test/ui/consts/const_fn_mut_refs.rs +++ b/src/test/ui/consts/const_fn_mut_refs.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(const_fn_mut_refs)] +#![feature(const_mut_refs)] struct Foo { x: i32 From 1f420b9891c962656eac16831c772cbd56afff24 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 21 Nov 2019 14:33:39 -0500 Subject: [PATCH 05/30] Allow mutable borrows in constant bodies --- src/librustc_mir/transform/check_consts/ops.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index a4f12a4e54fa7..117d628af257f 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -183,6 +183,10 @@ impl NonConstOp for Loop { #[derive(Debug)] pub struct MutBorrow(pub BorrowKind); impl NonConstOp for MutBorrow { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_mut_refs) + } + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { let kind = self.0; if let BorrowKind::Mut { .. } = kind { From de60f721c4983b1d43a305f0603a7ba6207b888d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 21 Nov 2019 14:35:19 -0500 Subject: [PATCH 06/30] Move and rewrite tests to use &mut in constants --- .../ui/consts/const-mut-refs/const_mut_refs.rs | 15 +++++++++++++++ .../feature-gate-const_mut_refs.rs} | 0 .../feature-gate-const_mut_refs.stderr} | 2 +- src/test/ui/consts/const_fn_mut_refs.rs | 15 --------------- 4 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/consts/const-mut-refs/const_mut_refs.rs rename src/test/ui/consts/{const-eval/feature-gate-const_fn_mut_refs.rs => const-mut-refs/feature-gate-const_mut_refs.rs} (100%) rename src/test/ui/consts/{const-eval/feature-gate-const_fn_mut_refs.stderr => const-mut-refs/feature-gate-const_mut_refs.stderr} (88%) delete mode 100644 src/test/ui/consts/const_fn_mut_refs.rs diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs new file mode 100644 index 0000000000000..60a69cb9f3f67 --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(const_mut_refs)] + +struct Foo { + x: usize +} + +const fn bar(foo: &mut Foo) -> usize { + foo.x + 1 +} + +fn main() { + let _: [(); bar(&mut Foo { x: 0 })] = [(); 1]; +} diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs similarity index 100% rename from src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.rs rename to src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr similarity index 88% rename from src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr rename to src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr index 26a61d38f8c3c..4fae119f02604 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_mut_refs.stderr +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr @@ -1,5 +1,5 @@ error[E0723]: mutable references in const fn are unstable - --> $DIR/feature-gate-const_fn_mut_refs.rs:5:14 + --> $DIR/feature-gate-const_mut_refs.rs:5:14 | LL | const fn foo(x: &mut i32) -> i32 { | ^ diff --git a/src/test/ui/consts/const_fn_mut_refs.rs b/src/test/ui/consts/const_fn_mut_refs.rs deleted file mode 100644 index 2263a130284a5..0000000000000 --- a/src/test/ui/consts/const_fn_mut_refs.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -#![feature(const_mut_refs)] - -struct Foo { - x: i32 -} - -const fn bar(foo: &mut Foo) -> i32 { - foo.x + 1 -} - -fn main() { - assert_eq!(bar(&mut Foo{x: 0}), 1); -} From d92e9b7374bb2087e0eb4803bfabb030c1397bcd Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 22 Nov 2019 19:59:34 -0500 Subject: [PATCH 07/30] Allow mutable derefs with feature gate --- src/librustc_mir/transform/check_consts/ops.rs | 6 +++++- src/test/ui/consts/const-mut-refs/const_mut_refs.rs | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 117d628af257f..be5845eaa365f 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -216,7 +216,11 @@ impl NonConstOp for MutBorrow { #[derive(Debug)] pub struct MutDeref; -impl NonConstOp for MutDeref {} +impl NonConstOp for MutDeref { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_mut_refs) + } +} #[derive(Debug)] pub struct Panic; diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs index 60a69cb9f3f67..36174b2843d31 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs @@ -7,7 +7,9 @@ struct Foo { } const fn bar(foo: &mut Foo) -> usize { - foo.x + 1 + let x = &mut foo.x; + *x = 1; + *x } fn main() { From e31a1368fda9c5b4b4bc39e69754b19d36dff8c2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 23 Nov 2019 15:00:14 -0500 Subject: [PATCH 08/30] Extend test for const_mut_refs feature --- .../consts/const-mut-refs/const_mut_refs.rs | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs index 36174b2843d31..99006a20b1bcb 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs @@ -6,12 +6,31 @@ struct Foo { x: usize } -const fn bar(foo: &mut Foo) -> usize { +const fn foo() -> Foo { + Foo { x: 0 } +} + +impl Foo { + const fn bar(&mut self) -> usize { + self.x = 1; + self.x + } + +} + +const fn baz(foo: &mut Foo) -> usize { let x = &mut foo.x; - *x = 1; + *x = 2; *x } +const fn bazz(foo: &mut Foo) -> usize { + foo.x = 3; + foo.x +} + fn main() { - let _: [(); bar(&mut Foo { x: 0 })] = [(); 1]; + let _: [(); foo().bar()] = [(); 1]; + let _: [(); baz(&mut foo())] = [(); 2]; + let _: [(); bazz(&mut foo())] = [(); 3]; } From 683f5c9c23a07fc6434b3e15207aa12144c90420 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 26 Nov 2019 10:00:41 -0500 Subject: [PATCH 09/30] Disallow cell borrowing --- .../transform/check_consts/ops.rs | 50 ++++++++++--------- .../transform/check_consts/validation.rs | 13 +++-- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index be5845eaa365f..1d23b6e27f31c 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -1,7 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use rustc::hir::def_id::DefId; -use rustc::mir::BorrowKind; use rustc::session::config::nightly_options; use rustc::ty::TyCtxt; use syntax::feature_gate::feature_err; @@ -181,36 +180,39 @@ impl NonConstOp for Loop { } #[derive(Debug)] -pub struct MutBorrow(pub BorrowKind); +pub struct CellBorrow; +impl NonConstOp for CellBorrow { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + span_err!(item.tcx.sess, span, E0492, + "cannot borrow a constant which may contain \ + interior mutability, create a static instead"); + } +} + +#[derive(Debug)] +pub struct MutBorrow; impl NonConstOp for MutBorrow { fn feature_gate(tcx: TyCtxt<'_>) -> Option { Some(tcx.features().const_mut_refs) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - let kind = self.0; - if let BorrowKind::Mut { .. } = kind { - let mut err = struct_span_err!(item.tcx.sess, span, E0017, - "references in {}s may only refer \ - to immutable values", item.const_kind()); - err.span_label(span, format!("{}s require immutable values", - item.const_kind())); - if item.tcx.sess.teach(&err.get_code().unwrap()) { - err.note("References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell."); - } - err.emit(); - } else { - span_err!(item.tcx.sess, span, E0492, - "cannot borrow a constant which may contain \ - interior mutability, create a static instead"); + let mut err = struct_span_err!(item.tcx.sess, span, E0017, + "references in {}s may only refer \ + to immutable values", item.const_kind()); + err.span_label(span, format!("{}s require immutable values", + item.const_kind())); + if item.tcx.sess.teach(&err.get_code().unwrap()) { + err.note("References in statics and constants may only refer \ + to immutable values.\n\n\ + Statics are shared everywhere, and if they refer to \ + mutable data one might violate memory safety since \ + holding multiple mutable references to shared data \ + is not allowed.\n\n\ + If you really want global mutable state, try using \ + static mut or a global UnsafeCell."); } + err.emit(); } } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 783c64ece7371..4a55bce767d81 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -360,7 +360,11 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { }; if !is_allowed { - self.check_op(ops::MutBorrow(kind)); + if let BorrowKind::Mut{ .. } = kind { + self.check_op(ops::MutBorrow); + } else { + self.check_op(ops::CellBorrow); + } } } @@ -385,7 +389,11 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { ); if borrowed_place_has_mut_interior { - self.check_op(ops::MutBorrow(kind)); + if let BorrowKind::Mut{ .. } = kind { + self.check_op(ops::MutBorrow); + } else { + self.check_op(ops::CellBorrow); + } } } @@ -452,7 +460,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } } } - fn visit_projection_elem( &mut self, place_base: &PlaceBase<'tcx>, From 681690db4e41505401a0ebbf3d1e4bec69ead702 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 26 Nov 2019 11:00:30 -0500 Subject: [PATCH 10/30] Update miri_unleashed tests --- .../ui/consts/miri_unleashed/mutable_const.rs | 4 +-- .../miri_unleashed/mutable_const.stderr | 22 ++------------- .../miri_unleashed/mutable_references.rs | 5 +--- .../miri_unleashed/mutable_references.stderr | 28 ++----------------- 4 files changed, 6 insertions(+), 53 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs index 44b408494679c..cf5e6d6002581 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs @@ -12,9 +12,7 @@ const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; const MUTATING_BEHIND_RAW: () = { // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. unsafe { - *MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks - //~^ ERROR any use of this value will cause an error - //~^^ tried to modify constant memory + *MUTABLE_BEHIND_RAW = 99 //~ ERROR constant contains unimplemented expression type } }; diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr index 757f0ffb59ff7..1a18063625be3 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr @@ -4,30 +4,12 @@ warning: skipping const checks LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ -warning: skipping const checks +error[E0019]: constant contains unimplemented expression type --> $DIR/mutable_const.rs:15:9 | LL | *MUTABLE_BEHIND_RAW = 99 | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: any use of this value will cause an error - --> $DIR/mutable_const.rs:15:9 - | -LL | / const MUTATING_BEHIND_RAW: () = { -LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. -LL | | unsafe { -LL | | *MUTABLE_BEHIND_RAW = 99 - | | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory -... | -LL | | } -LL | | }; - | |__- - | -note: lint level defined here - --> $DIR/mutable_const.rs:4:9 - | -LL | #![deny(const_err)] - | ^^^^^^^^^ - error: aborting due to previous error +For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs index 59dafcbf4d50c..d95833e3071df 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs @@ -1,4 +1,5 @@ // compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_mut_refs)] #![allow(const_err)] use std::cell::UnsafeCell; @@ -6,15 +7,12 @@ use std::cell::UnsafeCell; // a test demonstrating what things we could allow with a smarter const qualification static FOO: &&mut u32 = &&mut 42; -//~^ WARN: skipping const checks static BAR: &mut () = &mut (); -//~^ WARN: skipping const checks struct Foo(T); static BOO: &mut Foo<()> = &mut Foo(()); -//~^ WARN: skipping const checks struct Meh { x: &'static UnsafeCell, @@ -28,7 +26,6 @@ static MEH: Meh = Meh { }; static OH_YES: &mut i32 = &mut 42; -//~^ WARN: skipping const checks fn main() { unsafe { diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index b9c0af33c39cd..ce1f5f38dd99a 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,35 +1,11 @@ warning: skipping const checks - --> $DIR/mutable_references.rs:8:26 - | -LL | static FOO: &&mut u32 = &&mut 42; - | ^^^^^^^ - -warning: skipping const checks - --> $DIR/mutable_references.rs:11:23 - | -LL | static BAR: &mut () = &mut (); - | ^^^^^^^ - -warning: skipping const checks - --> $DIR/mutable_references.rs:16:28 - | -LL | static BOO: &mut Foo<()> = &mut Foo(()); - | ^^^^^^^^^^^^ - -warning: skipping const checks - --> $DIR/mutable_references.rs:26:8 + --> $DIR/mutable_references.rs:24:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -warning: skipping const checks - --> $DIR/mutable_references.rs:30:27 - | -LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^ - error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:37:5 + --> $DIR/mutable_references.rs:34:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign From 5e61e4cadc72141f9e4c80ca8615509f2eaeb51f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 26 Nov 2019 22:43:40 -0500 Subject: [PATCH 11/30] Suggest feature for const_mut_refs errors --- src/librustc_mir/transform/check_consts/ops.rs | 10 +++++++--- src/test/ui/consts/const-eval/issue-65394.stderr | 9 ++++++--- src/test/ui/consts/const-multi-ref.stderr | 9 ++++++--- src/test/ui/consts/const_let_assign3.stderr | 14 ++++++++++---- src/test/ui/consts/projection_qualif.stderr | 9 ++++++--- .../consts/static_mut_containing_mut_ref2.stderr | 9 ++++++--- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 1d23b6e27f31c..182ba4625667a 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -197,9 +197,13 @@ impl NonConstOp for MutBorrow { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - let mut err = struct_span_err!(item.tcx.sess, span, E0017, - "references in {}s may only refer \ - to immutable values", item.const_kind()); + let mut err = feature_err( + &item.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("references in {}s may only refer \ + to immutable values", item.const_kind()) + ); err.span_label(span, format!("{}s require immutable values", item.const_kind())); if item.tcx.sess.teach(&err.get_code().unwrap()) { diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr index acf5cbaede665..54b35073340fd 100644 --- a/src/test/ui/consts/const-eval/issue-65394.stderr +++ b/src/test/ui/consts/const-eval/issue-65394.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/issue-65394.rs:8:13 | LL | let r = &mut x; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/issue-65394.rs:7:9 @@ -12,5 +15,5 @@ LL | let mut x = Vec::::new(); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0493. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0493, E0658. +For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr index ed3837e9c9ee5..0809c77c1b604 100644 --- a/src/test/ui/consts/const-multi-ref.stderr +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/const-multi-ref.rs:6:13 | LL | let p = &mut a; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/const-multi-ref.rs:16:13 @@ -12,5 +15,5 @@ LL | let p = &a; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0492. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0492, E0658. +For more information about an error, try `rustc --explain E0492`. diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 53b960b4ec0e0..7852874944b22 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -4,17 +4,23 @@ error[E0019]: constant function contains unimplemented expression type LL | self.state = x; | ^^^^^^^^^^^^^^ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/const_let_assign3.rs:16:5 | LL | s.foo(3); | ^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/const_let_assign3.rs:22:13 | LL | let y = &mut x; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0019]: constant contains unimplemented expression type --> $DIR/const_let_assign3.rs:24:5 @@ -24,5 +30,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0017, E0019. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr index 0efb6bfd10a17..41c7b62812c08 100644 --- a/src/test/ui/consts/projection_qualif.stderr +++ b/src/test/ui/consts/projection_qualif.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/projection_qualif.rs:6:27 | LL | let b: *mut u32 = &mut a; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/projection_qualif.rs:7:18 @@ -21,5 +24,5 @@ LL | unsafe { *b = 5; } error: aborting due to 3 previous errors -Some errors have detailed explanations: E0017, E0019, E0658. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr index ca691b07be063..e0074687874fe 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/static_mut_containing_mut_ref2.rs:3:46 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0019]: static contains unimplemented expression type --> $DIR/static_mut_containing_mut_ref2.rs:3:45 @@ -12,5 +15,5 @@ LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 4 error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0019. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. From 19ddfb545bb6e70ba3281bdce4f40ae8e564a53a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 28 Nov 2019 11:38:07 -0500 Subject: [PATCH 12/30] Update miri unleashed tests --- .../ui/consts/miri_unleashed/mutable_const.rs | 3 ++- .../miri_unleashed/mutable_const.stderr | 23 ++++++++++++++----- .../miri_unleashed/mutable_references.rs | 5 ++++ .../miri_unleashed/mutable_references.stderr | 4 ++-- .../consts/miri_unleashed/read_from_static.rs | 11 +++++++++ 5 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/consts/miri_unleashed/read_from_static.rs diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs index cf5e6d6002581..972f59549ea74 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs @@ -1,6 +1,7 @@ // compile-flags: -Zunleash-the-miri-inside-of-you #![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] #![deny(const_err)] use std::cell::UnsafeCell; @@ -12,7 +13,7 @@ const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; const MUTATING_BEHIND_RAW: () = { // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. unsafe { - *MUTABLE_BEHIND_RAW = 99 //~ ERROR constant contains unimplemented expression type + *MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error } }; diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr index 1a18063625be3..9daca765c7cd0 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr @@ -1,15 +1,26 @@ warning: skipping const checks - --> $DIR/mutable_const.rs:9:38 + --> $DIR/mutable_const.rs:10:38 | LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ -error[E0019]: constant contains unimplemented expression type - --> $DIR/mutable_const.rs:15:9 +error: any use of this value will cause an error + --> $DIR/mutable_const.rs:16:9 | -LL | *MUTABLE_BEHIND_RAW = 99 - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / const MUTATING_BEHIND_RAW: () = { +LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. +LL | | unsafe { +LL | | *MUTABLE_BEHIND_RAW = 99 + | | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory +LL | | } +LL | | }; + | |__- + | +note: lint level defined here + --> $DIR/mutable_const.rs:5:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs index d95833e3071df..fe3c4ee70f2a2 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs @@ -6,12 +6,16 @@ use std::cell::UnsafeCell; // a test demonstrating what things we could allow with a smarter const qualification +// this is fine because is not possible to mutate through an immutable reference. static FOO: &&mut u32 = &&mut 42; +// this is fine because accessing an immutable static `BAR` is equivalent to accessing `*&BAR` +// which puts the mutable reference behind an immutable one. static BAR: &mut () = &mut (); struct Foo(T); +// this is fine for the same reason as `BAR`. static BOO: &mut Foo<()> = &mut Foo(()); struct Meh { @@ -25,6 +29,7 @@ static MEH: Meh = Meh { //~^ WARN: skipping const checks }; +// this is fine for the same reason as `BAR`. static OH_YES: &mut i32 = &mut 42; fn main() { diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index ce1f5f38dd99a..3e1300c63c17d 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,11 +1,11 @@ warning: skipping const checks - --> $DIR/mutable_references.rs:24:8 + --> $DIR/mutable_references.rs:28:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:34:5 + --> $DIR/mutable_references.rs:39:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign diff --git a/src/test/ui/consts/miri_unleashed/read_from_static.rs b/src/test/ui/consts/miri_unleashed/read_from_static.rs new file mode 100644 index 0000000000000..821c501c9fcc5 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/read_from_static.rs @@ -0,0 +1,11 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_mut_refs)] +#![allow(const_err)] + +static OH_YES: &mut i32 = &mut 42; + +fn main() { + // Make sure `OH_YES` can be read. + assert_eq!(*OH_YES, 42); +} From dc0117a42c000428914ed3ca42ba1a287f622694 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 28 Nov 2019 11:57:34 -0500 Subject: [PATCH 13/30] Add dual tests for const_mut_refs --- src/test/ui/consts/projection_qualif.mut_refs.stderr | 12 ++++++++++++ src/test/ui/consts/projection_qualif.rs | 8 ++++++-- ..._qualif.stderr => projection_qualif.stock.stderr} | 6 +++--- .../static_mut_containing_mut_ref2.mut_refs.stderr | 9 +++++++++ src/test/ui/consts/static_mut_containing_mut_ref2.rs | 9 +++++++-- ...r => static_mut_containing_mut_ref2.stock.stderr} | 4 ++-- 6 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/consts/projection_qualif.mut_refs.stderr rename src/test/ui/consts/{projection_qualif.stderr => projection_qualif.stock.stderr} (89%) create mode 100644 src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr rename src/test/ui/consts/{static_mut_containing_mut_ref2.stderr => static_mut_containing_mut_ref2.stock.stderr} (89%) diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr new file mode 100644 index 0000000000000..23538777c9df3 --- /dev/null +++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr @@ -0,0 +1,12 @@ +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/projection_qualif.rs:11:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index dedb7db592089..cfe8e7f03d5e4 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -1,11 +1,15 @@ +// revisions: stock mut_refs + +#![cfg_attr(mut_refs, feature(const_mut_refs))] + use std::cell::Cell; const FOO: &u32 = { let mut a = 42; { - let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values + let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants - //~^ contains unimplemented expression + //[stock]~^ contains unimplemented expression } &{a} }; diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stock.stderr similarity index 89% rename from src/test/ui/consts/projection_qualif.stderr rename to src/test/ui/consts/projection_qualif.stock.stderr index 41c7b62812c08..472d2607453d0 100644 --- a/src/test/ui/consts/projection_qualif.stderr +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: references in constants may only refer to immutable values - --> $DIR/projection_qualif.rs:6:27 + --> $DIR/projection_qualif.rs:10:27 | LL | let b: *mut u32 = &mut a; | ^^^^^^ constants require immutable values @@ -8,7 +8,7 @@ LL | let b: *mut u32 = &mut a; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: dereferencing raw pointers in constants is unstable - --> $DIR/projection_qualif.rs:7:18 + --> $DIR/projection_qualif.rs:11:18 | LL | unsafe { *b = 5; } | ^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe { *b = 5; } = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable error[E0019]: constant contains unimplemented expression type - --> $DIR/projection_qualif.rs:7:18 + --> $DIR/projection_qualif.rs:11:18 | LL | unsafe { *b = 5; } | ^^^^^^ diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr new file mode 100644 index 0000000000000..b43fbc86f99f2 --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/static_mut_containing_mut_ref2.rs:7:45 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index ef378fa84518e..74162fbd54b04 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -1,7 +1,12 @@ +// revisions: stock mut_refs + +#![cfg_attr(mut_refs, feature(const_mut_refs))] + static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//~^ ERROR references in statics may only refer to immutable values -//~| ERROR static contains unimplemented expression type +//[mut_refs]~^ ERROR could not evaluate static initializer +//[stock]~^^ ERROR references in statics may only refer to immutable values +//[stock]~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr similarity index 89% rename from src/test/ui/consts/static_mut_containing_mut_ref2.stderr rename to src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr index e0074687874fe..430cef94dc3cb 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: references in statics may only refer to immutable values - --> $DIR/static_mut_containing_mut_ref2.rs:3:46 + --> $DIR/static_mut_containing_mut_ref2.rs:7:46 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values @@ -8,7 +8,7 @@ LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 4 = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0019]: static contains unimplemented expression type - --> $DIR/static_mut_containing_mut_ref2.rs:3:45 + --> $DIR/static_mut_containing_mut_ref2.rs:7:45 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 416b439ffbdf6840bb3c663fea0246d3ead9a5dc Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 28 Nov 2019 12:20:28 -0500 Subject: [PATCH 14/30] Correct other tests related to const_mut_refs --- .../compile-fail/consts/const-fn-error.rs | 2 +- .../check-static-immutable-mut-slices.stderr | 7 ++- src/test/ui/error-codes/E0017.rs | 8 ++-- src/test/ui/error-codes/E0017.stderr | 24 ++++++++--- src/test/ui/error-codes/E0388.rs | 10 +++++ src/test/ui/error-codes/E0388.stderr | 43 +++++++++++++++++++ .../issue-17718-const-bad-values.stderr | 12 ++++-- src/test/ui/issues/issue-46604.rs | 2 +- src/test/ui/issues/issue-46604.stderr | 9 ++-- 9 files changed, 97 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/error-codes/E0388.rs create mode 100644 src/test/ui/error-codes/E0388.stderr diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs index 1a4fc72e81786..5d26059644d17 100644 --- a/src/test/compile-fail/consts/const-fn-error.rs +++ b/src/test/compile-fail/consts/const-fn-error.rs @@ -6,7 +6,7 @@ const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { //~^ ERROR E0015 - //~| ERROR E0017 + //~| ERROR E0658 //~| ERROR E0080 //~| ERROR E0744 //~| ERROR E0019 diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr index 4f4bf16a0ff69..39da824ede57c 100644 --- a/src/test/ui/check-static-immutable-mut-slices.stderr +++ b/src/test/ui/check-static-immutable-mut-slices.stderr @@ -1,9 +1,12 @@ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/check-static-immutable-mut-slices.rs:3:37 | LL | static TEST: &'static mut [isize] = &mut []; | ^^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0017`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 3bc518c2c2b71..64be41170d0c8 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -2,10 +2,10 @@ static X: i32 = 1; const C: i32 = 2; static mut M: i32 = 3; -const CR: &'static mut i32 = &mut C; //~ ERROR E0017 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 +const CR: &'static mut i32 = &mut C; //~ ERROR E0658 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 //~| ERROR E0019 //~| ERROR cannot borrow -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 -static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0017 +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658 +static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 8c8660adceb7a..9a87195a9d05e 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0019]: static contains unimplemented expression type --> $DIR/E0017.rs:6:39 @@ -10,11 +13,14 @@ error[E0019]: static contains unimplemented expression type LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0017.rs:6:39 @@ -22,19 +28,25 @@ error[E0596]: cannot borrow immutable static item `X` as mutable LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:10:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 6 previous errors -Some errors have detailed explanations: E0017, E0019, E0596. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0019, E0596, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs new file mode 100644 index 0000000000000..5954e3490b06c --- /dev/null +++ b/src/test/ui/error-codes/E0388.rs @@ -0,0 +1,10 @@ +static X: i32 = 1; +const C: i32 = 2; + +const CR: &'static mut i32 = &mut C; //~ ERROR E0658 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 + //~| ERROR cannot borrow + //~| ERROR E0019 +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658 + +fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr new file mode 100644 index 0000000000000..986307d3f123f --- /dev/null +++ b/src/test/ui/error-codes/E0388.stderr @@ -0,0 +1,43 @@ +error[E0658]: references in constants may only refer to immutable values + --> $DIR/E0388.rs:4:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0019]: static contains unimplemented expression type + --> $DIR/E0388.rs:5:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ + +error[E0658]: references in statics may only refer to immutable values + --> $DIR/E0388.rs:5:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/E0388.rs:5:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ cannot borrow as mutable + +error[E0658]: references in statics may only refer to immutable values + --> $DIR/E0388.rs:8:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0019, E0596, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr index 8d875d37d85f9..7e4a62ac96957 100644 --- a/src/test/ui/issues/issue-17718-const-bad-values.stderr +++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/issue-17718-const-bad-values.rs:1:34 | LL | const C1: &'static mut [usize] = &mut []; | ^^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0013]: constants cannot refer to statics, use a constant instead --> $DIR/issue-17718-const-bad-values.rs:5:46 @@ -10,13 +13,16 @@ error[E0013]: constants cannot refer to statics, use a constant instead LL | const C2: &'static mut usize = unsafe { &mut S }; | ^ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/issue-17718-const-bad-values.rs:5:41 | LL | const C2: &'static mut usize = unsafe { &mut S }; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 3 previous errors -Some errors have detailed explanations: E0013, E0017. +Some errors have detailed explanations: E0013, E0658. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs index 4f1ad38dbdd94..e1967eb765542 100644 --- a/src/test/ui/issues/issue-46604.rs +++ b/src/test/ui/issues/issue-46604.rs @@ -1,4 +1,4 @@ -static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0017 +static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0658 fn write>(buffer: T) { } fn main() { diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr index c72f580f24391..32c7ecbf72e95 100644 --- a/src/test/ui/issues/issue-46604.stderr +++ b/src/test/ui/issues/issue-46604.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/issue-46604.rs:1:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:6:5 @@ -12,5 +15,5 @@ LL | buf[0]=2; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0594. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0594, E0658. +For more information about an error, try `rustc --explain E0594`. From e01ad6a01abce35f59543bf38a280a05eb7f6929 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 29 Nov 2019 21:54:27 -0500 Subject: [PATCH 15/30] Remove E0017 from error codes index --- src/librustc_error_codes/error_codes.rs | 1 - src/librustc_error_codes/error_codes/E0017.md | 20 ------------------- 2 files changed, 21 deletions(-) delete mode 100644 src/librustc_error_codes/error_codes/E0017.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 7f111b42403b5..259fd51c4362e 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -18,7 +18,6 @@ E0010: include_str!("./error_codes/E0010.md"), E0013: include_str!("./error_codes/E0013.md"), E0014: include_str!("./error_codes/E0014.md"), E0015: include_str!("./error_codes/E0015.md"), -E0017: include_str!("./error_codes/E0017.md"), E0019: include_str!("./error_codes/E0019.md"), E0023: include_str!("./error_codes/E0023.md"), E0025: include_str!("./error_codes/E0025.md"), diff --git a/src/librustc_error_codes/error_codes/E0017.md b/src/librustc_error_codes/error_codes/E0017.md deleted file mode 100644 index d5e6857b4d6f8..0000000000000 --- a/src/librustc_error_codes/error_codes/E0017.md +++ /dev/null @@ -1,20 +0,0 @@ -References in statics and constants may only refer to immutable values. - -Erroneous code example: - -```compile_fail,E0017 -static X: i32 = 1; -const C: i32 = 2; - -// these three are not allowed: -const CR: &mut i32 = &mut C; -static STATIC_REF: &'static mut i32 = &mut X; -static CONST_REF: &'static mut i32 = &mut C; -``` - -Statics are shared everywhere, and if they refer to mutable data one might -violate memory safety since holding multiple mutable references to shared data -is not allowed. - -If you really want global mutable state, try using `static mut` or a global -`UnsafeCell`. From 462f06de07d8a5c071c4d8040dad006198f029c9 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 3 Dec 2019 20:32:50 -0500 Subject: [PATCH 16/30] Emit coercion suggestions in more places Fixes #66910 We have several different kinds of suggestions we can try to make when type coercion fails. However, we were previously only emitting these suggestions from `demand_coerce_diag`. This resulted in the compiler failing to emit applicable suggestions in several different cases, such as when the implicit return value of a function had the wrong type. This commit adds a new `emit_coerce_suggestions` method, which tries to emit a number of related suggestions. This method is called from both `demand_coerce_diag` and `CoerceMany::coerce_inner`, which covers a much wider range of cases than before. We now suggest using `.await` in more cases where it is applicable, among other improvements. --- src/librustc_typeck/check/coercion.rs | 4 ++++ src/librustc_typeck/check/demand.rs | 22 ++++++++++++++----- src/librustc_typeck/check/mod.rs | 8 +++++-- .../async-await/suggest-missing-await.fixed | 11 ++++++++++ .../ui/async-await/suggest-missing-await.rs | 11 ++++++++++ .../async-await/suggest-missing-await.stderr | 19 +++++++++++++++- .../fully-qualified-type-name4.stderr | 5 ++++- ...1632-try-desugar-incompatible-types.stderr | 13 +++++++---- src/test/ui/issues/issue-59756.stderr | 13 +++++++---- src/test/ui/mismatched_types/abridged.stderr | 10 +++++++-- .../ui/proc-macro/span-preservation.stderr | 5 +++++ src/test/ui/tail-typeck.stderr | 5 +++++ src/test/ui/wrong-ret-type.stderr | 5 +++++ 13 files changed, 112 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 901a2192e20dd..253fc5575c5bc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1284,6 +1284,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { augment_error(&mut err); } + if let Some(expr) = expression { + fcx.emit_coerce_suggestions(&mut err, expr, found, expected); + } + // Error possibly reported in `check_assign` so avoid emitting error again. err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected)) .is_some()); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 4331d441aa0d2..afdc3b220d0b9 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -15,6 +15,22 @@ use errors::{Applicability, DiagnosticBuilder}; use super::method::probe; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + + pub fn emit_coerce_suggestions( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr, + expr_ty: Ty<'tcx>, + expected: Ty<'tcx> + ) { + self.annotate_expected_due_to_let_ty(err, expr); + self.suggest_compatible_variants(err, expr, expected, expr_ty); + self.suggest_ref_or_into(err, expr, expected, expr_ty); + self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); + self.suggest_missing_await(err, expr, expected, expr_ty); + } + + // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { @@ -127,11 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return (expected, None) } - self.annotate_expected_due_to_let_ty(&mut err, expr); - self.suggest_compatible_variants(&mut err, expr, expected, expr_ty); - self.suggest_ref_or_into(&mut err, expr, expected, expr_ty); - self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty); - self.suggest_missing_await(&mut err, expr, expected, expr_ty); + self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected); (expected, Some(err)) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c7a0190a1d1b4..a956aba4f62b9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4584,8 +4584,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pointing_at_return_type = self.suggest_missing_return_type( err, &fn_decl, expected, found, can_suggest); } - self.suggest_ref_or_into(err, expr, expected, found); - self.suggest_boxing_when_appropriate(err, expr, expected, found); pointing_at_return_type } @@ -4957,7 +4955,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: expected, })); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + debug!("suggest_missing_await: trying obligation {:?}", obligation); if self.infcx.predicate_may_hold(&obligation) { + debug!("suggest_missing_await: obligation held: {:?}", obligation); if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { err.span_suggestion( sp, @@ -4965,7 +4965,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{}.await", code), Applicability::MaybeIncorrect, ); + } else { + debug!("suggest_missing_await: no snippet for {:?}", sp); } + } else { + debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) } } } diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed index 7c02a907ce7ad..1ec59d906206e 100644 --- a/src/test/ui/async-await/suggest-missing-await.fixed +++ b/src/test/ui/async-await/suggest-missing-await.fixed @@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() { //~| SUGGESTION x.await } +async fn dummy() {} + +#[allow(unused)] +async fn suggest_await_in_async_fn_return() { + dummy().await; + //~^ ERROR mismatched types [E0308] + //~| HELP try adding a semicolon + //~| HELP consider using `.await` here + //~| SUGGESTION dummy().await +} + fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index 91abd44e65caf..70cc1f1d5a2c6 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() { //~| SUGGESTION x.await } +async fn dummy() {} + +#[allow(unused)] +async fn suggest_await_in_async_fn_return() { + dummy() + //~^ ERROR mismatched types [E0308] + //~| HELP try adding a semicolon + //~| HELP consider using `.await` here + //~| SUGGESTION dummy().await +} + fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 7a635a37107d2..7ab024434b2bf 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -10,6 +10,23 @@ LL | take_u32(x) = note: expected type `u32` found opaque type `impl std::future::Future` -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:23:5 + | +LL | dummy() + | ^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `impl std::future::Future` +help: try adding a semicolon + | +LL | dummy(); + | ^ +help: consider using `.await` here + | +LL | dummy().await + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr index b388f38a7fac7..ca61fb0c171fe 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr @@ -4,7 +4,10 @@ error[E0308]: mismatched types LL | fn bar(x: usize) -> Option { | ------------- expected `std::option::Option` because of return type LL | return x; - | ^ expected enum `std::option::Option`, found `usize` + | ^ + | | + | expected enum `std::option::Option`, found `usize` + | help: try using a variant of the expected enum: `Some(x)` | = note: expected enum `std::option::Option` found type `usize` diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index aef6dc54747ce..9ca983df30af5 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? - | ^^^^^^^^^^^^^^^^^^^^- - | | | - | | help: try removing this `?` - | expected enum `std::result::Result`, found `isize` + | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `isize` | = note: expected enum `std::result::Result` found type `isize` +help: try removing this `?` + | +LL | missing_discourses() + | -- +help: try using a variant of the expected enum + | +LL | Ok(missing_discourses()?) + | error: aborting due to previous error diff --git a/src/test/ui/issues/issue-59756.stderr b/src/test/ui/issues/issue-59756.stderr index 150916c03668a..9066e57aabfe5 100644 --- a/src/test/ui/issues/issue-59756.stderr +++ b/src/test/ui/issues/issue-59756.stderr @@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-59756.rs:13:5 | LL | foo()? - | ^^^^^- - | | | - | | help: try removing this `?` - | expected enum `std::result::Result`, found struct `A` + | ^^^^^^ expected enum `std::result::Result`, found struct `A` | = note: expected enum `std::result::Result` found struct `A` +help: try removing this `?` + | +LL | foo() + | -- +help: try using a variant of the expected enum + | +LL | Ok(foo()?) + | error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c2081878629a6..c73130643db7b 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -26,7 +26,10 @@ error[E0308]: mismatched types LL | fn b() -> Option { | ----------- expected `std::option::Option` because of return type LL | Foo { bar: 1 } - | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo` + | ^^^^^^^^^^^^^^ + | | + | expected enum `std::option::Option`, found struct `Foo` + | help: try using a variant of the expected enum: `Some(Foo { bar: 1 })` | = note: expected enum `std::option::Option` found struct `Foo` @@ -37,7 +40,10 @@ error[E0308]: mismatched types LL | fn c() -> Result { | ---------------- expected `std::result::Result` because of return type LL | Foo { bar: 1 } - | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo` + | ^^^^^^^^^^^^^^ + | | + | expected enum `std::result::Result`, found struct `Foo` + | help: try using a variant of the expected enum: `Ok(Foo { bar: 1 })` | = note: expected enum `std::result::Result` found struct `Foo` diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index cd6f0ea10eac9..a77e92022e2b6 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -14,6 +14,11 @@ LL | fn b(x: Option) -> usize { LL | match x { LL | Some(x) => { return x }, | ^ expected `usize`, found `isize` + | +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | Some(x) => { return x.try_into().unwrap() }, + | ^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/span-preservation.rs:33:22 diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index eeeb258da215d..69f8ffa581bc1 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -5,6 +5,11 @@ LL | fn f() -> isize { return g(); } | ----- ^^^ expected `isize`, found `usize` | | | expected `isize` because of return type + | +help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit + | +LL | fn f() -> isize { return g().try_into().unwrap(); } + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr index 440620f40b1e2..c1274bd0ea6bc 100644 --- a/src/test/ui/wrong-ret-type.stderr +++ b/src/test/ui/wrong-ret-type.stderr @@ -5,6 +5,11 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; } | ----- ^ expected `usize`, found `isize` | | | expected `usize` because of return type + | +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); } + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From a6883c0ab00042f63c7e4cec3066577f3f8b8e5c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 3 Dec 2019 21:49:21 -0500 Subject: [PATCH 17/30] Disable issue-59756 test for now Currently, rustfix has no notion of mutually exclusive suggestions. When it processes issue-59756, it will attempt to apply two mutually exclusive suggestions for the same span, causing an error. --- src/test/ui/issues/issue-59756.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/ui/issues/issue-59756.rs b/src/test/ui/issues/issue-59756.rs index cccae396b7210..d6df0592be32c 100644 --- a/src/test/ui/issues/issue-59756.rs +++ b/src/test/ui/issues/issue-59756.rs @@ -1,4 +1,8 @@ // run-rustfix +// ignore-test +// +// FIXME: Re-enable this test once we support choosing +// between multiple mutually exclusive suggestions for the same span #![allow(warnings)] From 22c65f924266ba738fa3621ea07d31bc7ba8c45f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 5 Dec 2019 09:21:52 -0800 Subject: [PATCH 18/30] Do not ICE on closure typeck Tackle #66868. --- src/librustc/traits/error_reporting.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba44c6c3b9a1f..b644175a309c9 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2214,6 +2214,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let span = self.tcx.def_span(generator_did); + // Do not ICE on closure typeck (#66868). + if let None = self.tcx.hir().as_local_hir_id(generator_did) { + return false; + } let tables = self.tcx.typeck_tables_of(generator_did); debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ", generator_did, span); From f8ecf04f4b60f1004b9ba4092747f16d290dfff7 Mon Sep 17 00:00:00 2001 From: Kamlesh Kumar Date: Fri, 6 Dec 2019 10:52:28 +0530 Subject: [PATCH 19/30] accept union inside enum if not followed by identifier --- src/librustc_parse/parser/item.rs | 5 +++-- src/test/ui/enum/union-in-enum.rs | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/enum/union-in-enum.rs diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index ccf78e6402b3c..c3e5b39635f03 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1727,9 +1727,10 @@ impl<'a> Parser<'a> { /// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case /// it is, we try to parse the item and report error about nested types. fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> { - if self.token.is_keyword(kw::Enum) || + if (self.token.is_keyword(kw::Enum) || self.token.is_keyword(kw::Struct) || - self.token.is_keyword(kw::Union) + self.token.is_keyword(kw::Union)) + && self.look_ahead(1, |t| t.is_ident()) { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); diff --git a/src/test/ui/enum/union-in-enum.rs b/src/test/ui/enum/union-in-enum.rs new file mode 100644 index 0000000000000..048913e25cd96 --- /dev/null +++ b/src/test/ui/enum/union-in-enum.rs @@ -0,0 +1,13 @@ +// This test checks that the union keyword +// is accepted as the name of an enum variant +// when not followed by an identifier +// This special case exists because `union` is a contextual keyword. + +#![allow(warnings)] + +// check-pass + +enum A { union } +enum B { union {} } +enum C { union() } +fn main(){} From f442797c17f8f1f6ff217d48e664018359bdd6bc Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Dec 2019 13:56:25 +0100 Subject: [PATCH 20/30] Make `core::convert` a directory-module with `mod.rs` --- src/libcore/{convert.rs => convert/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/libcore/{convert.rs => convert/mod.rs} (100%) diff --git a/src/libcore/convert.rs b/src/libcore/convert/mod.rs similarity index 100% rename from src/libcore/convert.rs rename to src/libcore/convert/mod.rs From cba479f75c7513f91f727741882a99442f393c12 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 28 Nov 2019 15:24:26 +0100 Subject: [PATCH 21/30] Add `{f32,f64}::approx_unchecked_to` unsafe methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As discussed in https://github.com/rust-lang/rust/issues/10184 Currently, casting a floating point number to an integer with `as` is Undefined Behavior if the value is out of range. `-Z saturating-float-casts` fixes this soundness hole by making `as` “saturate” to the maximum or minimum value of the integer type (or zero for `NaN`), but has measurable negative performance impact in some benchmarks. There is some consensus in that thread for enabling saturation by default anyway, but provide an `unsafe fn` alternative for users who know through some other mean that their values are in range. --- src/libcore/convert/mod.rs | 5 ++++ src/libcore/convert/num.rs | 38 ++++++++++++++++++++++++++ src/libcore/intrinsics.rs | 5 ++++ src/libcore/num/f32.rs | 32 +++++++++++++++++++++- src/libcore/num/f64.rs | 32 +++++++++++++++++++++- src/librustc_codegen_llvm/intrinsic.rs | 29 +++++++++++++++++++- src/librustc_typeck/check/intrinsic.rs | 1 + 7 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 src/libcore/convert/num.rs diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs index 08802b3a97a0c..16d5375059fee 100644 --- a/src/libcore/convert/mod.rs +++ b/src/libcore/convert/mod.rs @@ -40,6 +40,11 @@ #![stable(feature = "rust1", since = "1.0.0")] +mod num; + +#[unstable(feature = "convert_float_to_int", issue = "67057")] +pub use num::FloatToInt; + /// The identity function. /// /// Two things are important to note about this function: diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs new file mode 100644 index 0000000000000..076a1107479e7 --- /dev/null +++ b/src/libcore/convert/num.rs @@ -0,0 +1,38 @@ +mod private { + /// This trait being unreachable from outside the crate + /// prevents other implementations of the `FloatToInt` trait, + /// which allows potentially adding more trait methods after the trait is `#[stable]`. + #[unstable(feature = "convert_float_to_int", issue = "67057")] + pub trait Sealed {} +} + +/// Supporting trait for inherent methods of `f32` and `f64` such as `round_unchecked_to`. +/// Typically doesn’t need to be used directly. +#[unstable(feature = "convert_float_to_int", issue = "67057")] +pub trait FloatToInt: private::Sealed + Sized { + #[cfg(not(bootstrap))] + #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[doc(hidden)] + unsafe fn approx_unchecked(self) -> Int; +} + +macro_rules! impl_float_to_int { + ( $Float: ident => $( $Int: ident )+ ) => { + #[unstable(feature = "convert_float_to_int", issue = "67057")] + impl private::Sealed for $Float {} + $( + #[unstable(feature = "convert_float_to_int", issue = "67057")] + impl FloatToInt<$Int> for $Float { + #[cfg(not(bootstrap))] + #[doc(hidden)] + #[inline] + unsafe fn approx_unchecked(self) -> $Int { + crate::intrinsics::float_to_int_approx_unchecked(self) + } + } + )+ + } +} + +impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); +impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 19928f30f2ea5..18aae59573d7d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1144,6 +1144,11 @@ extern "rust-intrinsic" { /// May assume inputs are finite. pub fn frem_fast(a: T, b: T) -> T; + /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range + /// https://github.com/rust-lang/rust/issues/10184 + #[cfg(not(bootstrap))] + pub fn float_to_int_approx_unchecked(value: Float) -> Int; + /// Returns the number of bits set in an integer type `T` pub fn ctpop(x: T) -> T; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 913c0f96d118d..ac06f95e244b6 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -7,9 +7,10 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::convert::FloatToInt; #[cfg(not(test))] use crate::intrinsics; - use crate::mem; use crate::num::FpCategory; @@ -400,6 +401,35 @@ impl f32 { intrinsics::minnumf32(self, other) } + /// Rounds toward zero and converts to any primitive integer type, + /// assuming that the value is finite and fits in that type. + /// + /// ``` + /// #![feature(float_approx_unchecked_to)] + /// + /// let value = 4.6_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, 4); + /// + /// let value = -128.9_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, std::i8::MIN); + /// ``` + /// + /// # Safety + /// + /// The value must: + /// + /// * Not be `NaN` + /// * Not be infinite + /// * Be representable in the return type `Int`, after truncating off its fractional part + #[cfg(not(bootstrap))] + #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[inline] + pub unsafe fn approx_unchecked_to(self) -> Int where Self: FloatToInt { + FloatToInt::::approx_unchecked(self) + } + /// Raw transmutation to `u32`. /// /// This is currently identical to `transmute::(self)` on all platforms. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 6ca830b1f38af..794f77fcfc1be 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -7,9 +7,10 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::convert::FloatToInt; #[cfg(not(test))] use crate::intrinsics; - use crate::mem; use crate::num::FpCategory; @@ -413,6 +414,35 @@ impl f64 { intrinsics::minnumf64(self, other) } + /// Rounds toward zero and converts to any primitive integer type, + /// assuming that the value is finite and fits in that type. + /// + /// ``` + /// #![feature(float_approx_unchecked_to)] + /// + /// let value = 4.6_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, 4); + /// + /// let value = -128.9_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, std::i8::MIN); + /// ``` + /// + /// # Safety + /// + /// The value must: + /// + /// * Not be `NaN` + /// * Not be infinite + /// * Be representable in the return type `Int`, after truncating off its fractional part + #[cfg(not(bootstrap))] + #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[inline] + pub unsafe fn approx_unchecked_to(self) -> Int where Self: FloatToInt { + FloatToInt::::approx_unchecked(self) + } + /// Raw transmutation to `u64`. /// /// This is currently identical to `transmute::(self)` on all platforms. diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 9df75a800f123..1767ad118e7c0 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -516,9 +516,36 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } } - }, + "float_to_int_approx_unchecked" => { + if float_type_width(arg_tys[0]).is_none() { + span_invalid_monomorphization_error( + tcx.sess, span, + &format!("invalid monomorphization of `float_to_int_approx_unchecked` \ + intrinsic: expected basic float type, \ + found `{}`", arg_tys[0])); + return; + } + match int_type_width_signed(ret_ty, self.cx) { + Some((width, signed)) => { + if signed { + self.fptosi(args[0].immediate(), self.cx.type_ix(width)) + } else { + self.fptoui(args[0].immediate(), self.cx.type_ix(width)) + } + } + None => { + span_invalid_monomorphization_error( + tcx.sess, span, + &format!("invalid monomorphization of `float_to_int_approx_unchecked` \ + intrinsic: expected basic integer type, \ + found `{}`", ret_ty)); + return; + } + } + } + "discriminant_value" => { args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9f034e65b6eaa..b967c6e36e35e 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -336,6 +336,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { (1, vec![param(0), param(0)], param(0)), "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => (1, vec![param(0), param(0)], param(0)), + "float_to_int_approx_unchecked" => (2, vec![ param(0) ], param(1)), "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()), "likely" => (0, vec![tcx.types.bool], tcx.types.bool), From a213ff82998ef91fa793883c2f2ebbc574967500 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 2 Dec 2019 09:44:48 +0100 Subject: [PATCH 22/30] Move numeric `From` and `TryFrom` impls to `libcore/convert/num.rs` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes `libcore/num/mod.rs` slightly smaller. It’s still 4911 lines and not easy to navigate. This doesn’t change any public API. --- src/libcore/convert/num.rs | 331 +++++++++++++++++++++++++++++++++++++ src/libcore/num/mod.rs | 331 +------------------------------------ 2 files changed, 332 insertions(+), 330 deletions(-) diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs index 076a1107479e7..0877dacb38dd2 100644 --- a/src/libcore/convert/num.rs +++ b/src/libcore/convert/num.rs @@ -1,3 +1,6 @@ +use super::{From, TryFrom}; +use crate::num::TryFromIntError; + mod private { /// This trait being unreachable from outside the crate /// prevents other implementations of the `FloatToInt` trait, @@ -36,3 +39,331 @@ macro_rules! impl_float_to_int { impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); + +// Conversion traits for primitive integer and float types +// Conversions T -> T are covered by a blanket impl and therefore excluded +// Some conversions from and to usize/isize are not implemented due to portability concerns +macro_rules! impl_from { + ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { + #[$attr] + #[doc = $doc] + impl From<$Small> for $Large { + #[inline] + fn from(small: $Small) -> $Large { + small as $Large + } + } + }; + ($Small: ty, $Large: ty, #[$attr:meta]) => { + impl_from!($Small, + $Large, + #[$attr], + concat!("Converts `", + stringify!($Small), + "` to `", + stringify!($Large), + "` losslessly.")); + } +} + +macro_rules! impl_from_bool { + ($target: ty, #[$attr:meta]) => { + impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", + stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` +values. + +# Examples + +``` +assert_eq!(", stringify!($target), "::from(true), 1); +assert_eq!(", stringify!($target), "::from(false), 0); +```")); + }; +} + +// Bool -> Any +impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } + +// Unsigned -> Unsigned +impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } + +// Signed -> Signed +impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } + +// Unsigned -> Signed +impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } + +// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX +// which imply that pointer-sized integers must be at least 16 bits: +// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 +impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } + +// RISC-V defines the possibility of a 128-bit address space (RV128). + +// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. +// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf +// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf + + +// Note: integers can only be represented with full precision in a float if +// they fit in the significand, which is 24 bits in f32 and 53 bits in f64. +// Lossy float conversions are not implemented at this time. + +// Signed -> Float +impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +// Unsigned -> Float +impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +// Float -> Float +impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + +// only negative bounds +macro_rules! try_from_lower_bounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + if u >= 0 { + Ok(u as $target) + } else { + Err(TryFromIntError(())) + } + } + } + )*} +} + +// unsigned to signed (only positive bound) +macro_rules! try_from_upper_bounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + if u > (<$target>::max_value() as $source) { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +// all other cases +macro_rules! try_from_both_bounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + let min = <$target>::min_value() as $source; + let max = <$target>::max_value() as $source; + if u < min || u > max { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +macro_rules! rev { + ($mac:ident, $source:ty, $($target:ty),*) => {$( + $mac!($target, $source); + )*} +} + +// intra-sign conversions +try_from_upper_bounded!(u16, u8); +try_from_upper_bounded!(u32, u16, u8); +try_from_upper_bounded!(u64, u32, u16, u8); +try_from_upper_bounded!(u128, u64, u32, u16, u8); + +try_from_both_bounded!(i16, i8); +try_from_both_bounded!(i32, i16, i8); +try_from_both_bounded!(i64, i32, i16, i8); +try_from_both_bounded!(i128, i64, i32, i16, i8); + +// unsigned-to-signed +try_from_upper_bounded!(u8, i8); +try_from_upper_bounded!(u16, i8, i16); +try_from_upper_bounded!(u32, i8, i16, i32); +try_from_upper_bounded!(u64, i8, i16, i32, i64); +try_from_upper_bounded!(u128, i8, i16, i32, i64, i128); + +// signed-to-unsigned +try_from_lower_bounded!(i8, u8, u16, u32, u64, u128); +try_from_lower_bounded!(i16, u16, u32, u64, u128); +try_from_lower_bounded!(i32, u32, u64, u128); +try_from_lower_bounded!(i64, u64, u128); +try_from_lower_bounded!(i128, u128); +try_from_both_bounded!(i16, u8); +try_from_both_bounded!(i32, u16, u8); +try_from_both_bounded!(i64, u32, u16, u8); +try_from_both_bounded!(i128, u64, u32, u16, u8); + +// usize/isize +try_from_upper_bounded!(usize, isize); +try_from_lower_bounded!(isize, usize); + +#[cfg(target_pointer_width = "16")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use crate::convert::TryFrom; + + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64, i128); + + try_from_both_bounded!(isize, u8); + try_from_lower_bounded!(isize, u16, u32, u64, u128); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64, i128); + + rev!(try_from_upper_bounded, usize, u32, u64, u128); + rev!(try_from_lower_bounded, usize, i8, i16); + rev!(try_from_both_bounded, usize, i32, i64, i128); + + rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); + rev!(try_from_both_bounded, isize, i32, i64, i128); +} + +#[cfg(target_pointer_width = "32")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use crate::convert::TryFrom; + + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64, i128); + + try_from_both_bounded!(isize, u8, u16); + try_from_lower_bounded!(isize, u32, u64, u128); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64, i128); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64, u128); + rev!(try_from_lower_bounded, usize, i8, i16, i32); + rev!(try_from_both_bounded, usize, i64, i128); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64, u128); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64, i128); +} + +#[cfg(target_pointer_width = "64")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use crate::convert::TryFrom; + + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + try_from_unbounded!(usize, i128); + + try_from_both_bounded!(isize, u8, u16, u32); + try_from_lower_bounded!(isize, u64, u128); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64, i128); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_upper_bounded, usize, u128); + rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); + rev!(try_from_both_bounded, usize, i128); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64, u128); + rev!(try_from_unbounded, isize, i32, i64); + rev!(try_from_both_bounded, isize, i128); +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4313248f2636a..585f144cf8a9f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4,7 +4,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::convert::TryFrom; use crate::fmt; use crate::intrinsics; use crate::mem; @@ -4701,7 +4700,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. #[stable(feature = "try_from", since = "1.34.0")] #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TryFromIntError(()); +pub struct TryFromIntError(pub(crate) ()); impl TryFromIntError { #[unstable(feature = "int_error_internals", @@ -4728,206 +4727,6 @@ impl From for TryFromIntError { } } -// no possible bounds violation -macro_rules! try_from_unbounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(value: $source) -> Result { - Ok(value as $target) - } - } - )*} -} - -// only negative bounds -macro_rules! try_from_lower_bounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - if u >= 0 { - Ok(u as $target) - } else { - Err(TryFromIntError(())) - } - } - } - )*} -} - -// unsigned to signed (only positive bound) -macro_rules! try_from_upper_bounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - if u > (<$target>::max_value() as $source) { - Err(TryFromIntError(())) - } else { - Ok(u as $target) - } - } - } - )*} -} - -// all other cases -macro_rules! try_from_both_bounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - let min = <$target>::min_value() as $source; - let max = <$target>::max_value() as $source; - if u < min || u > max { - Err(TryFromIntError(())) - } else { - Ok(u as $target) - } - } - } - )*} -} - -macro_rules! rev { - ($mac:ident, $source:ty, $($target:ty),*) => {$( - $mac!($target, $source); - )*} -} - -// intra-sign conversions -try_from_upper_bounded!(u16, u8); -try_from_upper_bounded!(u32, u16, u8); -try_from_upper_bounded!(u64, u32, u16, u8); -try_from_upper_bounded!(u128, u64, u32, u16, u8); - -try_from_both_bounded!(i16, i8); -try_from_both_bounded!(i32, i16, i8); -try_from_both_bounded!(i64, i32, i16, i8); -try_from_both_bounded!(i128, i64, i32, i16, i8); - -// unsigned-to-signed -try_from_upper_bounded!(u8, i8); -try_from_upper_bounded!(u16, i8, i16); -try_from_upper_bounded!(u32, i8, i16, i32); -try_from_upper_bounded!(u64, i8, i16, i32, i64); -try_from_upper_bounded!(u128, i8, i16, i32, i64, i128); - -// signed-to-unsigned -try_from_lower_bounded!(i8, u8, u16, u32, u64, u128); -try_from_lower_bounded!(i16, u16, u32, u64, u128); -try_from_lower_bounded!(i32, u32, u64, u128); -try_from_lower_bounded!(i64, u64, u128); -try_from_lower_bounded!(i128, u128); -try_from_both_bounded!(i16, u8); -try_from_both_bounded!(i32, u16, u8); -try_from_both_bounded!(i64, u32, u16, u8); -try_from_both_bounded!(i128, u64, u32, u16, u8); - -// usize/isize -try_from_upper_bounded!(usize, isize); -try_from_lower_bounded!(isize, usize); - -#[cfg(target_pointer_width = "16")] -mod ptr_try_from_impls { - use super::TryFromIntError; - use crate::convert::TryFrom; - - try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16); - try_from_unbounded!(usize, i32, i64, i128); - - try_from_both_bounded!(isize, u8); - try_from_lower_bounded!(isize, u16, u32, u64, u128); - try_from_both_bounded!(isize, i8); - try_from_unbounded!(isize, i16, i32, i64, i128); - - rev!(try_from_upper_bounded, usize, u32, u64, u128); - rev!(try_from_lower_bounded, usize, i8, i16); - rev!(try_from_both_bounded, usize, i32, i64, i128); - - rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_both_bounded, isize, i32, i64, i128); -} - -#[cfg(target_pointer_width = "32")] -mod ptr_try_from_impls { - use super::TryFromIntError; - use crate::convert::TryFrom; - - try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32); - try_from_unbounded!(usize, i64, i128); - - try_from_both_bounded!(isize, u8, u16); - try_from_lower_bounded!(isize, u32, u64, u128); - try_from_both_bounded!(isize, i8, i16); - try_from_unbounded!(isize, i32, i64, i128); - - rev!(try_from_unbounded, usize, u32); - rev!(try_from_upper_bounded, usize, u64, u128); - rev!(try_from_lower_bounded, usize, i8, i16, i32); - rev!(try_from_both_bounded, usize, i64, i128); - - rev!(try_from_unbounded, isize, u16); - rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i32); - rev!(try_from_both_bounded, isize, i64, i128); -} - -#[cfg(target_pointer_width = "64")] -mod ptr_try_from_impls { - use super::TryFromIntError; - use crate::convert::TryFrom; - - try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64); - try_from_unbounded!(usize, i128); - - try_from_both_bounded!(isize, u8, u16, u32); - try_from_lower_bounded!(isize, u64, u128); - try_from_both_bounded!(isize, i8, i16, i32); - try_from_unbounded!(isize, i64, i128); - - rev!(try_from_unbounded, usize, u32, u64); - rev!(try_from_upper_bounded, usize, u128); - rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); - rev!(try_from_both_bounded, usize, i128); - - rev!(try_from_unbounded, isize, u16, u32); - rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i32, i64); - rev!(try_from_both_bounded, isize, i128); -} - #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { fn min_value() -> Self; @@ -5110,131 +4909,3 @@ impl fmt::Display for ParseIntError { #[stable(feature = "rust1", since = "1.0.0")] pub use crate::num::dec2flt::ParseFloatError; - -// Conversion traits for primitive integer and float types -// Conversions T -> T are covered by a blanket impl and therefore excluded -// Some conversions from and to usize/isize are not implemented due to portability concerns -macro_rules! impl_from { - ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { - #[$attr] - #[doc = $doc] - impl From<$Small> for $Large { - #[inline] - fn from(small: $Small) -> $Large { - small as $Large - } - } - }; - ($Small: ty, $Large: ty, #[$attr:meta]) => { - impl_from!($Small, - $Large, - #[$attr], - concat!("Converts `", - stringify!($Small), - "` to `", - stringify!($Large), - "` losslessly.")); - } -} - -macro_rules! impl_from_bool { - ($target: ty, #[$attr:meta]) => { - impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", - stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` -values. - -# Examples - -``` -assert_eq!(", stringify!($target), "::from(true), 1); -assert_eq!(", stringify!($target), "::from(false), 0); -```")); - }; -} - -// Bool -> Any -impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } - -// Unsigned -> Unsigned -impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } - -// Signed -> Signed -impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } - -// Unsigned -> Signed -impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } - -// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX -// which imply that pointer-sized integers must be at least 16 bits: -// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 -impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } -impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } -impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } - -// RISC-V defines the possibility of a 128-bit address space (RV128). - -// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. -// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf -// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf - - -// Note: integers can only be represented with full precision in a float if -// they fit in the significand, which is 24 bits in f32 and 53 bits in f64. -// Lossy float conversions are not implemented at this time. - -// Signed -> Float -impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// Unsigned -> Float -impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// Float -> Float -impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } From 0c4bc58cee1a6723d55f18b226bc46bfaefcbff3 Mon Sep 17 00:00:00 2001 From: Matthew Kraai Date: Fri, 6 Dec 2019 07:06:03 -0800 Subject: [PATCH 23/30] Change "either" to "any" in Layout::from_size_align's docs --- src/libcore/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 4798769823f43..cee9b4eebe66e 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -53,7 +53,7 @@ pub struct Layout { impl Layout { /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `LayoutErr` if either of the following conditions + /// or returns `LayoutErr` if any of the following conditions /// are not met: /// /// * `align` must not be zero, From a3c85770fbf3ebe405dbc38c26483628146de240 Mon Sep 17 00:00:00 2001 From: Matthew Kraai Date: Fri, 6 Dec 2019 07:18:10 -0800 Subject: [PATCH 24/30] Change "us" to "is" in Layout::for_value comment --- src/libcore/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 4798769823f43..d260556a20803 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -137,7 +137,7 @@ impl Layout { #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - // See rationale in `new` for why this us using an unsafe variant below + // See rationale in `new` for why this is using an unsafe variant below debug_assert!(Layout::from_size_align(size, align).is_ok()); unsafe { Layout::from_size_align_unchecked(size, align) From 292b998c64ed0459b875eac9f5dccb2786a9deca Mon Sep 17 00:00:00 2001 From: Matthew Kraai Date: Fri, 6 Dec 2019 07:59:13 -0800 Subject: [PATCH 25/30] Change "wth" to "with" in `Layout::padding_needed_for` comment --- src/libcore/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index d260556a20803..65ff5d10e2de2 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -196,7 +196,7 @@ impl Layout { // valid. // // 2. `len + align - 1` can overflow by at most `align - 1`, - // so the &-mask wth `!(align - 1)` will ensure that in the + // so the &-mask with `!(align - 1)` will ensure that in the // case of overflow, `len_rounded_up` will itself be 0. // Thus the returned padding, when added to `len`, yields 0, // which trivially satisfies the alignment `align`. From 49697ae38bb724fd4eff97c64e73a83b9c1a28df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 17:28:04 +0100 Subject: [PATCH 26/30] get rid of __ in field names --- src/libstd/sync/mutex.rs | 22 ++++++++++------------ src/libstd/sync/rwlock.rs | 28 ++++++++++++++-------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 87c2318a9377c..e90da69906009 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -143,10 +143,8 @@ unsafe impl Sync for Mutex { } #[must_use = "if unused the Mutex will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { - // funny underscores due to how Deref/DerefMut currently work (they - // disregard field privacy). - __lock: &'a Mutex, - __poison: poison::Guard, + lock: &'a Mutex, + poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] @@ -417,8 +415,8 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { unsafe fn new(lock: &'mutex Mutex) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { MutexGuard { - __lock: lock, - __poison: guard, + lock: lock, + poison: guard, } }) } @@ -429,14 +427,14 @@ impl Deref for MutexGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } + unsafe { &*self.lock.data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] impl DerefMut for MutexGuard<'_, T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } + unsafe { &mut *self.lock.data.get() } } } @@ -445,8 +443,8 @@ impl Drop for MutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { - self.__lock.poison.done(&self.__poison); - self.__lock.inner.raw_unlock(); + self.lock.poison.done(&self.poison); + self.lock.inner.raw_unlock(); } } } @@ -466,11 +464,11 @@ impl fmt::Display for MutexGuard<'_, T> { } pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { - &guard.__lock.inner + &guard.lock.inner } pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { - &guard.__lock.poison + &guard.lock.poison } #[cfg(all(test, not(target_os = "emscripten")))] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index b1b56f321fc6b..c217291a42e48 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -87,7 +87,7 @@ unsafe impl Sync for RwLock {} #[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - __lock: &'a RwLock, + lock: &'a RwLock, } #[stable(feature = "rust1", since = "1.0.0")] @@ -108,8 +108,8 @@ unsafe impl Sync for RwLockReadGuard<'_, T> {} #[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { - __lock: &'a RwLock, - __poison: poison::Guard, + lock: &'a RwLock, + poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] @@ -465,7 +465,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { -> LockResult> { poison::map_result(lock.poison.borrow(), |_| { RwLockReadGuard { - __lock: lock, + lock: lock, } }) } @@ -476,8 +476,8 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { RwLockWriteGuard { - __lock: lock, - __poison: guard, + lock: lock, + poison: guard, } }) } @@ -487,7 +487,7 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { impl fmt::Debug for RwLockReadGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RwLockReadGuard") - .field("lock", &self.__lock) + .field("lock", &self.lock) .finish() } } @@ -503,7 +503,7 @@ impl fmt::Display for RwLockReadGuard<'_, T> { impl fmt::Debug for RwLockWriteGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RwLockWriteGuard") - .field("lock", &self.__lock) + .field("lock", &self.lock) .finish() } } @@ -520,7 +520,7 @@ impl Deref for RwLockReadGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } + unsafe { &*self.lock.data.get() } } } @@ -529,29 +529,29 @@ impl Deref for RwLockWriteGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } + unsafe { &*self.lock.data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] impl DerefMut for RwLockWriteGuard<'_, T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } + unsafe { &mut *self.lock.data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] impl Drop for RwLockReadGuard<'_, T> { fn drop(&mut self) { - unsafe { self.__lock.inner.read_unlock(); } + unsafe { self.lock.inner.read_unlock(); } } } #[stable(feature = "rust1", since = "1.0.0")] impl Drop for RwLockWriteGuard<'_, T> { fn drop(&mut self) { - self.__lock.poison.done(&self.__poison); - unsafe { self.__lock.inner.write_unlock(); } + self.lock.poison.done(&self.poison); + unsafe { self.lock.inner.write_unlock(); } } } From bbcda98d4107e462aae97d0b2e7c948a0d16f02b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 5 Dec 2019 06:45:50 +0100 Subject: [PATCH 27/30] cfg_attr: avoid .outer_tokens --- src/librustc_parse/config.rs | 123 +++++++++++------- src/librustc_parse/lib.rs | 27 ++-- src/librustc_parse/parser/attr.rs | 12 +- .../conditional-compilation/cfg-attr-parse.rs | 16 ++- .../cfg-attr-parse.stderr | 64 ++++++++- .../ui/malformed/malformed-special-attrs.rs | 2 +- .../malformed/malformed-special-attrs.stderr | 8 +- 7 files changed, 177 insertions(+), 75 deletions(-) diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 30e056e52d25a..b81111db95fcd 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -8,18 +8,20 @@ //! //! [#64197]: https://github.com/rust-lang/rust/issues/64197 -use crate::validate_attr; +use crate::{parse_in, validate_attr}; use rustc_feature::Features; use rustc_errors::Applicability; use syntax::attr::HasAttrs; use syntax::feature_gate::{feature_err, get_features}; use syntax::attr; -use syntax::ast; +use syntax::ast::{self, Attribute, AttrItem, MetaItem}; use syntax::edition::Edition; use syntax::mut_visit::*; use syntax::ptr::P; +use syntax::tokenstream::DelimSpan; use syntax::sess::ParseSess; use syntax::util::map_in_place::MapInPlace; +use syntax_pos::Span; use syntax_pos::symbol::sym; use smallvec::SmallVec; @@ -72,6 +74,11 @@ macro_rules! configure { } } +const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; +const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + "; + impl<'a> StripUnconfigured<'a> { pub fn configure(&mut self, mut node: T) -> Option { self.process_cfg_attrs(&mut node); @@ -97,34 +104,14 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { + fn process_cfg_attr(&mut self, attr: Attribute) -> Vec { if !attr.has_name(sym::cfg_attr) { return vec![attr]; } - if let ast::MacArgs::Empty = attr.get_normal_item().args { - self.sess.span_diagnostic - .struct_span_err( - attr.span, - "malformed `cfg_attr` attribute input", - ).span_suggestion( - attr.span, - "missing condition and attribute", - "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(), - Applicability::HasPlaceholders, - ).note("for more information, visit \ - ") - .emit(); - return vec![]; - } - let res = crate::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr()); - let (cfg_predicate, expanded_attrs) = match res { - Ok(result) => result, - Err(mut e) => { - e.emit(); - return vec![]; - } + let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { + None => return vec![], + Some(r) => r, }; // Lint on zero attributes in source. @@ -135,24 +122,72 @@ impl<'a> StripUnconfigured<'a> { // At this point we know the attribute is considered used. attr::mark_used(&attr); - if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { - // We call `process_cfg_attr` recursively in case there's a - // `cfg_attr` inside of another `cfg_attr`. E.g. - // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. - expanded_attrs.into_iter() - .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item( - attr.style, - item, - span, - ))) + if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + return vec![]; + } + + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs + .into_iter() + .flat_map(|(item, span)| { + let attr = attr::mk_attr_from_item(attr.style, item, span); + self.process_cfg_attr(attr) + }) .collect() - } else { - vec![] + } + + fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { + match &attr.get_normal_item().args { + ast::MacArgs::Delimited(dspan, delim, tts) if !tts.is_empty() => { + if let ast::MacDelimiter::Brace | ast::MacDelimiter::Bracket = delim { + self.error_malformed_cfg_attr_wrong_delim(*dspan); + } + match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { + Ok(r) => return Some(r), + Err(mut e) => e + .help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) + .note(CFG_ATTR_NOTE_REF) + .emit(), + } + } + _ => self.error_malformed_cfg_attr_missing(attr.span), } + None + } + + fn error_malformed_cfg_attr_wrong_delim(&self, dspan: DelimSpan) { + self.sess + .span_diagnostic + .struct_span_err(dspan.entire(), "wrong `cfg_attr` delimiters") + .multipart_suggestion( + "the delimiters should be `(` and `)`", + vec![ + (dspan.open, "(".to_string()), + (dspan.close, ")".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); + } + + fn error_malformed_cfg_attr_missing(&self, span: Span) { + self.sess + .span_diagnostic + .struct_span_err(span, "malformed `cfg_attr` attribute input") + .span_suggestion( + span, + "missing condition and attribute", + CFG_ATTR_GRAMMAR_HELP.to_string(), + Applicability::HasPlaceholders, + ) + .note(CFG_ATTR_NOTE_REF) + .emit(); } /// Determines if a node with the given attributes should be included in this configuration. - pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool { + pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { attrs.iter().all(|attr| { if !is_cfg(attr) { return true; @@ -199,7 +234,7 @@ impl<'a> StripUnconfigured<'a> { } /// Visit attributes on expression and statements (but not attributes on items in blocks). - fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { + fn visit_expr_attrs(&mut self, attrs: &[Attribute]) { // flag the offending attributes for attr in attrs.iter() { self.maybe_emit_expr_attr_err(attr); @@ -207,7 +242,7 @@ impl<'a> StripUnconfigured<'a> { } /// If attributes are not allowed on expressions, emit an error for `attr` - pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { + pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { let mut err = feature_err(self.sess, sym::stmt_expr_attributes, @@ -350,7 +385,7 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { } } -fn is_cfg(attr: &ast::Attribute) -> bool { +fn is_cfg(attr: &Attribute) -> bool { attr.check_name(sym::cfg) } @@ -359,8 +394,8 @@ fn is_cfg(attr: &ast::Attribute) -> bool { pub fn process_configure_mod( sess: &ParseSess, cfg_mods: bool, - attrs: &[ast::Attribute], -) -> (bool, Vec) { + attrs: &[Attribute], +) -> (bool, Vec) { // Don't perform gated feature checking. let mut strip_unconfigured = StripUnconfigured { sess, features: None }; let mut attrs = attrs.to_owned(); diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index a222f3f00c463..f1967372f4d09 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -270,21 +270,13 @@ pub fn stream_to_parser_with_base_dir<'a>( } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. -pub fn parse_in_attr<'a, T>( +pub fn parse_in<'a, T>( sess: &'a ParseSess, - attr: &ast::Attribute, + tts: TokenStream, + name: &'static str, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, T> { - let mut parser = Parser::new( - sess, - // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't - // require reconstructing and immediately re-parsing delimiters. - attr.get_normal_item().args.outer_tokens(), - None, - false, - false, - Some("attribute"), - ); + let mut parser = Parser::new(sess, tts, None, false, false, Some(name)); let result = f(&mut parser)?; if parser.token != token::Eof { parser.unexpected()?; @@ -292,6 +284,17 @@ pub fn parse_in_attr<'a, T>( Ok(result) } +/// Runs the given subparser `f` on the tokens of the given `attr`'s item. +pub fn parse_in_attr<'a, T>( + sess: &'a ParseSess, + attr: &ast::Attribute, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, +) -> PResult<'a, T> { + // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't + // require reconstructing and immediately re-parsing delimiters. + parse_in(sess, attr.get_normal_item().args.outer_tokens(), "attribute", f) +} + // NOTE(Centril): The following probably shouldn't be here but it acknowledges the // fact that architecturally, we are using parsing (read on below to understand why). diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index b2ae934ce6474..b2030a4570ef9 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -238,22 +238,18 @@ impl<'a> Parser<'a> { /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - self.expect(&token::OpenDelim(token::Paren))?; - let cfg_predicate = self.parse_meta_item()?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. let mut expanded_attrs = Vec::with_capacity(1); - - while !self.check(&token::CloseDelim(token::Paren)) { - let lo = self.token.span.lo(); + while self.token.kind != token::Eof { + let lo = self.token.span; let item = self.parse_attr_item()?; - expanded_attrs.push((item, self.prev_span.with_lo(lo))); - self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + expanded_attrs.push((item, lo.to(self.prev_span))); + self.eat(&token::Comma); } - self.expect(&token::CloseDelim(token::Paren))?; Ok((cfg_predicate, expanded_attrs)) } diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs index 93aef72220cc4..8ca31c118369c 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-parse.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs @@ -1,11 +1,11 @@ // Parse `cfg_attr` with varying numbers of attributes and trailing commas // Completely empty `cfg_attr` input -#[cfg_attr()] //~ error: expected identifier, found `)` +#[cfg_attr()] //~ error: malformed `cfg_attr` attribute input struct NoConfigurationPredicate; // Zero attributes, zero trailing comma (comma manatory here) -#[cfg_attr(all())] //~ error: expected `,`, found `)` +#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr` struct A0C0; // Zero attributes, one trailing comma @@ -40,4 +40,16 @@ struct A2C1; #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier struct A2C2; +// Wrong delimiter `[` +#[cfg_attr[all(),,]] +//~^ ERROR wrong `cfg_attr` delimiters +//~| ERROR expected identifier, found `,` +struct BracketZero; + +// Wrong delimiter `{` +#[cfg_attr{all(),,}] +//~^ ERROR wrong `cfg_attr` delimiters +//~| ERROR expected identifier, found `,` +struct BraceZero; + fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr index 3dfbd6df256eb..3a590d3282d46 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr @@ -1,32 +1,86 @@ -error: expected identifier, found `)` - --> $DIR/cfg-attr-parse.rs:4:12 +error: malformed `cfg_attr` attribute input + --> $DIR/cfg-attr-parse.rs:4:1 | LL | #[cfg_attr()] - | ^ expected identifier + | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | + = note: for more information, visit -error: expected `,`, found `)` +error: expected `,`, found end of `cfg_attr` input --> $DIR/cfg-attr-parse.rs:8:17 | LL | #[cfg_attr(all())] | ^ expected `,` + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:16:18 | LL | #[cfg_attr(all(),,)] | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:28:28 | LL | #[cfg_attr(all(), must_use,,)] | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:40:40 | LL | #[cfg_attr(all(), must_use, deprecated,,)] | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit + +error: wrong `cfg_attr` delimiters + --> $DIR/cfg-attr-parse.rs:44:11 + | +LL | #[cfg_attr[all(),,]] + | ^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[cfg_attr(all(),,)] + | ^ ^ + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:44:18 + | +LL | #[cfg_attr[all(),,]] + | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit + +error: wrong `cfg_attr` delimiters + --> $DIR/cfg-attr-parse.rs:50:11 + | +LL | #[cfg_attr{all(),,}] + | ^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[cfg_attr(all(),,)] + | ^ ^ + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:50:18 + | +LL | #[cfg_attr{all(),,}] + | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit -error: aborting due to 5 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/malformed/malformed-special-attrs.rs b/src/test/ui/malformed/malformed-special-attrs.rs index e67fbdd5ddd32..05b7ebe466662 100644 --- a/src/test/ui/malformed/malformed-special-attrs.rs +++ b/src/test/ui/malformed/malformed-special-attrs.rs @@ -1,7 +1,7 @@ #[cfg_attr] //~ ERROR malformed `cfg_attr` attribute struct S1; -#[cfg_attr = ""] //~ ERROR expected `(`, found `=` +#[cfg_attr = ""] //~ ERROR malformed `cfg_attr` attribute struct S2; #[derive] //~ ERROR malformed `derive` attribute diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr index 319c05eadbf1d..6f535e03e6aec 100644 --- a/src/test/ui/malformed/malformed-special-attrs.stderr +++ b/src/test/ui/malformed/malformed-special-attrs.stderr @@ -6,11 +6,13 @@ LL | #[cfg_attr] | = note: for more information, visit -error: expected `(`, found `=` - --> $DIR/malformed-special-attrs.rs:4:12 +error: malformed `cfg_attr` attribute input + --> $DIR/malformed-special-attrs.rs:4:1 | LL | #[cfg_attr = ""] - | ^ expected `(` + | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | + = note: for more information, visit error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:7:1 From cbc9f683125b4eb21eb3137bbd2c5295650eeaa5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 5 Dec 2019 13:53:56 +0100 Subject: [PATCH 28/30] derive: avoid parse_in_attr --- src/librustc_parse/lib.rs | 2 +- src/librustc_parse/parser/path.rs | 37 -------- src/libsyntax_expand/proc_macro.rs | 87 +++++++++++++------ .../ui/malformed/malformed-derive-entry.rs | 8 +- .../malformed/malformed-derive-entry.stderr | 27 ++++-- src/test/ui/span/macro-ty-params.rs | 1 - src/test/ui/span/macro-ty-params.stderr | 8 +- 7 files changed, 90 insertions(+), 80 deletions(-) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index f1967372f4d09..9a7b32402534e 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -285,7 +285,7 @@ pub fn parse_in<'a, T>( } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. -pub fn parse_in_attr<'a, T>( +fn parse_in_attr<'a, T>( sess: &'a ParseSess, attr: &ast::Attribute, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 70c3458e7c020..5334fc485e7a6 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -3,7 +3,6 @@ use crate::maybe_whole; use rustc_errors::{PResult, Applicability, pluralize}; use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; -use syntax::ast::MacArgs; use syntax::ThinVec; use syntax::token::{self, Token}; use syntax_pos::source_map::{Span, BytePos}; @@ -109,42 +108,6 @@ impl<'a> Parser<'a> { Ok(Path { segments, span: lo.to(self.prev_span) }) } - /// Like `parse_path`, but also supports parsing `Word` meta items into paths for - /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` - /// attributes. - fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { - let meta_ident = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref item) => match item.args { - MacArgs::Empty => Some(item.path.clone()), - _ => None, - }, - _ => None, - }, - _ => None, - }; - if let Some(path) = meta_ident { - self.bump(); - return Ok(path); - } - self.parse_path(style) - } - - /// Parse a list of paths inside `#[derive(path_0, ..., path_n)]`. - pub fn parse_derive_paths(&mut self) -> PResult<'a, Vec> { - self.expect(&token::OpenDelim(token::Paren))?; - let mut list = Vec::new(); - while !self.eat(&token::CloseDelim(token::Paren)) { - let path = self.parse_path_allowing_meta(PathStyle::Mod)?; - list.push(path); - if !self.eat(&token::Comma) { - self.expect(&token::CloseDelim(token::Paren))?; - break - } - } - Ok(list) - } - pub(super) fn parse_path_segments( &mut self, segments: &mut Vec, diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 8e56e2bb00b4b..ad2281a587910 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -1,7 +1,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; -use syntax::ast::{self, ItemKind, MacArgs}; +use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; use syntax::errors::{Applicability, FatalError}; use syntax::symbol::sym; use syntax::token; @@ -171,34 +171,71 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) if !attr.has_name(sym::derive) { return true; } - if !attr.is_meta_item_list() { - cx.struct_span_err(attr.span, "malformed `derive` attribute input") - .span_suggestion( - attr.span, - "missing traits to be derived", - "#[derive(Trait1, Trait2, ...)]".to_owned(), - Applicability::HasPlaceholders, - ).emit(); - return false; - } - let parse_derive_paths = |attr: &ast::Attribute| { - if let MacArgs::Empty = attr.get_normal_item().args { - return Ok(Vec::new()); + // 1) First let's ensure that it's a meta item. + let nmis = match attr.meta_item_list() { + None => { + cx.struct_span_err(attr.span, "malformed `derive` attribute input") + .span_suggestion( + attr.span, + "missing traits to be derived", + "#[derive(Trait1, Trait2, ...)]".to_owned(), + Applicability::HasPlaceholders, + ) + .emit(); + return false; } - rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) + Some(x) => x, }; - match parse_derive_paths(attr) { - Ok(traits) => { - result.extend(traits); - true - } - Err(mut e) => { - e.emit(); - false - } - } + let mut retain_in_fm = true; + let mut retain_in_map = true; + let traits = nmis + .into_iter() + // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`. + .filter_map(|nmi| match nmi { + NestedMetaItem::Literal(lit) => { + retain_in_fm = false; + cx.struct_span_err(lit.span, "expected path to a trait, found literal") + .help("for example, write `#[derive(Debug)]` for `Debug`") + .emit(); + None + } + NestedMetaItem::MetaItem(mi) => Some(mi), + }) + // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]` + // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`. + // In this case we can still at least determine that the user + // wanted this trait to be derived, so let's keep it. + .map(|mi| { + let mut traits_dont_accept = |title, action| { + retain_in_map = false; + let sp = mi.span.with_lo(mi.path.span.hi()); + cx.struct_span_err(sp, title) + .span_suggestion( + sp, + action, + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + }; + match &mi.kind { + MetaItemKind::List(..) => traits_dont_accept( + "traits in `#[derive(...)]` don't accept arguments", + "remove the arguments", + ), + MetaItemKind::NameValue(..) => traits_dont_accept( + "traits in `#[derive(...)]` don't accept values", + "remove the value", + ), + MetaItemKind::Word => {} + } + mi.path + }); + + result.extend(traits); + retain_in_fm && retain_in_map }); result } diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs index a6d886318e820..77fa2f566a8fc 100644 --- a/src/test/ui/malformed/malformed-derive-entry.rs +++ b/src/test/ui/malformed/malformed-derive-entry.rs @@ -1,7 +1,11 @@ -#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(` +#[derive(Copy(Bad))] +//~^ ERROR traits in `#[derive(...)]` don't accept arguments +//~| ERROR the trait bound struct Test1; -#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=` +#[derive(Copy="bad")] +//~^ ERROR traits in `#[derive(...)]` don't accept values +//~| ERROR the trait bound struct Test2; #[derive] //~ ERROR malformed `derive` attribute input diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr index 8d750b6683843..1f1ee39b049e3 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -1,20 +1,33 @@ -error: expected one of `)`, `,`, or `::`, found `(` +error: traits in `#[derive(...)]` don't accept arguments --> $DIR/malformed-derive-entry.rs:1:14 | LL | #[derive(Copy(Bad))] - | ^ expected one of `)`, `,`, or `::` + | ^^^^^ help: remove the arguments -error: expected one of `)`, `,`, or `::`, found `=` - --> $DIR/malformed-derive-entry.rs:4:14 +error: traits in `#[derive(...)]` don't accept values + --> $DIR/malformed-derive-entry.rs:6:14 | LL | #[derive(Copy="bad")] - | ^ expected one of `)`, `,`, or `::` + | ^^^^^^ help: remove the value error: malformed `derive` attribute input - --> $DIR/malformed-derive-entry.rs:7:1 + --> $DIR/malformed-derive-entry.rs:11:1 | LL | #[derive] | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` -error: aborting due to 3 previous errors +error[E0277]: the trait bound `Test1: std::clone::Clone` is not satisfied + --> $DIR/malformed-derive-entry.rs:1:10 + | +LL | #[derive(Copy(Bad))] + | ^^^^ the trait `std::clone::Clone` is not implemented for `Test1` + +error[E0277]: the trait bound `Test2: std::clone::Clone` is not satisfied + --> $DIR/malformed-derive-entry.rs:6:10 + | +LL | #[derive(Copy="bad")] + | ^^^^ the trait `std::clone::Clone` is not implemented for `Test2` + +error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/span/macro-ty-params.rs b/src/test/ui/span/macro-ty-params.rs index b077d590915cb..713b9eb542cfa 100644 --- a/src/test/ui/span/macro-ty-params.rs +++ b/src/test/ui/span/macro-ty-params.rs @@ -10,5 +10,4 @@ fn main() { foo::!(); //~ ERROR generic arguments in macro path foo::<>!(); //~ ERROR generic arguments in macro path m!(Default<>); //~ ERROR generic arguments in macro path - //~^ ERROR unexpected generic arguments in path } diff --git a/src/test/ui/span/macro-ty-params.stderr b/src/test/ui/span/macro-ty-params.stderr index 39b3edc67033d..21683b2fb8643 100644 --- a/src/test/ui/span/macro-ty-params.stderr +++ b/src/test/ui/span/macro-ty-params.stderr @@ -10,17 +10,11 @@ error: generic arguments in macro path LL | foo::<>!(); | ^^ -error: unexpected generic arguments in path - --> $DIR/macro-ty-params.rs:12:8 - | -LL | m!(Default<>); - | ^^^^^^^^^ - error: generic arguments in macro path --> $DIR/macro-ty-params.rs:12:15 | LL | m!(Default<>); | ^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 99191c2e717883bfec51b49df0e412a34849fc4a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 5 Dec 2019 14:19:00 +0100 Subject: [PATCH 29/30] parse_meta: ditch parse_in_attr --- src/librustc_parse/config.rs | 25 ++---------- src/librustc_parse/lib.rs | 11 ------ src/librustc_parse/parser/attr.rs | 19 +++++++++- src/librustc_parse/validate_attr.rs | 38 +++++++++++++++++-- src/libsyntax_expand/proc_macro.rs | 10 ++--- src/test/ui/malformed/malformed-meta-delim.rs | 11 ++++++ .../ui/malformed/malformed-meta-delim.stderr | 24 ++++++++++++ .../expected-comma-found-token.rs | 2 +- .../expected-comma-found-token.stderr | 7 +--- 9 files changed, 99 insertions(+), 48 deletions(-) create mode 100644 src/test/ui/malformed/malformed-meta-delim.rs create mode 100644 src/test/ui/malformed/malformed-meta-delim.stderr diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index b81111db95fcd..072f6845853a8 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -18,7 +18,6 @@ use syntax::ast::{self, Attribute, AttrItem, MetaItem}; use syntax::edition::Edition; use syntax::mut_visit::*; use syntax::ptr::P; -use syntax::tokenstream::DelimSpan; use syntax::sess::ParseSess; use syntax::util::map_in_place::MapInPlace; use syntax_pos::Span; @@ -139,11 +138,10 @@ impl<'a> StripUnconfigured<'a> { } fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { - match &attr.get_normal_item().args { - ast::MacArgs::Delimited(dspan, delim, tts) if !tts.is_empty() => { - if let ast::MacDelimiter::Brace | ast::MacDelimiter::Bracket = delim { - self.error_malformed_cfg_attr_wrong_delim(*dspan); - } + match attr.get_normal_item().args { + ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { + let msg = "wrong `cfg_attr` delimiters"; + validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg); match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { Ok(r) => return Some(r), Err(mut e) => e @@ -157,21 +155,6 @@ impl<'a> StripUnconfigured<'a> { None } - fn error_malformed_cfg_attr_wrong_delim(&self, dspan: DelimSpan) { - self.sess - .span_diagnostic - .struct_span_err(dspan.entire(), "wrong `cfg_attr` delimiters") - .multipart_suggestion( - "the delimiters should be `(` and `)`", - vec![ - (dspan.open, "(".to_string()), - (dspan.close, ")".to_string()), - ], - Applicability::MachineApplicable, - ) - .emit(); - } - fn error_malformed_cfg_attr_missing(&self, span: Span) { self.sess .span_diagnostic diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 9a7b32402534e..72436f29244cf 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -284,17 +284,6 @@ pub fn parse_in<'a, T>( Ok(result) } -/// Runs the given subparser `f` on the tokens of the given `attr`'s item. -fn parse_in_attr<'a, T>( - sess: &'a ParseSess, - attr: &ast::Attribute, - f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, -) -> PResult<'a, T> { - // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't - // require reconstructing and immediately re-parsing delimiters. - parse_in(sess, attr.get_normal_item().args.outer_tokens(), "attribute", f) -} - // NOTE(Centril): The following probably shouldn't be here but it acknowledges the // fact that architecturally, we are using parsing (read on below to understand why). diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index b2030a4570ef9..00fd6b8a25bc3 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -220,7 +220,7 @@ impl<'a> Parser<'a> { Ok(attrs) } - pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { let lit = self.parse_lit()?; debug!("checking if {:?} is unusuffixed", lit); @@ -247,12 +247,27 @@ impl<'a> Parser<'a> { let lo = self.token.span; let item = self.parse_attr_item()?; expanded_attrs.push((item, lo.to(self.prev_span))); - self.eat(&token::Comma); + if !self.eat(&token::Comma) { + break; + } } Ok((cfg_predicate, expanded_attrs)) } + /// Matches `COMMASEP(meta_item_inner)`. + crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec> { + // Presumably, the majority of the time there will only be one attr. + let mut nmis = Vec::with_capacity(1); + while self.token.kind != token::Eof { + nmis.push(self.parse_meta_item_inner()?); + if !self.eat(&token::Comma) { + break; + } + } + Ok(nmis) + } + /// Matches the following grammar (per RFC 1559). /// /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index 97e9cb8dcdf6f..94d3fe7b55167 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -1,10 +1,13 @@ //! Meta-syntax validation logic of attributes for post-expansion. +use crate::parse_in; + use rustc_errors::{PResult, Applicability}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; -use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind}; +use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; use syntax::attr::mk_name_value_item_str; use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT; +use syntax::tokenstream::DelimSpan; use syntax::sess::ParseSess; use syntax_pos::{Symbol, sym}; @@ -27,9 +30,20 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { Ok(match attr.kind { AttrKind::Normal(ref item) => MetaItem { - path: item.path.clone(), - kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?, span: attr.span, + path: item.path.clone(), + kind: match &attr.get_normal_item().args { + MacArgs::Empty => MetaItemKind::Word, + MacArgs::Eq(_, t) => { + let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?; + MetaItemKind::NameValue(v) + } + MacArgs::Delimited(dspan, delim, t) => { + check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); + let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; + MetaItemKind::List(nmis) + } + } }, AttrKind::DocComment(comment) => { mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span) @@ -37,6 +51,24 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } +crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { + if let ast::MacDelimiter::Parenthesis = delim { + return; + } + + sess.span_diagnostic + .struct_span_err(span.entire(), msg) + .multipart_suggestion( + "the delimiters should be `(` and `)`", + vec![ + (span.open, "(".to_string()), + (span.close, ")".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); +} + /// Checks that the given meta-item is compatible with this `AttributeTemplate`. fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool { match meta { diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index ad2281a587910..520488c658676 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -188,14 +188,14 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) Some(x) => x, }; - let mut retain_in_fm = true; - let mut retain_in_map = true; + let mut error_reported_filter_map = false; + let mut error_reported_map = false; let traits = nmis .into_iter() // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`. .filter_map(|nmi| match nmi { NestedMetaItem::Literal(lit) => { - retain_in_fm = false; + error_reported_filter_map = true; cx.struct_span_err(lit.span, "expected path to a trait, found literal") .help("for example, write `#[derive(Debug)]` for `Debug`") .emit(); @@ -209,7 +209,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) // wanted this trait to be derived, so let's keep it. .map(|mi| { let mut traits_dont_accept = |title, action| { - retain_in_map = false; + error_reported_map = true; let sp = mi.span.with_lo(mi.path.span.hi()); cx.struct_span_err(sp, title) .span_suggestion( @@ -235,7 +235,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) }); result.extend(traits); - retain_in_fm && retain_in_map + !error_reported_filter_map && !error_reported_map }); result } diff --git a/src/test/ui/malformed/malformed-meta-delim.rs b/src/test/ui/malformed/malformed-meta-delim.rs new file mode 100644 index 0000000000000..5b1614b69a92b --- /dev/null +++ b/src/test/ui/malformed/malformed-meta-delim.rs @@ -0,0 +1,11 @@ +fn main() {} + +#[allow { foo_lint } ] +//~^ ERROR wrong meta list delimiters +//~| HELP the delimiters should be `(` and `)` +fn delim_brace() {} + +#[allow [ foo_lint ] ] +//~^ ERROR wrong meta list delimiters +//~| HELP the delimiters should be `(` and `)` +fn delim_bracket() {} diff --git a/src/test/ui/malformed/malformed-meta-delim.stderr b/src/test/ui/malformed/malformed-meta-delim.stderr new file mode 100644 index 0000000000000..407193d4adebb --- /dev/null +++ b/src/test/ui/malformed/malformed-meta-delim.stderr @@ -0,0 +1,24 @@ +error: wrong meta list delimiters + --> $DIR/malformed-meta-delim.rs:3:9 + | +LL | #[allow { foo_lint } ] + | ^^^^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[allow ( foo_lint ) ] + | ^ ^ + +error: wrong meta list delimiters + --> $DIR/malformed-meta-delim.rs:8:9 + | +LL | #[allow [ foo_lint ] ] + | ^^^^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[allow ( foo_lint ) ] + | ^ ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.rs b/src/test/ui/on-unimplemented/expected-comma-found-token.rs index 77c0ea17269f0..8fb34f21152ab 100644 --- a/src/test/ui/on-unimplemented/expected-comma-found-token.rs +++ b/src/test/ui/on-unimplemented/expected-comma-found-token.rs @@ -6,7 +6,7 @@ #[rustc_on_unimplemented( message="the message" - label="the label" //~ ERROR expected one of `)` or `,`, found `label` + label="the label" //~ ERROR expected `,`, found `label` )] trait T {} diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr index 2e1d484e05a5a..048b72ee3bcdf 100644 --- a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr +++ b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr @@ -1,11 +1,8 @@ -error: expected one of `)` or `,`, found `label` +error: expected `,`, found `label` --> $DIR/expected-comma-found-token.rs:9:5 | LL | message="the message" - | - - | | - | expected one of `)` or `,` - | help: missing `,` + | - expected `,` LL | label="the label" | ^^^^^ unexpected token From 3c14f0eaa7eafb1a61dab61fc37c11c3e450cba2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 6 Dec 2019 16:38:57 -0500 Subject: [PATCH 30/30] Add note to src/ci/docker/README.md about multiple docker images I spent a while debugging a strage linker error about an outdated `glibc` version, only to discover that it was caused by a stale `obj` directory. It wasn't obviously to be that using the same obj dir with multiple Docker images (for the same target triple) could be a problem. This commit adds a note to the README, which should hopefully be helpful to anyone else who runs into this issue. --- src/ci/docker/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index a2d83eca24b0a..872f2c3467d20 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -16,6 +16,13 @@ for example: Images will output artifacts in an `obj` dir at the root of a repository. +**NOTE**: Re-using the same `obj` dir with different docker images with +the same target triple (e.g. `dist-x86_64-linux` and `dist-various-1`) +may result in strange linker errors, due shared library versions differing between platforms. + +If you encounter any issues when using multiple Docker images, try deleting your `obj` directory +before running your command. + ## Filesystem layout - Each directory, excluding `scripts` and `disabled`, corresponds to a docker image