Skip to content

Commit

Permalink
Auto merge of rust-lang#72589 - Dylan-DPC:rollup-7l2a2bo, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - rust-lang#72061 (add regression tests for stalled_on const vars)
 - rust-lang#72424 (fix ICE when debug-printing MIR)
 - rust-lang#72450 (Fix ice-rust-lang#72442)
 - rust-lang#72451 (Perform MIR NRVO even if types don't match)
 - rust-lang#72538 (Removed all instances of const_field.)

Failed merges:

r? @ghost
  • Loading branch information
bors committed May 25, 2020
2 parents f93bb2a + b6a8915 commit 698c5c6
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 78 deletions.
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();
}

0 comments on commit 698c5c6

Please sign in to comment.