Skip to content

Commit

Permalink
Auto merge of #97679 - Dylan-DPC:rollup-nswmgmx, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #97366 (Stabilize `{slice,array}::from_ref`)
 - #97653 (add cast kind of from_exposed_addr (int-to-ptr casts))
 - #97663 (take back half-baked noaliasing check in Assignment)
 - #97664 (On E0204 suggest missing type param bounds)
 - #97668 (rustdoc: clean up primitive.slice.html links)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jun 3, 2022
2 parents 3a90bed + d6f35b3 commit 72f7e31
Show file tree
Hide file tree
Showing 33 changed files with 370 additions and 87 deletions.
50 changes: 37 additions & 13 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2154,31 +2154,55 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
match (cast_ty_from, cast_ty_to) {
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (),
_ => {
span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty)
span_mirbug!(
self,
rvalue,
"Invalid PointerExposeAddress cast {:?} -> {:?}",
ty_from,
ty
)
}
}
}

CastKind::Misc => {
CastKind::PointerFromExposedAddress => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(*ty);
match (cast_ty_from, cast_ty_to) {
(None, _)
| (_, None | Some(CastTy::FnPtr))
| (Some(CastTy::Float), Some(CastTy::Ptr(_)))
| (
Some(CastTy::Ptr(_) | CastTy::FnPtr),
Some(CastTy::Float | CastTy::Int(_)),
) => {
span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,)
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (),
_ => {
span_mirbug!(
self,
rvalue,
"Invalid PointerFromExposedAddress cast {:?} -> {:?}",
ty_from,
ty
)
}
}
}

CastKind::Misc => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(*ty);
// Misc casts are either between floats and ints, or one ptr type to another.
match (cast_ty_from, cast_ty_to) {
(
Some(CastTy::Int(_)),
Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)),
Some(CastTy::Int(_) | CastTy::Float),
Some(CastTy::Int(_) | CastTy::Float),
)
| (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float))
| (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
_ => {
span_mirbug!(
self,
rvalue,
"Invalid Misc cast {:?} -> {:?}",
ty_from,
ty,
)
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,9 @@ fn codegen_stmt<'tcx>(
lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
}
Rvalue::Cast(
CastKind::Misc | CastKind::PointerExposeAddress,
CastKind::Misc
| CastKind::PointerExposeAddress
| CastKind::PointerFromExposedAddress,
ref operand,
to_ty,
) => {
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::CastKind::Pointer(
PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
)
| mir::CastKind::Misc => {
| mir::CastKind::Misc
// Since int2ptr can have arbitrary integer types as input (so we have to do
// sign extension and all that), it is currently best handled in the same code
// path as the other integer-to-X casts.
| mir::CastKind::PointerFromExposedAddress => {
assert!(bx.cx().is_backend_immediate(cast));
let ll_t_out = bx.cx().immediate_backend_type(cast);
if operand.layout.abi.is_uninhabited() {
Expand Down
34 changes: 24 additions & 10 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_immediate(res, dest)?;
}

PointerFromExposedAddress => {
let src = self.read_immediate(src)?;
let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
self.write_immediate(res, dest)?;
}

Misc => {
let src = self.read_immediate(src)?;
let res = self.misc_cast(&src, cast_ty)?;
Expand Down Expand Up @@ -201,6 +207,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
}

pub fn pointer_from_exposed_address_cast(
&mut self,
src: &ImmTy<'tcx, M::PointerTag>,
cast_ty: Ty<'tcx>,
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
assert!(src.layout.ty.is_integral());
assert_matches!(cast_ty.kind(), ty::RawPtr(_));

// First cast to usize.
let scalar = src.to_scalar()?;
let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
let addr = addr.to_machine_usize(self)?;

// Then turn address into pointer.
let ptr = M::ptr_from_addr_cast(&self, addr);
Ok(Scalar::from_maybe_pointer(ptr, self).into())
}

pub fn cast_from_int_like(
&self,
scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
Expand All @@ -225,16 +249,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Scalar::from_uint(v, size)
}

RawPtr(_) => {
assert!(src_layout.ty.is_integral());

let size = self.pointer_size();
let addr = u64::try_from(size.truncate(v)).unwrap();

let ptr = M::ptr_from_addr_cast(&self, addr);
Scalar::from_maybe_pointer(ptr, self)
}

Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,8 +869,6 @@ where
Ok(src_val) => {
assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
// Yay, we got a value that we can write directly.
// FIXME: Add a check to make sure that if `src` is indirect,
// it does not overlap with `dest`.
return self.write_immediate_no_validate(*src_val, dest);
}
Err(mplace) => mplace,
Expand All @@ -890,7 +888,7 @@ where
});
assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");

self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true)
self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ false)
}

/// Copies the data from an operand to a place. The layouts may disagree, but they must
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
place: mir::Place<'tcx>,
) -> InterpResult<'tcx> {
let dest = self.eval_place(place)?;
// FIXME: ensure some kind of non-aliasing between LHS and RHS?
// Also see https://github.com/rust-lang/rust/issues/68364.

use rustc_middle::mir::Rvalue::*;
match *rvalue {
Expand Down
18 changes: 8 additions & 10 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,32 +519,30 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}

Rvalue::Cast(
CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
_,
_,
) => {}

