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 #97679

Merged
merged 13 commits into from
Jun 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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