From 9788354fffa92cbd0e277334842b0f7872a8bd55 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 24 Nov 2019 22:39:05 +0000 Subject: [PATCH 01/15] Handle non_exhaustive in borrow checking --- src/librustc_mir/build/matches/simplify.rs | 2 +- .../auxiliary/monovariants.rs | 8 ++++ .../borrowck-exhaustive.rs | 42 +++++++++++++++++++ .../borrowck-non-exhaustive.rs | 18 ++++++++ .../borrowck-non-exhaustive.stderr | 15 +++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs create mode 100644 src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 9b7bccca2ddf3..3e71b871801d1 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.hir.tcx().features().exhaustive_patterns && !v.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()).is_empty() } - }); + }) && (adt_def.did.is_local() || !adt_def.is_variant_list_non_exhaustive()); if irrefutable { let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index); candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns)); diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs new file mode 100644 index 0000000000000..5f86db86d4477 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs @@ -0,0 +1,8 @@ +#[non_exhaustive] +pub enum NonExhaustiveMonovariant { + Variant(u32), +} + +pub enum ExhaustiveMonovariant { + Variant(u32), +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs b/src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs new file mode 100644 index 0000000000000..be775b37f7b77 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs @@ -0,0 +1,42 @@ +// Test that the borrow checker doesn't consider checking an exhaustive pattern +// as an access. + +// check-pass + +// aux-build:monovariants.rs +extern crate monovariants; + +use monovariants::ExhaustiveMonovariant; + +enum Local { + Variant(u32), +} + +#[non_exhaustive] +enum LocalNonExhaustive { + Variant(u32), +} + +fn main() { + let mut x = ExhaustiveMonovariant::Variant(1); + let y = &mut x; + match x { + ExhaustiveMonovariant::Variant(_) => {}, + _ => {}, + } + drop(y); + let mut x = Local::Variant(1); + let y = &mut x; + match x { + Local::Variant(_) => {}, + _ => {}, + } + drop(y); + let mut x = LocalNonExhaustive::Variant(1); + let y = &mut x; + match x { + LocalNonExhaustive::Variant(_) => {}, + _ => {}, + } + drop(y); +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs new file mode 100644 index 0000000000000..00dcf89c7aa67 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs @@ -0,0 +1,18 @@ +// Test that the borrow checker considers `#[non_exhaustive]` when checking +// whether a match contains a discriminant read. + +// aux-build:monovariants.rs +extern crate monovariants; + +use monovariants::NonExhaustiveMonovariant; + +fn main() { + let mut x = NonExhaustiveMonovariant::Variant(1); + let y = &mut x; + match x { + NonExhaustiveMonovariant::Variant(_) => {}, + //~^ ERROR cannot use `x` because it was mutably borrowed + _ => {}, + } + drop(y); +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr new file mode 100644 index 0000000000000..9edfa84cbc085 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr @@ -0,0 +1,15 @@ +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-non-exhaustive.rs:13:9 + | +LL | let y = &mut x; + | ------ borrow of `x` occurs here +LL | match x { +LL | NonExhaustiveMonovariant::Variant(_) => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of borrowed `x` +... +LL | drop(y); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0503`. From 3bd39840cb2b74661eddedc600fd39ad77feb2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Nov 2019 16:06:28 -0800 Subject: [PATCH 02/15] Do not ICE on trait aliases with missing obligations --- src/librustc_typeck/astconv.rs | 11 ++++++++--- src/test/ui/issues/issue-65673.rs | 12 ++++++++++++ src/test/ui/issues/issue-65673.stderr | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-65673.rs create mode 100644 src/test/ui/issues/issue-65673.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index aa05a08686a99..a8d2c6e812ff4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1223,10 +1223,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by /// removing the dummy `Self` type (`trait_object_dummy_self`). - fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>) - -> ty::ExistentialTraitRef<'tcx> { + fn trait_ref_to_existential( + &self, + trait_ref: ty::TraitRef<'tcx>, + ) -> ty::ExistentialTraitRef<'tcx> { if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self { - bug!("trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref); + self.tcx().sess.delay_span_bug(DUMMY_SP, &format!( + "trait_ref_to_existential called on {:?} with non-dummy Self", + trait_ref, + )); } ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) } diff --git a/src/test/ui/issues/issue-65673.rs b/src/test/ui/issues/issue-65673.rs new file mode 100644 index 0000000000000..ea1d70194b191 --- /dev/null +++ b/src/test/ui/issues/issue-65673.rs @@ -0,0 +1,12 @@ +#![feature(trait_alias)] +trait Trait {} +trait WithType { + type Ctx; +} +trait Alias = where T: Trait; + +impl WithType for T { + type Ctx = dyn Alias; +//~^ ERROR the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time +} +fn main() {} diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr new file mode 100644 index 0000000000000..a556e35b6a944 --- /dev/null +++ b/src/test/ui/issues/issue-65673.stderr @@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time + --> $DIR/issue-65673.rs:9:5 + | +LL | type Ctx; + | --- associated type defined here +... +LL | impl WithType for T { + | ---------------------- in this `impl` item +LL | type Ctx = dyn Alias; + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = note: to learn more, visit + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2f44bb070c10e80374d4b6c865342c3a6b3d572c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Nov 2019 11:29:01 -0800 Subject: [PATCH 03/15] review comments --- src/librustc_typeck/astconv.rs | 4 ++++ src/test/ui/issues/issue-65673.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a8d2c6e812ff4..91bf0ca2b33d3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1228,6 +1228,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref: ty::TraitRef<'tcx>, ) -> ty::ExistentialTraitRef<'tcx> { if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self { + // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, which + // picks up non-supertraits where clauses - but also, the object safety completely + // ignores trait aliases, which could be object safety hazards. We `delay_span_bug` + // here to avoid an ICE in stable even when the feature is disabled. (#66420) self.tcx().sess.delay_span_bug(DUMMY_SP, &format!( "trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref, diff --git a/src/test/ui/issues/issue-65673.rs b/src/test/ui/issues/issue-65673.rs index ea1d70194b191..4b47bd493a568 100644 --- a/src/test/ui/issues/issue-65673.rs +++ b/src/test/ui/issues/issue-65673.rs @@ -1,4 +1,4 @@ -#![feature(trait_alias)] +#![feature(trait_alias)] // Enabled to reduce stderr output, but can be triggered even if disabled. trait Trait {} trait WithType { type Ctx; From 099b9da89874dac289a1475cb62141b063cdf62b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Nov 2019 14:57:06 -0800 Subject: [PATCH 04/15] Move `trait_ref_to_existential` to a closure review comment --- src/librustc_typeck/astconv.rs | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 91bf0ca2b33d3..e1b540515af41 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1221,25 +1221,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) } - /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - /// removing the dummy `Self` type (`trait_object_dummy_self`). - fn trait_ref_to_existential( - &self, - trait_ref: ty::TraitRef<'tcx>, - ) -> ty::ExistentialTraitRef<'tcx> { - if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, which - // picks up non-supertraits where clauses - but also, the object safety completely - // ignores trait aliases, which could be object safety hazards. We `delay_span_bug` - // here to avoid an ICE in stable even when the feature is disabled. (#66420) - self.tcx().sess.delay_span_bug(DUMMY_SP, &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - )); - } - ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) - } - fn conv_object_ty_poly_trait_ref(&self, span: Span, trait_bounds: &[hir::PolyTraitRef], @@ -1421,13 +1402,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("regular_traits: {:?}", regular_traits); debug!("auto_traits: {:?}", auto_traits); + // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by + // removing the dummy `Self` type (`trait_object_dummy_self`). + let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { + if trait_ref.self_ty() != dummy_self { + // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, + // which picks up non-supertraits where clauses - but also, the object safety + // completely ignores trait aliases, which could be object safety hazards. We + // `delay_span_bug` here to avoid an ICE in stable even when the feature is + // disabled. (#66420) + tcx.sess.delay_span_bug(DUMMY_SP, &format!( + "trait_ref_to_existential called on {:?} with non-dummy Self", + trait_ref, + )); + } + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }; + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { - i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref)) + i.trait_ref().map_bound(|trait_ref| trait_ref_to_existential(trait_ref)) }); let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { - let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); + let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); ty::ExistentialProjection { ty: b.ty, item_def_id: b.projection_ty.item_def_id, From dbcbaf07f18088d0d84bbf35c67a1eed8364f8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Nov 2019 15:22:45 -0800 Subject: [PATCH 05/15] Do not ICE in `if` without `else` in `async fn` --- src/librustc_typeck/check/generator_interior.rs | 10 ++++++++-- .../async-await/issue-66387-if-without-else.rs | 8 ++++++++ .../issue-66387-if-without-else.stderr | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/async-await/issue-66387-if-without-else.rs create mode 100644 src/test/ui/async-await/issue-66387-if-without-else.stderr diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index ff9c945eec452..6e254122c0100 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -244,7 +244,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // can be reborrowed without needing to spill to a temporary. // If this were not the case, then we could conceivably have // to create intermediate temporaries.) - let ty = self.fcx.tables.borrow().expr_ty(expr); - self.record(ty, scope, Some(expr), expr.span); + // + // The type table might not have invormation for this expression + // if it is in a malformed scope. (#66387) + if let Some(ty) = self.fcx.tables.borrow().expr_ty_opt(expr) { + self.record(ty, scope, Some(expr), expr.span); + } else { + self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); + } } } diff --git a/src/test/ui/async-await/issue-66387-if-without-else.rs b/src/test/ui/async-await/issue-66387-if-without-else.rs new file mode 100644 index 0000000000000..3602b09c0ece7 --- /dev/null +++ b/src/test/ui/async-await/issue-66387-if-without-else.rs @@ -0,0 +1,8 @@ +// edition:2018 +async fn f() -> i32 { + if true { //~ ERROR if may be missing an else clause + return 0; + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-66387-if-without-else.stderr b/src/test/ui/async-await/issue-66387-if-without-else.stderr new file mode 100644 index 0000000000000..32952059525a0 --- /dev/null +++ b/src/test/ui/async-await/issue-66387-if-without-else.stderr @@ -0,0 +1,16 @@ +error[E0317]: if may be missing an else clause + --> $DIR/issue-66387-if-without-else.rs:3:5 + | +LL | / if true { +LL | | return 0; +LL | | } + | |_____^ expected (), found i32 + | + = note: expected type `()` + found type `i32` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0317`. From 944dece5259e99d4ca6c1d01c0861724a9740cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Nov 2019 11:08:56 -0800 Subject: [PATCH 06/15] review comments --- src/librustc_typeck/check/generator_interior.rs | 2 +- src/test/ui/async-await/issue-66387-if-without-else.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 6e254122c0100..6e37c0dbbdf9d 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // If this were not the case, then we could conceivably have // to create intermediate temporaries.) // - // The type table might not have invormation for this expression + // The type table might not have information for this expression // if it is in a malformed scope. (#66387) if let Some(ty) = self.fcx.tables.borrow().expr_ty_opt(expr) { self.record(ty, scope, Some(expr), expr.span); diff --git a/src/test/ui/async-await/issue-66387-if-without-else.rs b/src/test/ui/async-await/issue-66387-if-without-else.rs index 3602b09c0ece7..aa5a8db61210d 100644 --- a/src/test/ui/async-await/issue-66387-if-without-else.rs +++ b/src/test/ui/async-await/issue-66387-if-without-else.rs @@ -3,6 +3,8 @@ async fn f() -> i32 { if true { //~ ERROR if may be missing an else clause return 0; } + // An `if` block without `else` causes the type table not to have a type for this expr. + // Check that we do not unconditionally access the type table and we don't ICE. } fn main() {} From 7ce52265ac719f0c4f1306a9740c733f801579d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Nov 2019 14:45:52 -0800 Subject: [PATCH 07/15] Fix ICE when trying to suggest `Type<>` instead of `Type()` --- src/librustc/hir/lowering.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6b6032516ca73..e665e058e6022 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1874,15 +1874,16 @@ impl<'a> LoweringContext<'a> { if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) { // Do not suggest going from `Trait()` to `Trait<>` if data.inputs.len() > 0 { - let split = snippet.find('(').unwrap(); - let trait_name = &snippet[0..split]; - let args = &snippet[split + 1 .. snippet.len() - 1]; - err.span_suggestion( - data.span, - "use angle brackets instead", - format!("{}<{}>", trait_name, args), - Applicability::MaybeIncorrect, - ); + if let Some(split) = snippet.find('(') { + let trait_name = &snippet[0..split]; + let args = &snippet[split + 1 .. snippet.len() - 1]; + err.span_suggestion( + data.span, + "use angle brackets instead", + format!("{}<{}>", trait_name, args), + Applicability::MaybeIncorrect, + ); + } } }; err.emit(); From de2b8820e152e1d9612f7233f70ae4c931e3037e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Nov 2019 14:28:15 -0800 Subject: [PATCH 08/15] Do not ICE on recovery from unmet associated type bound obligation --- src/librustc_typeck/check/mod.rs | 11 ++++++++--- src/test/ui/issues/issue-66353.rs | 15 +++++++++++++++ src/test/ui/issues/issue-66353.stderr | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-66353.rs create mode 100644 src/test/ui/issues/issue-66353.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f7132cd868aac..b39932dfe0142 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -705,9 +705,14 @@ impl Inherited<'a, 'tcx> { span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); } - self.fulfillment_cx - .borrow_mut() - .register_predicate_obligation(self, obligation); + let _ = self.fulfillment_cx + .try_borrow_mut() + .map_err(|e| self.tcx.sess.delay_span_bug(obligation.cause.span, &format!( + "fullfillment context already borrowed: {:?} - {:?}", + e, + obligation, + ))) + .map(|mut cx| cx.register_predicate_obligation(self, obligation)); } fn register_predicates(&self, obligations: I) diff --git a/src/test/ui/issues/issue-66353.rs b/src/test/ui/issues/issue-66353.rs new file mode 100644 index 0000000000000..d8abdd5206ef4 --- /dev/null +++ b/src/test/ui/issues/issue-66353.rs @@ -0,0 +1,15 @@ +// #66353: ICE when trying to recover from incorrect associated type + +trait _Func { + fn func(_: Self); +} + +trait _A { + type AssocT; +} + +fn main() { + _Func::< <() as _A>::AssocT >::func(()); + //~^ ERROR the trait bound `(): _A` is not satisfied + //~| ERROR the trait bound `(): _Func<_>` is not satisfied +} diff --git a/src/test/ui/issues/issue-66353.stderr b/src/test/ui/issues/issue-66353.stderr new file mode 100644 index 0000000000000..8fd50300ca63e --- /dev/null +++ b/src/test/ui/issues/issue-66353.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): _A` is not satisfied + --> $DIR/issue-66353.rs:12:14 + | +LL | _Func::< <() as _A>::AssocT >::func(()); + | ^^^^^^^^^^^^^^^^^^ the trait `_A` is not implemented for `()` + +error[E0277]: the trait bound `(): _Func<_>` is not satisfied + --> $DIR/issue-66353.rs:12:41 + | +LL | fn func(_: Self); + | ----------------- required by `_Func::func` +... +LL | _Func::< <() as _A>::AssocT >::func(()); + | ^^ the trait `_Func<_>` is not implemented for `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 4e02ef37b218a6047d581697249ebe4c1a11c9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Nov 2019 11:34:46 -0800 Subject: [PATCH 09/15] review comments --- src/librustc_typeck/check/mod.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b39932dfe0142..a02d5b5a571c5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -705,14 +705,9 @@ impl Inherited<'a, 'tcx> { span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); } - let _ = self.fulfillment_cx - .try_borrow_mut() - .map_err(|e| self.tcx.sess.delay_span_bug(obligation.cause.span, &format!( - "fullfillment context already borrowed: {:?} - {:?}", - e, - obligation, - ))) - .map(|mut cx| cx.register_predicate_obligation(self, obligation)); + self.fulfillment_cx + .borrow_mut() + .register_predicate_obligation(self, obligation); } fn register_predicates(&self, obligations: I) @@ -3015,7 +3010,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fallback_has_occurred: bool, mutate_fullfillment_errors: impl Fn(&mut Vec>), ) { - if let Err(mut errors) = self.fulfillment_cx.borrow_mut().select_where_possible(self) { + let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); + if let Err(mut errors) = result { mutate_fullfillment_errors(&mut errors); self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); } From b78102019b830f9cf6b33d8d1d0774148cea1d98 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 13 Nov 2019 19:32:12 +0100 Subject: [PATCH 10/15] find_deprecation: deprecation attr may be ill-formed meta. --- src/libsyntax/attr/builtin.rs | 5 ++++- .../issue-66340-deprecated-attr-non-meta-grammar.rs | 11 +++++++++++ ...ssue-66340-deprecated-attr-non-meta-grammar.stderr | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs create mode 100644 src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 84c86c9651fcf..5217f63660795 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -655,7 +655,10 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, break } - let meta = attr.meta().unwrap(); + let meta = match attr.meta() { + Some(meta) => meta, + None => continue, + }; depr = match &meta.kind { MetaItemKind::Word => Some(Deprecation { since: None, note: None }), MetaItemKind::NameValue(..) => { diff --git a/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs new file mode 100644 index 0000000000000..c0cde75d4caeb --- /dev/null +++ b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs @@ -0,0 +1,11 @@ +// The original problem in #66340 was that `find_deprecation_generic` +// called `attr.meta().unwrap()` under the assumption that the attribute +// was a well-formed `MetaItem`. + +fn main() { + foo() +} + +#[deprecated(note = test)] +//~^ ERROR expected unsuffixed literal or identifier, found `test` +fn foo() {} diff --git a/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr new file mode 100644 index 0000000000000..24178faf8de78 --- /dev/null +++ b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr @@ -0,0 +1,8 @@ +error: expected unsuffixed literal or identifier, found `test` + --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21 + | +LL | #[deprecated(note = test)] + | ^^^^ + +error: aborting due to previous error + From 92c4e192491dc84cc97aea5afc0ed00faf5f1e61 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 13 Nov 2019 12:05:37 +0100 Subject: [PATCH 11/15] parser: don't use `unreachable!()` in `fn unexpected`. --- src/libsyntax/parse/parser.rs | 4 +++- .../parser/issue-66357-unexpected-unreachable.rs | 14 ++++++++++++++ .../issue-66357-unexpected-unreachable.stderr | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/issue-66357-unexpected-unreachable.rs create mode 100644 src/test/ui/parser/issue-66357-unexpected-unreachable.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e81d4573b73e5..e6e9d37962af4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -442,7 +442,9 @@ impl<'a> Parser<'a> { crate fn unexpected(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), - Ok(_) => unreachable!(), + // We can get `Ok(true)` from `recover_closing_delimiter` + // which is called in `expected_one_of_not_found`. + Ok(_) => FatalError.raise(), } } diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.rs b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs new file mode 100644 index 0000000000000..1730adfa91419 --- /dev/null +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs @@ -0,0 +1,14 @@ +// The problem in #66357 was that the call trace: +// +// - parse_fn_block_decl +// - expect_or +// - unexpected +// - expect_one_of +// - expected_one_of_not_found +// - recover_closing_delimiter +// +// ended up bubbling up `Ok(true)` to `unexpected` which then used `unreachable!()`. + +fn f() { |[](* } +//~^ ERROR expected one of `,` or `:`, found `(` +//~| ERROR expected one of `)`, `-`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr new file mode 100644 index 0000000000000..560b46a192579 --- /dev/null +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr @@ -0,0 +1,15 @@ +error: expected one of `,` or `:`, found `(` + --> $DIR/issue-66357-unexpected-unreachable.rs:12:13 + | +LL | fn f() { |[](* } + | ^ expected one of `,` or `:` here + +error: expected one of `)`, `-`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` + --> $DIR/issue-66357-unexpected-unreachable.rs:12:14 + | +LL | fn f() { |[](* } + | -^ help: `)` may belong here + | | + | unclosed delimiter + +error: aborting due to 2 previous errors \ No newline at end of file From 71dbc682b3f2485da8447bb3803c2ae228ebcab4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 10 Nov 2019 11:15:34 +0100 Subject: [PATCH 12/15] Undo an assert causing an ICE until we fix the problem properly --- src/librustc_target/abi/mod.rs | 6 +----- src/test/ui/issues/issue-65462.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-65462.rs diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index fde5c5bed4d91..26d37f196befa 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -738,11 +738,7 @@ impl FieldPlacement { pub fn offset(&self, i: usize) -> Size { match *self { - FieldPlacement::Union(count) => { - assert!(i < count, - "Tried to access field {} of union with {} fields", i, count); - Size::ZERO - }, + FieldPlacement::Union(_) => Size::ZERO, FieldPlacement::Array { stride, count } => { let i = i as u64; assert!(i < count); diff --git a/src/test/ui/issues/issue-65462.rs b/src/test/ui/issues/issue-65462.rs new file mode 100644 index 0000000000000..8c39ea531d244 --- /dev/null +++ b/src/test/ui/issues/issue-65462.rs @@ -0,0 +1,15 @@ +// build-pass + +enum Empty {} +enum Enum { + Empty( Empty ) +} + +fn foobar() -> Option< Enum > { + let value: Option< Empty > = None; + Some( Enum::Empty( value? ) ) +} + +fn main() { + foobar(); +} From 0f177c30c8268c6d9254b4cbedc6ed5419060a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 4 Nov 2019 10:57:41 -0800 Subject: [PATCH 13/15] Do not ICE whith a precision flag in formatting str and no format arguments --- src/libsyntax_ext/format.rs | 10 ++++++---- src/test/ui/if/ifmt-bad-arg.rs | 5 +++++ src/test/ui/if/ifmt-bad-arg.stderr | 13 ++++++++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 37310f46f7eed..3c7f80aa399bf 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -374,10 +374,12 @@ impl<'a, 'b> Context<'a, 'b> { format!("are {} arguments", count) }, )); - e.span_label( - self.args[pos].span, - "this parameter corresponds to the precision flag", - ); + if let Some(arg) = self.args.get(pos) { + e.span_label( + arg.span, + "this parameter corresponds to the precision flag", + ); + } zero_based_note = true; } _ => {} diff --git a/src/test/ui/if/ifmt-bad-arg.rs b/src/test/ui/if/ifmt-bad-arg.rs index ba897f171af25..a0b0a8fb98594 100644 --- a/src/test/ui/if/ifmt-bad-arg.rs +++ b/src/test/ui/if/ifmt-bad-arg.rs @@ -86,4 +86,9 @@ tenth number: {}", println!("{:foo}", 1); //~ ERROR unknown format trait `foo` println!("{5} {:4$} {6:7$}", 1); //~^ ERROR invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument) + + // We used to ICE here because we tried to unconditionally access the first argument, which + // doesn't exist. + println!("{:.*}"); + //~^ ERROR 2 positional arguments in format string, but no arguments were given } diff --git a/src/test/ui/if/ifmt-bad-arg.stderr b/src/test/ui/if/ifmt-bad-arg.stderr index c58cbc312335a..11dcc3a6d232e 100644 --- a/src/test/ui/if/ifmt-bad-arg.stderr +++ b/src/test/ui/if/ifmt-bad-arg.stderr @@ -285,6 +285,17 @@ LL | println!("{5} {:4$} {6:7$}", 1); = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html +error: 2 positional arguments in format string, but no arguments were given + --> $DIR/ifmt-bad-arg.rs:92:15 + | +LL | println!("{:.*}"); + | ^^--^ + | | + | this precision flag adds an extra required argument at position 0, which is why there are 2 arguments expected + | + = note: positional arguments are zero-based + = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html + error[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:78:32 | @@ -303,6 +314,6 @@ LL | println!("{} {:07$.*} {}", 1, 3.2, 4); = note: expected type `&usize` found type `&{float}` -error: aborting due to 35 previous errors +error: aborting due to 36 previous errors For more information about this error, try `rustc --explain E0308`. From 75611d28d010a73f9c912f43c5af31682906f470 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 13 Nov 2019 19:19:25 -0500 Subject: [PATCH 14/15] [ConstProp] Avoid OOM crashes by not evaluating large Places Fix spurious CI filures due to OOM Fixes #66397 --- src/librustc_mir/transform/const_prop.rs | 10 +++++++++- src/test/ui/consts/issue-66342.rs | 12 ++++++++++++ src/test/ui/consts/issue-66397.rs | 8 ++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/issue-66342.rs create mode 100644 src/test/ui/consts/issue-66397.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e7095101f465d..272369008370a 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -22,7 +22,7 @@ use rustc::ty::subst::InternalSubsts; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc::ty::layout::{ - LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, + LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size, }; use crate::interpret::{ @@ -34,6 +34,9 @@ use crate::interpret::{ use crate::const_eval::error_to_const_error; use crate::transform::{MirPass, MirSource}; +/// The maximum number of bytes that we'll allocate space for a return value. +const MAX_ALLOC_LIMIT: u64 = 1024; + pub struct ConstProp; impl<'tcx> MirPass<'tcx> for ConstProp { @@ -434,6 +437,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) -> Option<()> { let span = source_info.span; + // #66397: Don't try to eval into large places as that can cause an OOM + if place_layout.size >= Size::from_bytes(MAX_ALLOC_LIMIT) { + return None; + } + let overflow_check = self.tcx.sess.overflow_checks(); // Perform any special handling for specific Rvalue types. diff --git a/src/test/ui/consts/issue-66342.rs b/src/test/ui/consts/issue-66342.rs new file mode 100644 index 0000000000000..417f69041658d --- /dev/null +++ b/src/test/ui/consts/issue-66342.rs @@ -0,0 +1,12 @@ +// check-pass +// only-x86_64 + +// Checks that the compiler does not actually try to allocate 4 TB during compilation and OOM crash. + +fn foo() -> [u8; 4 * 1024 * 1024 * 1024 * 1024] { + unimplemented!() +} + +fn main() { + foo(); +} diff --git a/src/test/ui/consts/issue-66397.rs b/src/test/ui/consts/issue-66397.rs new file mode 100644 index 0000000000000..1b4aff43b5bf1 --- /dev/null +++ b/src/test/ui/consts/issue-66397.rs @@ -0,0 +1,8 @@ +// check-pass +// only-x86_64 + +// Checks that the compiler does not actually try to allocate 4 TB during compilation and OOM crash. + +fn main() { + [0; 4 * 1024 * 1024 * 1024 * 1024]; +} From d8612f3547da805826a07de9518d7b6176511041 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 6 Dec 2019 15:21:32 -0500 Subject: [PATCH 15/15] Fix tests --- src/test/ui/parser/issue-66357-unexpected-unreachable.stderr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr index 560b46a192579..c7b6e15ddace8 100644 --- a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr @@ -12,4 +12,5 @@ LL | fn f() { |[](* } | | | unclosed delimiter -error: aborting due to 2 previous errors \ No newline at end of file +error: aborting due to 2 previous errors +