Rvalue::Cast(
CastKind::Pointer(
PointerCast::UnsafeFnPointer
PointerCast::MutToConstPointer
| PointerCast::ArrayToPointer
| PointerCast::UnsafeFnPointer
| PointerCast::ClosureFnPointer(_)
| PointerCast::ReifyFnPointer,
),
_,
_,
) => {
// Nothing to do here. Function pointer casts are allowed now.
// These are all okay; they only change the type, not the data.
}

Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
// Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
// in the type of any local, which also excludes casts).
// Unsizing is implemented for CTFE.
}

Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
self.check_op(ops::RawPtrToIntCast);
}
Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
// Since no pointer can ever get exposed (rejected above), this is easy to support.
}

Rvalue::Cast(CastKind::Misc, _, _) => {}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@ impl<'tcx> Validator<'_, 'tcx> {
// ptr-to-int casts are not possible in consts and thus not promotable
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),

// int-to-ptr casts are fine, they just use the integer value at pointer type.
// all other casts including int-to-ptr casts are fine, they just use the integer value
// at pointer type.
Rvalue::Cast(_, operand, _) => {
self.validate_operand(operand)?;
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2613,12 +2613,18 @@ impl<'tcx> Rvalue<'tcx> {

#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum CastKind {
Misc,
/// An exposing pointer to address cast. A cast between a pointer and an integer type, or
/// between a function pointer and an integer type.
/// See the docs on `expose_addr` for more details.
PointerExposeAddress,
/// An address-to-pointer cast that picks up an exposed provenance.
/// See the docs on `from_exposed_addr` for more details.
PointerFromExposedAddress,
/// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
/// translated into `&raw mut/const *r`, i.e., they are not actually casts.
Pointer(PointerCast),
/// Remaining unclassified casts.
Misc,
}

#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/ty/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,10 @@ pub fn suggest_constraining_type_params<'a>(
continue;
}

let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + ");
let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
constraint.sort();
constraint.dedup();
let constraint = constraint.join(" + ");
let mut suggest_restrict = |span, bound_list_non_empty| {
suggestions.push((
span,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
CastKind::PointerExposeAddress
}
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
CastKind::PointerFromExposedAddress
}
(_, _) => CastKind::Misc,
};
let source = unpack!(
Expand Down
63 changes: 53 additions & 10 deletions compiler/rustc_typeck/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! up data structures required by type-checking/codegen.
use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
use rustc_errors::struct_span_err;
use rustc_errors::{struct_span_err, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
Expand All @@ -11,12 +11,12 @@ use rustc_infer::infer;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeFoldable};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
use rustc_trait_selection::traits::predicate_for_trait_def;
use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
use std::collections::BTreeMap;

pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
let lang_items = tcx.lang_items();
Expand Down Expand Up @@ -91,6 +91,20 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
E0204,
"the trait `Copy` may not be implemented for this type"
);

// We'll try to suggest constraining type parameters to fulfill the requirements of
// their `Copy` implementation.
let mut generics = None;
if let ty::Adt(def, _substs) = self_type.kind() {
let self_def_id = def.did();
if let Some(local) = self_def_id.as_local() {
let self_item = tcx.hir().expect_item(local);
generics = self_item.kind.generics();
}
}
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
let mut bounds = vec![];

for (field, ty) in fields {
let field_span = tcx.def_span(field.did);
err.span_label(field_span, "this field does not implement `Copy`");
Expand All @@ -115,17 +129,46 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
// FIXME: This error could be more descriptive, especially if the error_predicate
// contains a foreign type or if it's a deeply nested type...
if error_predicate != error.root_obligation.predicate {
err.span_note(
error.obligation.cause.span,
&format!(
"the `Copy` impl for `{}` requires that `{}`",
ty, error_predicate
),
);
errors
.entry((ty.to_string(), error_predicate.to_string()))
.or_default()
.push(error.obligation.cause.span);
}
if let ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
polarity: ty::ImplPolarity::Positive,
..
}) = error_predicate.kind().skip_binder()
{
let ty = trait_ref.self_ty();
if let ty::Param(_) = ty.kind() {
bounds.push((
format!("{ty}"),
trait_ref.print_only_trait_path().to_string(),
Some(trait_ref.def_id),
));
}
}
}
});
}
for ((ty, error_predicate), spans) in errors {
let span: MultiSpan = spans.into();
err.span_note(
span,
&format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
);
}
if let Some(generics) = generics {
suggest_constraining_type_params(
tcx,
generics,
&mut err,
bounds.iter().map(|(param, constraint, def_id)| {
(param.as_str(), constraint.as_str(), *def_id)
}),
);
}
err.emit();
}
Err(CopyImplementationError::NotAnAdt) => {
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ where

/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
#[rustc_const_stable(feature = "const_array_from_ref_shared", since = "1.63.0")]
pub const fn from_ref<T>(s: &T) -> &[T; 1] {
// SAFETY: Converting `&T` to `&[T; 1]` is sound.
unsafe { &*(s as *const T).cast::<[T; 1]>() }
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/slice/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")]
#[must_use]
pub const fn from_ref<T>(s: &T) -> &[T] {
array::from_ref(s)
Expand Down
2 changes: 2 additions & 0 deletions src/etc/htmldocck.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text):
else:
actual_str = flatten(actual_tree)

expected_str = expected_str.replace("{{channel}}", channel)

# Conditions:
# 1. Is --bless
# 2. Are actual and expected tree different
Expand Down
Loading

0 comments on commit 72f7e31

Please sign in to comment.