From a8c152dfc921e8ec2c00f65e7c731197e522a96d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 9 May 2020 22:01:15 +0200 Subject: [PATCH 1/7] add regression tests + improve method name --- .../traits/fulfill.rs | 8 ++--- .../issue-70180-1-stalled_on.rs | 35 +++++++++++++++++++ .../issue-70180-2-stalled_on.rs | 35 +++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/issue-70180-1-stalled_on.rs create mode 100644 src/test/ui/const-generics/issue-70180-2-stalled_on.rs diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 1e056c96acd38..dfffdbedf4ca4 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -355,7 +355,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { // trait selection is because we don't have enough // information about the types in the trait. pending_obligation.stalled_on = - trait_ref_type_vars(self.selcx, data.to_poly_trait_ref()); + trait_ref_infer_vars(self.selcx, data.to_poly_trait_ref()); debug!( "process_predicate: pending obligation {:?} now stalled on {:?}", @@ -433,7 +433,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { Ok(None) => { let tcx = self.selcx.tcx(); pending_obligation.stalled_on = - trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); + trait_ref_infer_vars(self.selcx, data.to_poly_trait_ref(tcx)); ProcessResult::Unchanged } Ok(Some(os)) => ProcessResult::Changed(mk_pending(infcx, os)), @@ -539,8 +539,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } -/// Returns the set of type inference variables contained in a trait ref. -fn trait_ref_type_vars<'a, 'tcx>( +/// Returns the set of inference variables contained in a trait ref. +fn trait_ref_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Vec> { diff --git a/src/test/ui/const-generics/issue-70180-1-stalled_on.rs b/src/test/ui/const-generics/issue-70180-1-stalled_on.rs new file mode 100644 index 0000000000000..ff2a5250263d5 --- /dev/null +++ b/src/test/ui/const-generics/issue-70180-1-stalled_on.rs @@ -0,0 +1,35 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +pub fn works() { + let array/*: [_; _]*/ = default_array(); + let _: [_; 4] = array; + Foo::foo(&array); +} + +pub fn didnt_work() { + let array/*: [_; _]*/ = default_array(); + Foo::foo(&array); + let _: [_; 4] = array; +} + +trait Foo { + fn foo(&self) {} +} + +impl Foo for [i32; 4] {} +impl Foo for [i64; 8] {} + +// Only needed because `[_; _]` is not valid type syntax. +fn default_array() -> [T; N] +where + [T; N]: Default, +{ + Default::default() +} + +fn main() { + works(); + didnt_work(); +} diff --git a/src/test/ui/const-generics/issue-70180-2-stalled_on.rs b/src/test/ui/const-generics/issue-70180-2-stalled_on.rs new file mode 100644 index 0000000000000..83338668f4ffd --- /dev/null +++ b/src/test/ui/const-generics/issue-70180-2-stalled_on.rs @@ -0,0 +1,35 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn works() { + let array/*: [u8; _]*/ = default_byte_array(); + let _: [_; 4] = array; + Foo::foo(&array); +} + +fn didnt_work() { + let array/*: [u8; _]*/ = default_byte_array(); + Foo::foo(&array); + let _: [_; 4] = array; +} + +trait Foo { + fn foo(&self) {} +} + +impl Foo for [u8; 4] {} +impl Foo for [u8; 8] {} + +// Only needed because `[u8; _]` is not valid type syntax. +fn default_byte_array() -> [u8; N] +where + [u8; N]: Default, +{ + Default::default() +} + +fn main() { + works(); + didnt_work(); +} From 47cc221e9827ab1b92f20353f423916a3f14d182 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 22 May 2020 10:11:17 +0800 Subject: [PATCH 2/7] add mcve for issue 72442 --- src/test/ui/async-await/issue-72442.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/ui/async-await/issue-72442.rs diff --git a/src/test/ui/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs new file mode 100644 index 0000000000000..cced1da48f693 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.rs @@ -0,0 +1,25 @@ +// edition:2018 + +use std::fs::File; +use std::future::Future; +use std::io::prelude::*; + +fn main() -> Result<(), Box> { + block_on(async { + { + let path = std::path::Path::new("."); + let mut f = File::open(path.to_str())?; + //~^ ERROR the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied + let mut src = String::new(); + f.read_to_string(&mut src)?; + Ok(()) + } + }) +} + +fn block_on(f: F) -> F::Output +where + F: Future>>, +{ + Ok(()) +} From 7cdc8972342e8f4946b518ac4886079f604cf2c1 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 22 May 2020 10:11:52 +0800 Subject: [PATCH 3/7] only try to suggest for try trait_ref --- src/libcore/ops/try.rs | 1 + src/librustc_hir/lang_items.rs | 2 ++ src/librustc_trait_selection/traits/error_reporting/mod.rs | 6 +++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 996a01d413cbc..e15ea11569f34 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -25,6 +25,7 @@ ) )] #[doc(alias = "?")] +#[cfg_attr(not(bootstrap), lang = "try")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 53f72804a848d..8921cc0c99dca 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -256,4 +256,6 @@ language_item_table! { AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; TerminationTraitLangItem, "termination", termination, Target::Trait; + + TryTraitLangItem, "try", try_trait, Target::Trait; } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 139b860072224..f18a417cccd05 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -402,7 +402,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); self.note_version_mismatch(&mut err, &trait_ref); - self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + + if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { + self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + } + if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { err.emit(); return; From d24ba6d1243db648eac365eaf637264e6d04d5f1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 21 May 2020 19:27:12 -0700 Subject: [PATCH 4/7] Perform MIR NRVO even if types don't match --- src/librustc_mir/transform/nrvo.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/transform/nrvo.rs b/src/librustc_mir/transform/nrvo.rs index 941ffa94aa857..ffad1ebea005b 100644 --- a/src/librustc_mir/transform/nrvo.rs +++ b/src/librustc_mir/transform/nrvo.rs @@ -44,18 +44,6 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { } }; - // Sometimes, the return place is assigned a local of a different but coercable type, for - // example `&T` instead of `&mut T`. Overwriting the `LocalInfo` for the return place would - // result in it having an incorrect type. Although this doesn't seem to cause a problem in - // codegen, bail out anyways since it happens so rarely. - let ret_ty = body.local_decls[mir::RETURN_PLACE].ty; - let assigned_ty = body.local_decls[returned_local].ty; - if ret_ty != assigned_ty { - debug!("`{:?}` was eligible for NRVO but for type mismatch", src.def_id()); - debug!("typeof(_0) != typeof({:?}); {:?} != {:?}", returned_local, ret_ty, assigned_ty); - return; - } - debug!( "`{:?}` was eligible for NRVO, making {:?} the return place", src.def_id(), @@ -72,6 +60,12 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { // Overwrite the debuginfo of `_0` with that of the renamed local. let (renamed_decl, ret_decl) = body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE); + + // Sometimes, the return place is assigned a local of a different but coercable type, for + // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means + // its type may no longer match the return type of its function. This doesn't cause a + // problem in codegen because these two types are layout-compatible, but may be unexpected. + debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty); ret_decl.clone_from(renamed_decl); // The return place is always mutable. From 16ba3e129d5d37c63b7000fcd4b52261e7f1c4f1 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 22 May 2020 10:12:03 +0800 Subject: [PATCH 5/7] bless issue-72442 --- src/test/ui/async-await/issue-72442.rs | 3 ++- src/test/ui/async-await/issue-72442.stderr | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/async-await/issue-72442.stderr diff --git a/src/test/ui/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs index cced1da48f693..61c8c8c1594d3 100644 --- a/src/test/ui/async-await/issue-72442.rs +++ b/src/test/ui/async-await/issue-72442.rs @@ -1,4 +1,5 @@ // edition:2018 +// compile-flags:-Cincremental=tmp/issue-72442 use std::fs::File; use std::future::Future; @@ -9,7 +10,7 @@ fn main() -> Result<(), Box> { { let path = std::path::Path::new("."); let mut f = File::open(path.to_str())?; - //~^ ERROR the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied + //~^ ERROR the trait bound let mut src = String::new(); f.read_to_string(&mut src)?; Ok(()) diff --git a/src/test/ui/async-await/issue-72442.stderr b/src/test/ui/async-await/issue-72442.stderr new file mode 100644 index 0000000000000..5685433357871 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied + --> $DIR/issue-72442.rs:12:36 + | +LL | let mut f = File::open(path.to_str())?; + | ^^^^^^^^^^^^^ the trait `std::convert::AsRef` is not implemented for `std::option::Option<&str>` + | + ::: $SRC_DIR/libstd/fs.rs:LL:COL + | +LL | pub fn open>(path: P) -> io::Result { + | ----------- required by this bound in `std::fs::File::open` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 245ebc7210f99528d65e4b46f012dbde2a2f299f Mon Sep 17 00:00:00 2001 From: Rakshith Ravi Date: Sun, 24 May 2020 19:38:54 +0530 Subject: [PATCH 6/7] Removed all instances of const_field. --- src/librustc_codegen_ssa/mir/constant.rs | 16 +++++------- src/librustc_middle/dep_graph/dep_node.rs | 1 - src/librustc_middle/query/mod.rs | 8 ------ src/librustc_mir/const_eval/eval_queries.rs | 2 +- src/librustc_mir/const_eval/mod.rs | 27 --------------------- src/librustc_mir/lib.rs | 4 --- 6 files changed, 7 insertions(+), 51 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index d2629b771c2af..574f91e5b4d81 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -1,6 +1,5 @@ use crate::mir::operand::OperandRef; use crate::traits::*; -use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::layout::HasTyCtxt; @@ -59,17 +58,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant .map(|val| { let field_ty = ty.builtin_index().unwrap(); - let fields = match ty.kind { - ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()), - _ => bug!("invalid simd shuffle type: {}", ty), - }; let c = ty::Const::from_value(bx.tcx(), val, ty); - let values: Vec<_> = (0..fields) + let values: Vec<_> = bx + .tcx() + .destructure_const(ty::ParamEnv::reveal_all().and(&c)) + .fields + .into_iter() .map(|field| { - let field = bx.tcx().const_field( - ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))), - ); - if let Some(prim) = field.try_to_scalar() { + if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { Abi::Scalar(ref x) => x, diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/src/librustc_middle/dep_graph/dep_node.rs index 3303790088010..2c0524fa99102 100644 --- a/src/librustc_middle/dep_graph/dep_node.rs +++ b/src/librustc_middle/dep_graph/dep_node.rs @@ -49,7 +49,6 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; use crate::traits::query::{ diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index f7f5c5df8d67b..f04a6f0899a06 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1,5 +1,4 @@ use crate::dep_graph::SerializedDepNodeIndex; -use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; use crate::traits::query::{ @@ -553,13 +552,6 @@ rustc_queries! { } } - /// Extracts a field of a (variant of a) const. - query const_field( - key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> - ) -> ConstValue<'tcx> { - desc { "extract field of const" } - } - /// Destructure a constant ADT or array into its variant index and its /// field values. query destructure_const( diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index fd5e0632a2c10..695e0741e3598 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -122,7 +122,7 @@ pub(super) fn op_to_const<'tcx>( } else { // It is guaranteed that any non-slice scalar pair is actually ByRef here. // When we come back from raw const eval, we are always by-ref. The only way our op here is - // by-val is if we are in const_field, i.e., if this is (a field of) something that we + // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or // structs containing such. op.try_as_mplace(ecx) diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs index 7f557e340bbc8..3539ccf5de038 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -5,7 +5,6 @@ use std::convert::TryFrom; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use rustc_target::abi::VariantIdx; use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx}; @@ -19,32 +18,6 @@ pub use eval_queries::*; pub use fn_queries::*; pub use machine::*; -/// Extracts a field of a (variant of a) const. -// this function uses `unwrap` copiously, because an already validated constant must have valid -// fields and can thus never fail outside of compiler bugs -pub(crate) fn const_field<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - variant: Option, - field: mir::Field, - value: &'tcx ty::Const<'tcx>, -) -> ConstValue<'tcx> { - trace!("const_field: {:?}, {:?}", field, value); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - // get the operand again - let op = ecx.eval_const_to_op(value, None).unwrap(); - // downcast - let down = match variant { - None => op, - Some(variant) => ecx.operand_downcast(op, variant).unwrap(), - }; - // then project - let field = ecx.operand_field(down, field.index()).unwrap(); - // and finally move back to the const world, always normalizing because - // this is not called for statics. - op_to_const(&ecx, field) -} - pub(crate) fn const_caller_location( tcx: TyCtxt<'tcx>, (file, line, col): (Symbol, u32, u32), diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 785c6c21d7443..928d5bf88f2fc 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -56,10 +56,6 @@ pub fn provide(providers: &mut Providers<'_>) { providers.const_eval_validated = const_eval::const_eval_validated_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.const_field = |tcx, param_env_and_value| { - let (param_env, (value, field)) = param_env_and_value.into_parts(); - const_eval::const_field(tcx, param_env, None, field, value) - }; providers.destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) From d59fa081ec272573ef560c4ea914466fce74db3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 08:52:16 +0200 Subject: [PATCH 7/7] fix ICE when debug-printing MIR --- src/librustc_middle/ty/print/pretty.rs | 30 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index f03d91aa64b78..a47addf18044c 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -1,5 +1,7 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; -use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar}; +use crate::mir::interpret::{ + sign_extend, truncate, AllocId, ConstValue, GlobalAlloc, Pointer, Scalar, +}; use crate::ty::layout::IntegerExt; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; @@ -951,15 +953,20 @@ pub trait PrettyPrinter<'tcx>: }, _, ), - ) => { - let byte_str = self - .tcx() - .global_alloc(ptr.alloc_id) - .unwrap_memory() - .get_bytes(&self.tcx(), ptr, Size::from_bytes(*data)) - .unwrap(); - p!(pretty_print_byte_str(byte_str)); - } + ) => match self.tcx().get_global_alloc(ptr.alloc_id) { + Some(GlobalAlloc::Memory(alloc)) => { + if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, Size::from_bytes(*data)) + { + p!(pretty_print_byte_str(byte_str)) + } else { + p!(write("")) + } + } + // FIXME: for statics and functions, we could in principle print more detail. + Some(GlobalAlloc::Static(def_id)) => p!(write("", def_id)), + Some(GlobalAlloc::Function(_)) => p!(write("")), + None => p!(write("")), + }, // Bool (Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")), (Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")), @@ -1018,6 +1025,9 @@ pub trait PrettyPrinter<'tcx>: )?; } (Scalar::Ptr(ptr), ty::FnPtr(_)) => { + // FIXME: this can ICE when the ptr is dangling or points to a non-function. + // We should probably have a helper method to share code with the "Byte strings" + // printing above (which also has to handle pointers to all sorts of things). let instance = self.tcx().global_alloc(ptr.alloc_id).unwrap_fn(); self = self.typed_value( |this| this.print_value_path(instance.def_id(), instance.substs),