Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #72588

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions src/libcore/ops/try.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
16 changes: 6 additions & 10 deletions src/librustc_codegen_ssa/mir/constant.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_hir/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
1 change: 0 additions & 1 deletion src/librustc_middle/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
8 changes: 0 additions & 8 deletions src/librustc_middle/query/mod.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -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(
Expand Down
30 changes: 20 additions & 10 deletions src/librustc_middle/ty/print/pretty.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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("<too short allocation>"))
}
}
// FIXME: for statics and functions, we could in principle print more detail.
Some(GlobalAlloc::Static(def_id)) => p!(write("<static({:?})>", def_id)),
Some(GlobalAlloc::Function(_)) => p!(write("<function>")),
None => p!(write("<dangling pointer>")),
},
// Bool
(Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")),
(Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")),
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 0 additions & 27 deletions src/librustc_mir/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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<VariantIdx>,
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),
Expand Down
4 changes: 0 additions & 4 deletions src/librustc_mir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 6 additions & 12 deletions src/librustc_mir/transform/nrvo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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.
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_trait_selection/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trait_selection/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {:?}",
Expand Down Expand Up @@ -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)),
Expand Down Expand Up @@ -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<TyOrConstInferVar<'tcx>> {
Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/async-await/issue-72442.rs
Original file line number Diff line number Diff line change
@@ -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<dyn std::error::Error>> {
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) -> F::Output
where
F: Future<Output = Result<(), Box<dyn std::error::Error>>>,
{
Ok(())
}
14 changes: 14 additions & 0 deletions src/test/ui/async-await/issue-72442.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0277]: the trait bound `std::option::Option<&str>: std::convert::AsRef<std::path::Path>` is not satisfied
--> $DIR/issue-72442.rs:12:36
|
LL | let mut f = File::open(path.to_str())?;
| ^^^^^^^^^^^^^ the trait `std::convert::AsRef<std::path::Path>` is not implemented for `std::option::Option<&str>`
|
::: $SRC_DIR/libstd/fs.rs:LL:COL
|
LL | pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
| ----------- 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`.
35 changes: 35 additions & 0 deletions src/test/ui/const-generics/issue-70180-1-stalled_on.rs
Original file line number Diff line number Diff line change
@@ -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, const N: usize>() -> [T; N]
where
[T; N]: Default,
{
Default::default()
}

fn main() {
works();
didnt_work();
}
35 changes: 35 additions & 0 deletions src/test/ui/const-generics/issue-70180-2-stalled_on.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
fn foo(&self) {}
}

impl Foo<i32> for [u8; 4] {}
impl Foo<i64> for [u8; 8] {}

// Only needed because `[u8; _]` is not valid type syntax.
fn default_byte_array<const N: usize>() -> [u8; N]
where
[u8; N]: Default,
{
Default::default()
}

fn main() {
works();
didnt_work();
}