From 0d395841fc5141462c88a4167b2f675405d3a8eb Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 22 Jun 2016 18:29:16 -0700 Subject: Detect double reference when applying binary op ```rust let vr = v.iter().filter(|x| { x % 2 == 0 }); ``` will now yield the following compiler output: ```bash ERROR binary operation `%` cannot be applied to type `&&_` NOTE this is a reference of a reference to a type that `%` can be applied to, you need to dereference this variable once for this operation to work NOTE an implementation of `std::ops::Rem` might be missing for `&&_` ``` The first NOTE is new. Bug #33877 --- src/test/compile-fail/binary-op-on-double-ref.rs | 20 ++++++++++++++++++++ src/test/compile-fail/str-concat-on-double-ref.rs | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/compile-fail/binary-op-on-double-ref.rs create mode 100644 src/test/compile-fail/str-concat-on-double-ref.rs (limited to 'src/test') diff --git a/src/test/compile-fail/binary-op-on-double-ref.rs b/src/test/compile-fail/binary-op-on-double-ref.rs new file mode 100644 index 00000000000..5cc8e0f9988 --- /dev/null +++ b/src/test/compile-fail/binary-op-on-double-ref.rs @@ -0,0 +1,20 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; + let vr = v.iter().filter(|x| { + x % 2 == 0 + //~^ ERROR binary operation `%` cannot be applied to type `&&_` + //~| NOTE this is a reference of type that `%` can be applied to + //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&_` + }); + println!("{:?}", vr); +} diff --git a/src/test/compile-fail/str-concat-on-double-ref.rs b/src/test/compile-fail/str-concat-on-double-ref.rs new file mode 100644 index 00000000000..d79ab6b805c --- /dev/null +++ b/src/test/compile-fail/str-concat-on-double-ref.rs @@ -0,0 +1,19 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let a: &String = &"1".to_owned(); + let b: &str = &"2"; + let c = a + b; + //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String` + //~| NOTE this is a reference of type that `+` can be applied to + //~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String` + println!("{:?}", c); +} -- cgit 1.4.1-3-g733a5 From b8669dff556a03ca37b39cbb81be65c94d24defe Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 26 Dec 2016 13:27:51 -0500 Subject: Ensure type is copyable before emitting note suggesting adding manual deref. drive-by: fix merge conflict; fix test expected error output post rebase. --- src/librustc_typeck/check/op.rs | 5 +++-- src/test/compile-fail/binary-op-on-double-ref.rs | 4 ++-- src/test/compile-fail/str-concat-on-double-ref.rs | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 4202f65c44d..925d28247b6 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -206,8 +206,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_ty); if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { - if self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], - token::intern(name), trait_def_id, + if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && + self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.span_note( lhs_expr.span, diff --git a/src/test/compile-fail/binary-op-on-double-ref.rs b/src/test/compile-fail/binary-op-on-double-ref.rs index 5cc8e0f9988..a49cfaa1760 100644 --- a/src/test/compile-fail/binary-op-on-double-ref.rs +++ b/src/test/compile-fail/binary-op-on-double-ref.rs @@ -12,9 +12,9 @@ fn main() { let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; let vr = v.iter().filter(|x| { x % 2 == 0 - //~^ ERROR binary operation `%` cannot be applied to type `&&_` + //~^ ERROR binary operation `%` cannot be applied to type `&&{integer}` //~| NOTE this is a reference of type that `%` can be applied to - //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&_` + //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&{integer}` }); println!("{:?}", vr); } diff --git a/src/test/compile-fail/str-concat-on-double-ref.rs b/src/test/compile-fail/str-concat-on-double-ref.rs index d79ab6b805c..f85422f76d4 100644 --- a/src/test/compile-fail/str-concat-on-double-ref.rs +++ b/src/test/compile-fail/str-concat-on-double-ref.rs @@ -13,7 +13,6 @@ fn main() { let b: &str = &"2"; let c = a + b; //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String` - //~| NOTE this is a reference of type that `+` can be applied to //~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String` println!("{:?}", c); } -- cgit 1.4.1-3-g733a5 From 2b7a23ed304d4298247b030eea0820018c05cd30 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 25 Jan 2017 14:48:20 +0800 Subject: Hide uninhabitedness checks behind feature gate --- src/librustc/ty/inhabitedness/mod.rs | 6 +-- src/librustc_const_eval/_match.rs | 17 ++++++-- src/librustc_mir/build/matches/simplify.rs | 30 +++++++------ .../uninhabited-matches-feature-gated.rs | 50 ++++++++++++++++++++++ .../uninhabited-reference-type-feature-gated.rs | 19 -------- 5 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 src/test/compile-fail/uninhabited-matches-feature-gated.rs delete mode 100644 src/test/compile-fail/uninhabited-reference-type-feature-gated.rs (limited to 'src/test') diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 92395e3c381..6c49493a655 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -191,11 +191,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } TyRef(_, ref tm) => { - if tcx.sess.features.borrow().never_type { - tm.ty.uninhabited_from(visited, tcx) - } else { - DefIdForest::empty() - } + tm.ty.uninhabited_from(visited, tcx) } _ => DefIdForest::empty(), diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index bb5dacf71e1..1770a112cdf 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -379,19 +379,24 @@ impl<'tcx> Witness<'tcx> { fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, pcx: PatternContext<'tcx>) -> Vec { + let check_inhabited = cx.tcx.sess.features.borrow().never_type; debug!("all_constructors({:?})", pcx.ty); match pcx.ty.sty { ty::TyBool => [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), ty::TySlice(ref sub_ty) => { - if sub_ty.is_uninhabited_from(cx.module, cx.tcx) { + if sub_ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited + { vec![Slice(0)] } else { (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() } } ty::TyArray(ref sub_ty, length) => { - if length == 0 || !sub_ty.is_uninhabited_from(cx.module, cx.tcx) { + if length == 0 || !(sub_ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited) + { vec![Slice(length)] } else { vec![] @@ -403,7 +408,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let forest = v.uninhabited_from(&mut visited, cx.tcx, substs, AdtKind::Enum); - if forest.contains(cx.tcx, cx.module) { + if forest.contains(cx.tcx, cx.module) + && check_inhabited + { None } else { Some(Variant(v.did)) @@ -411,7 +418,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, }).collect() } _ => { - if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) { + if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited + { vec![] } else { vec![Single] diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b0718341223..e94d35195c2 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -99,20 +99,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { - let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { - i == variant_index || { - let mut visited = FxHashSet::default(); - let node_set = v.uninhabited_from(&mut visited, - self.hir.tcx(), - substs, - adt_def.adt_kind()); - !node_set.is_empty() + if self.hir.tcx().sess.features.borrow().never_type { + let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { + i == variant_index || { + let mut visited = FxHashSet::default(); + let node_set = v.uninhabited_from(&mut visited, + self.hir.tcx(), + substs, + adt_def.adt_kind()); + !node_set.is_empty() + } + }); + if irrefutable { + let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); + candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); + Ok(()) + } else { + Err(match_pair) } - }); - if irrefutable { - let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); - candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); - Ok(()) } else { Err(match_pair) } diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs new file mode 100644 index 00000000000..0f8b0a6c238 --- /dev/null +++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs @@ -0,0 +1,50 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(slice_patterns)] + +enum Void {} + +fn main() { + let x: Result = Ok(23); + let _ = match x { //~ ERROR non-exhaustive + Ok(n) => n, + }; + + let x: &Void = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: (Void,) = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: [Void; 1] = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: &[Void] = unsafe { std::mem::uninitialized() }; + let _ = match x { //~ ERROR non-exhaustive + &[] => (), + }; + + let x: Void = unsafe { std::mem::uninitialized() }; + let _ = match x {}; // okay + + let x: Result = Ok(23); + let _ = match x { //~ ERROR non-exhaustive + Ok(x) => x, + }; + + let x: Result = Ok(23); + let Ok(x) = x; + //~^ ERROR refutable +} + diff --git a/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs b/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs deleted file mode 100644 index 8f246eddbcd..00000000000 --- a/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -enum Void {} - -fn main() { - let x: Result = Ok(23); - let _ = match x { //~ ERROR non-exhaustive - Ok(n) => n, - }; -} - -- cgit 1.4.1-3-g733a5 From ff11f987c669a62058267c5b71f804b03fe9954d Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 26 Jan 2017 10:37:20 +0100 Subject: drop_in_place is stable now, don't #![feature] it in the nomicon and a test It was stable since Rust 1.8. --- src/doc/nomicon/destructors.md | 6 +++--- src/test/run-pass/extern_fat_drop.rs | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/test') diff --git a/src/doc/nomicon/destructors.md b/src/doc/nomicon/destructors.md index c6fa5b079db..be4730cf8bc 100644 --- a/src/doc/nomicon/destructors.md +++ b/src/doc/nomicon/destructors.md @@ -26,7 +26,7 @@ this is totally fine. For instance, a custom implementation of `Box` might write `Drop` like this: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -57,7 +57,7 @@ use-after-free the `ptr` because when drop exits, it becomes inaccessible. However this wouldn't work: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -135,7 +135,7 @@ The classic safe solution to overriding recursive drop and allowing moving out of Self during `drop` is to use an Option: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; diff --git a/src/test/run-pass/extern_fat_drop.rs b/src/test/run-pass/extern_fat_drop.rs index deb7e6bd539..8ce1f744dee 100644 --- a/src/test/run-pass/extern_fat_drop.rs +++ b/src/test/run-pass/extern_fat_drop.rs @@ -10,8 +10,6 @@ // aux-build:fat_drop.rs -#![feature(drop_in_place)] - extern crate fat_drop; fn main() { -- cgit 1.4.1-3-g733a5 From eaf182e5395e4e0ab0b792020daed1f12b99d688 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 25 Jan 2017 23:28:59 +0100 Subject: Add note for E0117 --- src/librustc_typeck/coherence/orphan.rs | 1 + src/test/compile-fail/E0117.rs | 1 + src/test/compile-fail/E0206.rs | 1 + src/test/compile-fail/coherence-impls-copy.rs | 5 ++++- 4 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/test') diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 2b5a4515cd0..c54f467a4c4 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -263,6 +263,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { .span_label(item.span, &format!("impl doesn't use types inside crate")) .note(&format!("the impl does not reference any types defined in \ this crate")) + .note("define and implement a trait or new type instead") .emit(); return; } diff --git a/src/test/compile-fail/E0117.rs b/src/test/compile-fail/E0117.rs index e9375e67325..4ba9c3382f3 100644 --- a/src/test/compile-fail/E0117.rs +++ b/src/test/compile-fail/E0117.rs @@ -11,6 +11,7 @@ impl Drop for u32 {} //~ ERROR E0117 //~^ NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead fn main() { } diff --git a/src/test/compile-fail/E0206.rs b/src/test/compile-fail/E0206.rs index 888e42ed3a1..1131e8e1b01 100644 --- a/src/test/compile-fail/E0206.rs +++ b/src/test/compile-fail/E0206.rs @@ -16,6 +16,7 @@ impl Copy for Foo { } //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead #[derive(Copy, Clone)] struct Bar; diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index f686a146042..fe121a3bc48 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -37,6 +37,7 @@ impl Copy for (MyType, MyType) {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead impl Copy for &'static NotSync {} //~^ ERROR the trait `Copy` may not be implemented for this type @@ -46,8 +47,9 @@ impl Copy for [MyType] {} //~^ ERROR the trait `Copy` may not be implemented for this type //~| NOTE type is not a structure or enumeration //~| ERROR only traits defined in the current crate can be implemented for arbitrary types -//~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead +//~| NOTE impl doesn't use types inside crate impl Copy for &'static [NotSync] {} //~^ ERROR the trait `Copy` may not be implemented for this type @@ -55,6 +57,7 @@ impl Copy for &'static [NotSync] {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead fn main() { } -- cgit 1.4.1-3-g733a5 From d83687f68c1eed7d9783d23a7464e93aa5e886c3 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 26 Jan 2017 21:51:20 -0800 Subject: Fix can_begin_expr keyword behavior --- src/libsyntax/parse/token.rs | 24 ++++++++++++++++++++- src/test/compile-fail/can-begin-expr-check.rs | 30 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/can-begin-expr-check.rs (limited to 'src/test') diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bf790b96e37..43ad1eacf33 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -80,6 +80,28 @@ impl Lit { } } +fn ident_can_begin_expr(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::Box.name(), + keywords::Break.name(), + keywords::Continue.name(), + keywords::False.name(), + keywords::For.name(), + keywords::If.name(), + keywords::Loop.name(), + keywords::Match.name(), + keywords::Move.name(), + keywords::Return.name(), + keywords::True.name(), + keywords::Unsafe.name(), + keywords::While.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -163,7 +185,7 @@ impl Token { pub fn can_begin_expr(&self) -> bool { match *self { OpenDelim(..) => true, - Ident(..) => true, + Ident(ident) => ident_can_begin_expr(ident), Literal(..) => true, Not => true, BinOp(Minus) => true, diff --git a/src/test/compile-fail/can-begin-expr-check.rs b/src/test/compile-fail/can-begin-expr-check.rs new file mode 100644 index 00000000000..68f219c6ed9 --- /dev/null +++ b/src/test/compile-fail/can-begin-expr-check.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + + return; + return (); + return as (); + return return as (); + return return return; + + return if true { + () + } else { + () + }; + + loop { + return break as (); + } + + return enum; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` +} -- cgit 1.4.1-3-g733a5