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_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_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 04fe3b60b6a87..83bada4041963 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -257,4 +257,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_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 2445d484754d0..1083563c647b6 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_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 031ce6629bf4d..10426cf856188 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), 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) 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. diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index b1c6815c7414f..50af3c12c6f38 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; diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index e44163f7bb1a4..e2ee22d8a55f8 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -357,7 +357,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 {:?}", @@ -435,7 +435,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)), @@ -603,8 +603,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/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs new file mode 100644 index 0000000000000..61c8c8c1594d3 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.rs @@ -0,0 +1,26 @@ +// edition:2018 +// compile-flags:-Cincremental=tmp/issue-72442 + +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 + let mut src = String::new(); + f.read_to_string(&mut src)?; + Ok(()) + } + }) +} + +fn block_on(f: F) -> F::Output +where + F: Future>>, +{ + 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`. 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(); +}