mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 17:03:35 +00:00
Auto merge of #127486 - matthiaskrgr:rollup-lvv018b, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #120248 (Make casts of pointers to trait objects stricter) - #127355 (Mark format! with must_use hint) - #127399 (Verify that allocations output by GVN are sufficiently aligned.) - #127460 (clarify `sys::unix::fd::FileDesc::drop` comment) - #127467 (bootstrap: once_cell::sync::Lazy -> std::sync::LazyLock) Failed merges: - #127357 (Remove `StructuredDiag`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a06e9c83f6
@ -38,6 +38,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
|
||||
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
@ -49,6 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
||||
use crate::renumber::RegionCtxt;
|
||||
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
|
||||
use crate::{
|
||||
borrow_set::BorrowSet,
|
||||
@ -2333,7 +2335,57 @@ impl<'a, 'tcx> TypeChecker<'a, '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) {
|
||||
(Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (),
|
||||
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
|
||||
let mut normalize = |t| self.normalize(t, location);
|
||||
let src_tail =
|
||||
tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
|
||||
let dst_tail =
|
||||
tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
|
||||
|
||||
// This checks (lifetime part of) vtable validity for pointer casts,
|
||||
// which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
|
||||
//
|
||||
// Note that other checks (such as denying `dyn Send` -> `dyn Debug`) are in `rustc_hir_typeck`.
|
||||
if let ty::Dynamic(src_tty, ..) = src_tail.kind()
|
||||
&& let ty::Dynamic(dst_tty, ..) = dst_tail.kind()
|
||||
&& src_tty.principal().is_some()
|
||||
&& dst_tty.principal().is_some()
|
||||
{
|
||||
// Remove auto traits.
|
||||
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
|
||||
let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
|
||||
tcx.mk_poly_existential_predicates(
|
||||
&src_tty.without_auto_traits().collect::<Vec<_>>(),
|
||||
),
|
||||
tcx.lifetimes.re_static,
|
||||
ty::Dyn,
|
||||
));
|
||||
let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
|
||||
tcx.mk_poly_existential_predicates(
|
||||
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
|
||||
),
|
||||
tcx.lifetimes.re_static,
|
||||
ty::Dyn,
|
||||
));
|
||||
|
||||
// Replace trait object lifetimes with fresh vars, to allow casts like
|
||||
// `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
|
||||
let src_obj =
|
||||
freshen_single_trait_object_lifetime(self.infcx, src_obj);
|
||||
let dst_obj =
|
||||
freshen_single_trait_object_lifetime(self.infcx, dst_obj);
|
||||
|
||||
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
|
||||
|
||||
self.eq_types(
|
||||
src_obj,
|
||||
dst_obj,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_mirbug!(
|
||||
self,
|
||||
@ -2856,3 +2908,16 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
fn freshen_single_trait_object_lifetime<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") };
|
||||
|
||||
let fresh = infcx
|
||||
.next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || {
|
||||
RegionCtxt::Unknown
|
||||
});
|
||||
infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind))
|
||||
}
|
||||
|
@ -298,15 +298,21 @@ impl IntoDiagArg for hir::def::Namespace {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DiagSymbolList(Vec<Symbol>);
|
||||
pub struct DiagSymbolList<S = Symbol>(Vec<S>);
|
||||
|
||||
impl From<Vec<Symbol>> for DiagSymbolList {
|
||||
fn from(v: Vec<Symbol>) -> Self {
|
||||
impl<S> From<Vec<S>> for DiagSymbolList<S> {
|
||||
fn from(v: Vec<S>) -> Self {
|
||||
DiagSymbolList(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for DiagSymbolList {
|
||||
impl<S> FromIterator<S> for DiagSymbolList<S> {
|
||||
fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
|
||||
iter.into_iter().collect::<Vec<_>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: std::fmt::Display> IntoDiagArg for DiagSymbolList<S> {
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
DiagArgValue::StrListSepByAnd(
|
||||
self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(),
|
||||
|
@ -138,6 +138,11 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
|
||||
hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
|
||||
hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
|
||||
|
||||
hir_typeck_ptr_cast_add_auto_to_object = adding {$traits_len ->
|
||||
[1] an auto trait {$traits}
|
||||
*[other] auto traits {$traits}
|
||||
} to a trait object in a pointer cast may cause UB later on
|
||||
|
||||
hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
|
||||
hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
|
||||
hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this return type
|
||||
|
@ -32,9 +32,9 @@ use super::FnCtxt;
|
||||
|
||||
use crate::errors;
|
||||
use crate::type_error_struct;
|
||||
use hir::ExprKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{self as hir, ExprKind};
|
||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::Mutability;
|
||||
@ -44,7 +44,7 @@ use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::DUMMY_SP;
|
||||
@ -73,7 +73,7 @@ enum PointerKind<'tcx> {
|
||||
/// No metadata attached, ie pointer to sized type or foreign type
|
||||
Thin,
|
||||
/// A trait object
|
||||
VTable(Option<DefId>),
|
||||
VTable(&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>),
|
||||
/// Slice
|
||||
Length,
|
||||
/// The unsize info of this projection or opaque type
|
||||
@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
Ok(match *t.kind() {
|
||||
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
|
||||
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
|
||||
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
|
||||
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
|
||||
None => Some(PointerKind::Thin),
|
||||
Some(f) => {
|
||||
@ -755,7 +755,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
Err(CastError::IllegalCast)
|
||||
}
|
||||
|
||||
// ptr -> *
|
||||
// ptr -> ptr
|
||||
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
||||
|
||||
// ptr-addr-cast
|
||||
@ -799,40 +799,126 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
fn check_ptr_ptr_cast(
|
||||
&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: ty::TypeAndMut<'tcx>,
|
||||
m_cast: ty::TypeAndMut<'tcx>,
|
||||
m_src: ty::TypeAndMut<'tcx>,
|
||||
m_dst: ty::TypeAndMut<'tcx>,
|
||||
) -> Result<CastKind, CastError> {
|
||||
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
|
||||
debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}");
|
||||
// ptr-ptr cast. vtables must match.
|
||||
|
||||
let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
|
||||
let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
|
||||
let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?);
|
||||
let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
|
||||
|
||||
let Some(cast_kind) = cast_kind else {
|
||||
match (src_kind, dst_kind) {
|
||||
// We can't cast if target pointer kind is unknown
|
||||
return Err(CastError::UnknownCastPtrKind);
|
||||
};
|
||||
(_, None) => Err(CastError::UnknownCastPtrKind),
|
||||
// Cast to thin pointer is OK
|
||||
(_, Some(PointerKind::Thin)) => Ok(CastKind::PtrPtrCast),
|
||||
|
||||
// Cast to thin pointer is OK
|
||||
if cast_kind == PointerKind::Thin {
|
||||
return Ok(CastKind::PtrPtrCast);
|
||||
}
|
||||
|
||||
let Some(expr_kind) = expr_kind else {
|
||||
// We can't cast to fat pointer if source pointer kind is unknown
|
||||
return Err(CastError::UnknownExprPtrKind);
|
||||
};
|
||||
(None, _) => Err(CastError::UnknownExprPtrKind),
|
||||
|
||||
// thin -> fat? report invalid cast (don't complain about vtable kinds)
|
||||
if expr_kind == PointerKind::Thin {
|
||||
return Err(CastError::SizedUnsizedCast);
|
||||
}
|
||||
// thin -> fat? report invalid cast (don't complain about vtable kinds)
|
||||
(Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast),
|
||||
|
||||
// vtable kinds must match
|
||||
if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
|
||||
Ok(CastKind::PtrPtrCast)
|
||||
} else {
|
||||
Err(CastError::DifferingKinds)
|
||||
// trait object -> trait object? need to do additional checks
|
||||
(Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
|
||||
match (src_tty.principal(), dst_tty.principal()) {
|
||||
// A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
|
||||
// - `Src` and `Dst` traits are the same
|
||||
// - traits have the same generic arguments
|
||||
// - `SrcAuto` is a superset of `DstAuto`
|
||||
(Some(src_principal), Some(dst_principal)) => {
|
||||
let tcx = fcx.tcx;
|
||||
|
||||
// Check that the traits are actually the same.
|
||||
// The `dyn Src = dyn Dst` check below would suffice,
|
||||
// but this may produce a better diagnostic.
|
||||
//
|
||||
// Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
|
||||
// and is unaffected by this check.
|
||||
if src_principal.def_id() != dst_principal.def_id() {
|
||||
return Err(CastError::DifferingKinds);
|
||||
}
|
||||
|
||||
// We need to reconstruct trait object types.
|
||||
// `m_src` and `m_dst` won't work for us here because they will potentially
|
||||
// contain wrappers, which we do not care about.
|
||||
//
|
||||
// e.g. we want to allow `dyn T -> (dyn T,)`, etc.
|
||||
//
|
||||
// We also need to skip auto traits to emit an FCW and not an error.
|
||||
let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
|
||||
tcx.mk_poly_existential_predicates(
|
||||
&src_tty.without_auto_traits().collect::<Vec<_>>(),
|
||||
),
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::Dyn,
|
||||
));
|
||||
let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
|
||||
tcx.mk_poly_existential_predicates(
|
||||
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
|
||||
),
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::Dyn,
|
||||
));
|
||||
|
||||
// `dyn Src = dyn Dst`, this checks for matching traits/generics
|
||||
fcx.demand_eqtype(self.span, src_obj, dst_obj);
|
||||
|
||||
// Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`.
|
||||
// Emit an FCW otherwise.
|
||||
let src_auto: FxHashSet<_> = src_tty
|
||||
.auto_traits()
|
||||
.chain(
|
||||
tcx.supertrait_def_ids(src_principal.def_id())
|
||||
.filter(|def_id| tcx.trait_is_auto(*def_id)),
|
||||
)
|
||||
.collect();
|
||||
|
||||
let added = dst_tty
|
||||
.auto_traits()
|
||||
.filter(|trait_did| !src_auto.contains(trait_did))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !added.is_empty() {
|
||||
tcx.emit_node_span_lint(
|
||||
lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT,
|
||||
self.expr.hir_id,
|
||||
self.span,
|
||||
errors::PtrCastAddAutoToObject {
|
||||
traits_len: added.len(),
|
||||
traits: {
|
||||
let mut traits: Vec<_> = added
|
||||
.into_iter()
|
||||
.map(|trait_did| tcx.def_path_str(trait_did))
|
||||
.collect();
|
||||
|
||||
traits.sort();
|
||||
traits.into()
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Ok(CastKind::PtrPtrCast)
|
||||
}
|
||||
|
||||
// dyn Auto -> dyn Auto'? ok.
|
||||
(None, None) => Ok(CastKind::PtrPtrCast),
|
||||
|
||||
// dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
|
||||
// FIXME: allow this
|
||||
(Some(_), None) => Err(CastError::DifferingKinds),
|
||||
|
||||
// dyn Auto -> dyn Trait? not ok.
|
||||
(None, Some(_)) => Err(CastError::DifferingKinds),
|
||||
}
|
||||
}
|
||||
|
||||
// fat -> fat? metadata kinds must match
|
||||
(Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast),
|
||||
|
||||
(_, _) => Err(CastError::DifferingKinds),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@ use std::borrow::Cow;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, Diag, DiagArgValue, EmissionGuarantee, IntoDiagArg, MultiSpan,
|
||||
SubdiagMessageOp, Subdiagnostic,
|
||||
codes::*, Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
@ -253,6 +253,13 @@ pub struct LossyProvenanceInt2Ptr<'tcx> {
|
||||
pub sugg: LossyProvenanceInt2PtrSuggestion,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_typeck_ptr_cast_add_auto_to_object)]
|
||||
pub struct PtrCastAddAutoToObject {
|
||||
pub traits_len: usize,
|
||||
pub traits: DiagSymbolList<String>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
|
||||
pub struct LossyProvenanceInt2PtrSuggestion {
|
||||
|
@ -80,6 +80,7 @@ declare_lint_pass! {
|
||||
PRIVATE_BOUNDS,
|
||||
PRIVATE_INTERFACES,
|
||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||
PTR_CAST_ADD_AUTO_TO_OBJECT,
|
||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
REDUNDANT_LIFETIMES,
|
||||
REFINING_IMPL_TRAIT_INTERNAL,
|
||||
@ -4938,6 +4939,58 @@ declare_lint! {
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `ptr_cast_add_auto_to_object` lint detects casts of raw pointers to trait
|
||||
/// objects, which add auto traits.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2021,compile_fail
|
||||
/// let ptr: *const dyn core::any::Any = &();
|
||||
/// _ = ptr as *const dyn core::any::Any + Send;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Adding an auto trait can make the vtable invalid, potentially causing
|
||||
/// UB in safe code afterwards. For example:
|
||||
///
|
||||
/// ```ignore (causes a warning)
|
||||
/// #![feature(arbitrary_self_types)]
|
||||
///
|
||||
/// trait Trait {
|
||||
/// fn f(self: *const Self)
|
||||
/// where
|
||||
/// Self: Send;
|
||||
/// }
|
||||
///
|
||||
/// impl Trait for *const () {
|
||||
/// fn f(self: *const Self) {
|
||||
/// unreachable!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let unsend: *const () = &();
|
||||
/// let unsend: *const dyn Trait = &unsend;
|
||||
/// let send_bad: *const (dyn Trait + Send) = unsend as _;
|
||||
/// send_bad.f(); // this crashes, since vtable for `*const ()` does not have an entry for `f`
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Generally you must ensure that vtable is right for the pointer's type,
|
||||
/// before passing the pointer to safe code.
|
||||
pub PTR_CAST_ADD_AUTO_TO_OBJECT,
|
||||
Warn,
|
||||
"detects `as` casts from pointers to `dyn Trait` to pointers to `dyn Trait + Auto`",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||
reference: "issue #127323 <https://github.com/rust-lang/rust/issues/127323>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope,
|
||||
/// above their definition, which may happen in key-value attributes.
|
||||
|
@ -349,6 +349,14 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn without_auto_traits(
|
||||
&self,
|
||||
) -> impl Iterator<Item = ty::PolyExistentialPredicate<'tcx>> + '_ {
|
||||
self.iter().filter(|predicate| {
|
||||
!matches!(predicate.as_ref().skip_binder(), ExistentialPredicate::AutoTrait(_))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>;
|
||||
|
@ -1391,11 +1391,15 @@ fn op_to_prop_const<'tcx>(
|
||||
let (prov, offset) = pointer.into_parts();
|
||||
let alloc_id = prov.alloc_id();
|
||||
intern_const_alloc_for_constprop(ecx, alloc_id).ok()?;
|
||||
if matches!(ecx.tcx.global_alloc(alloc_id), GlobalAlloc::Memory(_)) {
|
||||
// `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
|
||||
// by `GlobalAlloc::Memory`, so do fall through to copying if needed.
|
||||
// FIXME: find a way to treat this more uniformly
|
||||
// (probably by fixing codegen)
|
||||
|
||||
// `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
|
||||
// by `GlobalAlloc::Memory`, so do fall through to copying if needed.
|
||||
// FIXME: find a way to treat this more uniformly (probably by fixing codegen)
|
||||
if let GlobalAlloc::Memory(alloc) = ecx.tcx.global_alloc(alloc_id)
|
||||
// Transmuting a constant is just an offset in the allocation. If the alignment of the
|
||||
// allocation is not enough, fallback to copying into a properly aligned value.
|
||||
&& alloc.inner().align >= op.layout.align.abi
|
||||
{
|
||||
return Some(ConstValue::Indirect { alloc_id, offset });
|
||||
}
|
||||
}
|
||||
|
@ -2374,7 +2374,7 @@ impl dyn Error + Send {
|
||||
let err: Box<dyn Error> = self;
|
||||
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
||||
// Reapply the `Send` marker.
|
||||
Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
|
||||
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -2387,8 +2387,8 @@ impl dyn Error + Send + Sync {
|
||||
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
|
||||
let err: Box<dyn Error> = self;
|
||||
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
||||
// Reapply the `Send + Sync` marker.
|
||||
Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
|
||||
// Reapply the `Send + Sync` markers.
|
||||
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1796,18 +1796,18 @@ fn test_ord_absence() {
|
||||
}
|
||||
|
||||
fn map_debug<K: Debug>(mut map: BTreeMap<K, ()>) {
|
||||
format!("{map:?}");
|
||||
format!("{:?}", map.iter());
|
||||
format!("{:?}", map.iter_mut());
|
||||
format!("{:?}", map.keys());
|
||||
format!("{:?}", map.values());
|
||||
format!("{:?}", map.values_mut());
|
||||
let _ = format!("{map:?}");
|
||||
let _ = format!("{:?}", map.iter());
|
||||
let _ = format!("{:?}", map.iter_mut());
|
||||
let _ = format!("{:?}", map.keys());
|
||||
let _ = format!("{:?}", map.values());
|
||||
let _ = format!("{:?}", map.values_mut());
|
||||
if true {
|
||||
format!("{:?}", map.into_iter());
|
||||
let _ = format!("{:?}", map.into_iter());
|
||||
} else if true {
|
||||
format!("{:?}", map.into_keys());
|
||||
let _ = format!("{:?}", map.into_keys());
|
||||
} else {
|
||||
format!("{:?}", map.into_values());
|
||||
let _ = format!("{:?}", map.into_values());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -705,9 +705,9 @@ fn test_ord_absence() {
|
||||
}
|
||||
|
||||
fn set_debug<K: Debug>(set: BTreeSet<K>) {
|
||||
format!("{set:?}");
|
||||
format!("{:?}", set.iter());
|
||||
format!("{:?}", set.into_iter());
|
||||
let _ = format!("{set:?}");
|
||||
let _ = format!("{:?}", set.iter());
|
||||
let _ = format!("{:?}", set.into_iter());
|
||||
}
|
||||
|
||||
fn set_clone<K: Clone>(mut set: BTreeSet<K>) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
//! Some examples of the [`format!`] extension are:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! format!("Hello"); // => "Hello"
|
||||
//! format!("Hello, {}!", "world"); // => "Hello, world!"
|
||||
//! format!("The number is {}", 1); // => "The number is 1"
|
||||
@ -50,6 +51,7 @@
|
||||
//! the iterator advances. This leads to behavior like this:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! format!("{1} {} {0} {}", 1, 2); // => "2 1 1 2"
|
||||
//! ```
|
||||
//!
|
||||
@ -77,6 +79,7 @@
|
||||
//! For example, the following [`format!`] expressions all use named arguments:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! format!("{argument}", argument = "test"); // => "test"
|
||||
//! format!("{name} {}", 1, name = 2); // => "2 1"
|
||||
//! format!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b"
|
||||
@ -86,6 +89,7 @@
|
||||
//! reference a variable with that name in the current scope.
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! let argument = 2 + 2;
|
||||
//! format!("{argument}"); // => "4"
|
||||
//!
|
||||
|
@ -257,6 +257,7 @@ pub mod vec;
|
||||
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
|
||||
pub mod __export {
|
||||
pub use core::format_args;
|
||||
pub use core::hint::must_use;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -111,6 +111,7 @@ macro_rules! vec {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(unused_must_use)]
|
||||
/// format!("test"); // => "test"
|
||||
/// format!("hello {}", "world!"); // => "hello world!"
|
||||
/// format!("x = {}, y = {val}", 10, val = 30); // => "x = 10, y = 30"
|
||||
@ -119,10 +120,13 @@ macro_rules! vec {
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow_internal_unstable(hint_must_use, liballoc_internals)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")]
|
||||
macro_rules! format {
|
||||
($($arg:tt)*) => {{
|
||||
let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
|
||||
res
|
||||
}}
|
||||
($($arg:tt)*) => {
|
||||
$crate::__export::must_use({
|
||||
let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
|
||||
res
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -217,19 +217,19 @@ fn test_format_macro_interface() {
|
||||
|
||||
// make sure that format! doesn't move out of local variables
|
||||
let a = Box::new(3);
|
||||
format!("{a}");
|
||||
format!("{a}");
|
||||
let _ = format!("{a}");
|
||||
let _ = format!("{a}");
|
||||
|
||||
// make sure that format! doesn't cause spurious unused-unsafe warnings when
|
||||
// it's inside of an outer unsafe block
|
||||
unsafe {
|
||||
let a: isize = ::std::mem::transmute(3_usize);
|
||||
format!("{a}");
|
||||
let _ = format!("{a}");
|
||||
}
|
||||
|
||||
// test that trailing commas are acceptable
|
||||
format!("{}", "test",);
|
||||
format!("{foo}", foo = "test",);
|
||||
let _ = format!("{}", "test",);
|
||||
let _ = format!("{foo}", foo = "test",);
|
||||
}
|
||||
|
||||
// Basic test to make sure that we can invoke the `write!` macro with an
|
||||
|
@ -441,7 +441,7 @@ mod debug_map {
|
||||
}
|
||||
}
|
||||
|
||||
format!("{Foo:?}");
|
||||
let _ = format!("{Foo:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -455,7 +455,7 @@ mod debug_map {
|
||||
}
|
||||
}
|
||||
|
||||
format!("{Foo:?}");
|
||||
let _ = format!("{Foo:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -469,7 +469,7 @@ mod debug_map {
|
||||
}
|
||||
}
|
||||
|
||||
format!("{Foo:?}");
|
||||
let _ = format!("{Foo:?}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +175,11 @@ impl Drop for OwnedFd {
|
||||
// the file descriptor was closed or not, and if we retried (for
|
||||
// something like EINTR), we might close another valid file descriptor
|
||||
// opened after we closed ours.
|
||||
// However, this is usually justified, as some of the major Unices
|
||||
// do make sure to always close the FD, even when `close()` is interrupted,
|
||||
// and the scenario is rare to begin with.
|
||||
// Helpful link to an epic discussion by POSIX workgroup:
|
||||
// http://austingroupbugs.net/view.php?id=529
|
||||
#[cfg(not(target_os = "hermit"))]
|
||||
{
|
||||
#[cfg(unix)]
|
||||
|
@ -54,7 +54,6 @@ dependencies = [
|
||||
"junction",
|
||||
"libc",
|
||||
"object",
|
||||
"once_cell",
|
||||
"opener",
|
||||
"pretty_assertions",
|
||||
"semver",
|
||||
|
@ -49,7 +49,6 @@ home = "0.5"
|
||||
ignore = "0.4"
|
||||
libc = "0.2"
|
||||
object = { version = "0.32", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
|
||||
once_cell = "1.19"
|
||||
opener = "0.5"
|
||||
semver = "1.0"
|
||||
serde = "1.0"
|
||||
|
@ -753,7 +753,7 @@ fn configure_cmake(
|
||||
}
|
||||
|
||||
if builder.config.llvm_clang_cl.is_some() {
|
||||
cflags.push(&format!(" --target={target}"));
|
||||
cflags.push(format!(" --target={target}"));
|
||||
}
|
||||
cfg.define("CMAKE_C_FLAGS", cflags);
|
||||
let mut cxxflags: OsString = builder
|
||||
@ -772,7 +772,7 @@ fn configure_cmake(
|
||||
cxxflags.push(s);
|
||||
}
|
||||
if builder.config.llvm_clang_cl.is_some() {
|
||||
cxxflags.push(&format!(" --target={target}"));
|
||||
cxxflags.push(format!(" --target={target}"));
|
||||
}
|
||||
cfg.define("CMAKE_CXX_FLAGS", cxxflags);
|
||||
if let Some(ar) = builder.ar(target) {
|
||||
@ -913,7 +913,7 @@ impl Step for Lld {
|
||||
// Find clang's runtime library directory and push that as a search path to the
|
||||
// cmake linker flags.
|
||||
let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
|
||||
ldflags.push_all(&format!("/libpath:{}", clang_rt_dir.display()));
|
||||
ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ use std::fs;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::LazyLock;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::core::build_steps::tool::{self, SourceType};
|
||||
@ -27,8 +28,6 @@ use crate::utils::exec::{command, BootstrapCommand};
|
||||
pub use crate::Compiler;
|
||||
|
||||
use clap::ValueEnum;
|
||||
// FIXME: replace with std::lazy after it gets stabilized and reaches beta
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@ -498,7 +497,7 @@ impl StepDescription {
|
||||
|
||||
enum ReallyDefault<'a> {
|
||||
Bool(bool),
|
||||
Lazy(Lazy<bool, Box<dyn Fn() -> bool + 'a>>),
|
||||
Lazy(LazyLock<bool, Box<dyn Fn() -> bool + 'a>>),
|
||||
}
|
||||
|
||||
pub struct ShouldRun<'a> {
|
||||
@ -529,7 +528,7 @@ impl<'a> ShouldRun<'a> {
|
||||
}
|
||||
|
||||
pub fn lazy_default_condition(mut self, lazy_cond: Box<dyn Fn() -> bool + 'a>) -> Self {
|
||||
self.is_really_default = ReallyDefault::Lazy(Lazy::new(lazy_cond));
|
||||
self.is_really_default = ReallyDefault::Lazy(LazyLock::new(lazy_cond));
|
||||
self
|
||||
}
|
||||
|
||||
@ -2526,7 +2525,7 @@ impl Cargo {
|
||||
|
||||
if let Some(target_linker) = builder.linker(target) {
|
||||
let target = crate::envify(&target.triple);
|
||||
self.command.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
|
||||
self.command.env(format!("CARGO_TARGET_{target}_LINKER"), target_linker);
|
||||
}
|
||||
// We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
|
||||
// `linker_args` here.
|
||||
|
@ -9,10 +9,7 @@ use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
// FIXME: replace with std::lazy after it gets stabilized and reaches beta
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::{LazyLock, Mutex};
|
||||
|
||||
use crate::core::builder::Step;
|
||||
|
||||
@ -196,7 +193,7 @@ impl Interner {
|
||||
}
|
||||
}
|
||||
|
||||
pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
|
||||
pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
|
||||
|
||||
/// This is essentially a `HashMap` which allows storing any type in its input and
|
||||
/// any type in its output. It is a write-once cache; values are never evicted,
|
||||
|
@ -98,7 +98,7 @@ fn or_fun_call() {
|
||||
|
||||
let opt = Some(1);
|
||||
let hello = "Hello";
|
||||
let _ = opt.ok_or(format!("{} world.", hello));
|
||||
let _ = opt.ok_or_else(|| format!("{} world.", hello));
|
||||
|
||||
// index
|
||||
let map = HashMap::<u64, u64>::new();
|
||||
|
@ -100,6 +100,12 @@ error: use of `unwrap_or` to construct default value
|
||||
LL | let _ = stringy.unwrap_or(String::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
|
||||
|
||||
error: use of `ok_or` followed by a function call
|
||||
--> tests/ui/or_fun_call.rs:101:17
|
||||
|
|
||||
LL | let _ = opt.ok_or(format!("{} world.", hello));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> tests/ui/or_fun_call.rs:105:21
|
||||
|
|
||||
@ -190,5 +196,5 @@ error: use of `unwrap_or_else` to construct default value
|
||||
LL | let _ = stringy.unwrap_or_else(String::new);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
|
||||
|
||||
error: aborting due to 31 previous errors
|
||||
error: aborting due to 32 previous errors
|
||||
|
||||
|
@ -35,7 +35,7 @@ fn cast_dangling() {
|
||||
fn format() {
|
||||
// Pointer string formatting! We can't check the output as it changes when libstd changes,
|
||||
// but we can make sure Miri does not error.
|
||||
format!("{:?}", &mut 13 as *mut _);
|
||||
let _ = format!("{:?}", &mut 13 as *mut _);
|
||||
}
|
||||
|
||||
fn transmute() {
|
||||
@ -52,7 +52,7 @@ fn ptr_bitops1() {
|
||||
let one = bytes.as_ptr().wrapping_offset(1);
|
||||
let three = bytes.as_ptr().wrapping_offset(3);
|
||||
let res = (one as usize) | (three as usize);
|
||||
format!("{}", res);
|
||||
let _ = format!("{}", res);
|
||||
}
|
||||
|
||||
fn ptr_bitops2() {
|
||||
|
@ -138,7 +138,7 @@ fn test_derive() {
|
||||
assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y));
|
||||
x.hash(&mut DefaultHasher::new());
|
||||
P::default();
|
||||
format!("{:?}", x);
|
||||
let _ = format!("{:?}", x);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -202,7 +202,7 @@ fn test_errors() {
|
||||
// Opening a non-existing file should fail with a "not found" error.
|
||||
assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
|
||||
// Make sure we can also format this.
|
||||
format!("{0}: {0:?}", File::open(&path).unwrap_err());
|
||||
let _ = format!("{0}: {0:?}", File::open(&path).unwrap_err());
|
||||
// Removing a non-existing file should fail with a "not found" error.
|
||||
assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
|
||||
// Reading the metadata of a non-existing file should fail with a "not found" error.
|
||||
@ -301,5 +301,5 @@ fn test_from_raw_os_error() {
|
||||
let error = Error::from_raw_os_error(code);
|
||||
assert!(matches!(error.kind(), ErrorKind::Uncategorized));
|
||||
// Make sure we can also format this.
|
||||
format!("{error:?}");
|
||||
let _ = format!("{error:?}");
|
||||
}
|
||||
|
@ -15,5 +15,5 @@ fn main() {
|
||||
panic!("unsupported OS")
|
||||
};
|
||||
let err = io::Error::from_raw_os_error(raw_os_error);
|
||||
format!("{err}: {err:?}");
|
||||
let _ = format!("{err}: {err:?}");
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ fn main() {
|
||||
}
|
||||
|
||||
// Regression test for Debug impl's
|
||||
format!("{:?} {:?}", dst, dst.iter());
|
||||
format!("{:?}", VecDeque::<u32>::new().iter());
|
||||
let _ = format!("{:?} {:?}", dst, dst.iter());
|
||||
let _ = format!("{:?}", VecDeque::<u32>::new().iter());
|
||||
|
||||
for a in dst {
|
||||
assert_eq!(*a, 2);
|
||||
|
@ -68,8 +68,6 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId
|
||||
/// The type parameter `A` allows you to use a different value type; normally you will want
|
||||
/// it to be `core::any::Any` (also known as `std::any::Any`), but there are other choices:
|
||||
///
|
||||
/// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`; with
|
||||
/// that, you can only add types that implement `Clone` to the map.
|
||||
/// - You can add on `+ Send` or `+ Send + Sync` (e.g. `Map<dyn Any + Send>`) to add those
|
||||
/// auto traits.
|
||||
///
|
||||
@ -79,9 +77,6 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId
|
||||
/// also spelled [`AnyMap`] for convenience.
|
||||
/// - <code>[Map]<dyn [core::any::Any] + Send></code>
|
||||
/// - <code>[Map]<dyn [core::any::Any] + Send + Sync></code>
|
||||
/// - <code>[Map]<dyn [CloneAny]></code>
|
||||
/// - <code>[Map]<dyn [CloneAny] + Send></code>
|
||||
/// - <code>[Map]<dyn [CloneAny] + Send + Sync></code>
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
@ -205,12 +200,6 @@ mod tests {
|
||||
assert_debug::<Map<dyn Any>>();
|
||||
assert_debug::<Map<dyn Any + Send>>();
|
||||
assert_debug::<Map<dyn Any + Send + Sync>>();
|
||||
assert_send::<Map<dyn CloneAny + Send>>();
|
||||
assert_send::<Map<dyn CloneAny + Send + Sync>>();
|
||||
assert_sync::<Map<dyn CloneAny + Send + Sync>>();
|
||||
assert_debug::<Map<dyn CloneAny>>();
|
||||
assert_debug::<Map<dyn CloneAny + Send>>();
|
||||
assert_debug::<Map<dyn CloneAny + Send + Sync>>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -232,53 +221,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// impl some traits for dyn Any
|
||||
use core::fmt;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait CloneToAny {
|
||||
/// Clone `self` into a new `Box<dyn CloneAny>` object.
|
||||
fn clone_to_any(&self) -> Box<dyn CloneAny>;
|
||||
}
|
||||
|
||||
impl<T: Any + Clone> CloneToAny for T {
|
||||
#[inline]
|
||||
fn clone_to_any(&self) -> Box<dyn CloneAny> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_clone {
|
||||
($t:ty) => {
|
||||
impl Clone for Box<$t> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<$t> {
|
||||
// SAFETY: this dance is to reapply any Send/Sync marker. I’m not happy about this
|
||||
// approach, given that I used to do it in safe code, but then came a dodgy
|
||||
// future-compatibility warning where_clauses_object_safety, which is spurious for
|
||||
// auto traits but still super annoying (future-compatibility lints seem to mean
|
||||
// your bin crate needs a corresponding allow!). Although I explained my plight¹
|
||||
// and it was all explained and agreed upon, no action has been taken. So I finally
|
||||
// caved and worked around it by doing it this way, which matches what’s done for
|
||||
// core::any², so it’s probably not *too* bad.
|
||||
//
|
||||
// ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013
|
||||
// ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616
|
||||
let clone: Box<dyn CloneAny> = (**self).clone_to_any();
|
||||
let raw: *mut dyn CloneAny = Box::into_raw(clone);
|
||||
unsafe { Box::from_raw(raw as *mut $t) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $t {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad(stringify!($t))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Methods for downcasting from an `Any`-like trait object.
|
||||
///
|
||||
/// This should only be implemented on trait objects for subtraits of `Any`, though you can
|
||||
@ -350,16 +292,3 @@ macro_rules! implement {
|
||||
implement!(Any);
|
||||
implement!(Any + Send);
|
||||
implement!(Any + Send + Sync);
|
||||
|
||||
/// [`Any`], but with cloning.
|
||||
///
|
||||
/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`.
|
||||
/// See [`core::any`] for more details on `Any` in general.
|
||||
pub trait CloneAny: Any + CloneToAny {}
|
||||
impl<T: Any + Clone> CloneAny for T {}
|
||||
implement!(CloneAny);
|
||||
implement!(CloneAny + Send);
|
||||
implement!(CloneAny + Send + Sync);
|
||||
impl_clone!(dyn CloneAny);
|
||||
impl_clone!(dyn CloneAny + Send);
|
||||
impl_clone!(dyn CloneAny + Send + Sync);
|
||||
|
@ -29,16 +29,17 @@ fn bar() ({
|
||||
|
||||
|
||||
|
||||
({
|
||||
let res =
|
||||
((::alloc::fmt::format as
|
||||
for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
|
||||
as
|
||||
fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test"
|
||||
as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
|
||||
as String);
|
||||
(res as String)
|
||||
} as String);
|
||||
((::alloc::__export::must_use as
|
||||
fn(String) -> String {must_use::<String>})(({
|
||||
let res =
|
||||
((::alloc::fmt::format as
|
||||
for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
|
||||
as
|
||||
fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test"
|
||||
as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
|
||||
as String);
|
||||
(res as String)
|
||||
} as String)) as String);
|
||||
} as ())
|
||||
type Foo = [i32; (3 as usize)];
|
||||
struct Bar {
|
||||
|
@ -4,25 +4,12 @@
|
||||
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
|
||||
trait Foo<T> {
|
||||
fn foo(&self, _: T) -> u32 { 42 }
|
||||
}
|
||||
|
||||
trait Bar { //~ WARN trait `Bar` is never used
|
||||
fn bar(&self) { println!("Bar!"); }
|
||||
}
|
||||
|
||||
impl<T> Foo<T> for () {}
|
||||
impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
|
||||
impl Bar for () {}
|
||||
|
||||
unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32>+'a)) -> u32 {
|
||||
let foo_e : *const dyn Foo<u32> = t as *const _;
|
||||
let r_1 = foo_e as *mut dyn Foo<u32>;
|
||||
|
||||
(&*r_1).foo(0)
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct FooS<T:?Sized>(T);
|
||||
#[repr(C)]
|
||||
@ -38,11 +25,6 @@ fn tuple_i32_to_u32<T:?Sized>(u: *const (i32, T)) -> *const (u32, T) {
|
||||
|
||||
|
||||
fn main() {
|
||||
let x = 4u32;
|
||||
let y : &dyn Foo<u32> = &x;
|
||||
let fl = unsafe { round_trip_and_call(y as *const dyn Foo<u32>) };
|
||||
assert_eq!(fl, (43+4));
|
||||
|
||||
let s = FooS([0,1,2]);
|
||||
let u: &FooS<[u32]> = &s;
|
||||
let u: *const FooS<[u32]> = u;
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: trait `Bar` is never used
|
||||
--> $DIR/cast-rfc0401-vtable-kinds.rs:11:7
|
||||
--> $DIR/cast-rfc0401-vtable-kinds.rs:7:7
|
||||
|
|
||||
LL | trait Bar {
|
||||
| ^^^
|
||||
|
18
tests/ui/cast/ptr-to-trait-obj-add-auto.rs
Normal file
18
tests/ui/cast/ptr-to-trait-obj-add-auto.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ check-pass
|
||||
|
||||
trait Trait<'a> {}
|
||||
|
||||
fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
|
||||
x as _
|
||||
//~^ warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
|
||||
//~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
}
|
||||
|
||||
// (to test diagnostic list formatting)
|
||||
fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) {
|
||||
x as _
|
||||
//~^ warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
|
||||
//~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
}
|
||||
|
||||
fn main() {}
|
43
tests/ui/cast/ptr-to-trait-obj-add-auto.stderr
Normal file
43
tests/ui/cast/ptr-to-trait-obj-add-auto.stderr
Normal file
@ -0,0 +1,43 @@
|
||||
warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
|
||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
|
||||
|
|
||||
LL | x as _
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
||||
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
|
||||
|
||||
warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
|
||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
|
||||
|
|
||||
LL | x as _
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
|
||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
|
||||
|
|
||||
LL | x as _
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
||||
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
|
||||
|
||||
Future breakage diagnostic:
|
||||
warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
|
||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
|
||||
|
|
||||
LL | x as _
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
||||
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
|
||||
|
9
tests/ui/cast/ptr-to-trait-obj-add-super-auto.rs
Normal file
9
tests/ui/cast/ptr-to-trait-obj-add-super-auto.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ check-pass
|
||||
|
||||
trait Trait: Send {}
|
||||
impl Trait for () {}
|
||||
|
||||
fn main() {
|
||||
// This is OK: `Trait` has `Send` super trait.
|
||||
&() as *const dyn Trait as *const (dyn Trait + Send);
|
||||
}
|
37
tests/ui/cast/ptr-to-trait-obj-different-args.rs
Normal file
37
tests/ui/cast/ptr-to-trait-obj-different-args.rs
Normal file
@ -0,0 +1,37 @@
|
||||
//@ check-fail
|
||||
//
|
||||
// issue: <https://github.com/rust-lang/rust/issues/120222>
|
||||
|
||||
trait A {}
|
||||
impl<T> A for T {}
|
||||
trait B {}
|
||||
impl<T> B for T {}
|
||||
|
||||
trait Trait<G> {}
|
||||
struct X;
|
||||
impl<T> Trait<X> for T {}
|
||||
struct Y;
|
||||
impl<T> Trait<Y> for T {}
|
||||
|
||||
fn main() {
|
||||
let a: *const dyn A = &();
|
||||
let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
|
||||
|
||||
let x: *const dyn Trait<X> = &();
|
||||
let y: *const dyn Trait<Y> = x as _; //~ error: mismatched types
|
||||
|
||||
_ = (b, y);
|
||||
}
|
||||
|
||||
fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
|
||||
let _: *const dyn Trait<T> = x as _; //~ error: mismatched types
|
||||
let _: *const dyn Trait<X> = t as _; //~ error: mismatched types
|
||||
}
|
||||
|
||||
trait Assocked {
|
||||
type Assoc: ?Sized;
|
||||
}
|
||||
|
||||
fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
|
||||
x as _ //~ error: mismatched types
|
||||
}
|
53
tests/ui/cast/ptr-to-trait-obj-different-args.stderr
Normal file
53
tests/ui/cast/ptr-to-trait-obj-different-args.stderr
Normal file
@ -0,0 +1,53 @@
|
||||
error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid
|
||||
--> $DIR/ptr-to-trait-obj-different-args.rs:18:27
|
||||
|
|
||||
LL | let b: *const dyn B = a as _;
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: vtable kinds may not match
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ptr-to-trait-obj-different-args.rs:21:34
|
||||
|
|
||||
LL | let y: *const dyn Trait<Y> = x as _;
|
||||
| ^^^^^^ expected `X`, found `Y`
|
||||
|
|
||||
= note: expected trait object `dyn Trait<X>`
|
||||
found trait object `dyn Trait<Y>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ptr-to-trait-obj-different-args.rs:27:34
|
||||
|
|
||||
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
|
||||
| - found this type parameter
|
||||
LL | let _: *const dyn Trait<T> = x as _;
|
||||
| ^^^^^^ expected `X`, found type parameter `T`
|
||||
|
|
||||
= note: expected trait object `dyn Trait<X>`
|
||||
found trait object `dyn Trait<T>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ptr-to-trait-obj-different-args.rs:28:34
|
||||
|
|
||||
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
|
||||
| - expected this type parameter
|
||||
LL | let _: *const dyn Trait<T> = x as _;
|
||||
LL | let _: *const dyn Trait<X> = t as _;
|
||||
| ^^^^^^ expected type parameter `T`, found `X`
|
||||
|
|
||||
= note: expected trait object `dyn Trait<T>`
|
||||
found trait object `dyn Trait<X>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ptr-to-trait-obj-different-args.rs:36:5
|
||||
|
|
||||
LL | x as _
|
||||
| ^^^^^^ expected `u8`, found `u32`
|
||||
|
|
||||
= note: expected trait object `dyn Assocked<Assoc = u8>`
|
||||
found trait object `dyn Assocked<Assoc = u32>`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0606.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
27
tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
Normal file
27
tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
Normal file
@ -0,0 +1,27 @@
|
||||
//@ check-fail
|
||||
//
|
||||
// Make sure we can't trick the compiler by using a projection.
|
||||
|
||||
trait Cat<'a> {}
|
||||
impl Cat<'_> for () {}
|
||||
|
||||
trait Id {
|
||||
type Id: ?Sized;
|
||||
}
|
||||
impl<T: ?Sized> Id for T {
|
||||
type Id = T;
|
||||
}
|
||||
|
||||
struct S<T: ?Sized> {
|
||||
tail: <T as Id>::Id,
|
||||
}
|
||||
|
||||
fn m<'a>() {
|
||||
let unsend: *const dyn Cat<'a> = &();
|
||||
let _send = unsend as *const S<dyn Cat<'static>>;
|
||||
//~^ error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17
|
||||
|
|
||||
LL | fn m<'a>() {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | let unsend: *const dyn Cat<'a> = &();
|
||||
LL | let _send = unsend as *const S<dyn Cat<'static>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
||||
|
|
||||
= note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
|
||||
= note: the struct `S<T>` is invariant over the parameter `T`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
31
tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
Normal file
31
tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
Normal file
@ -0,0 +1,31 @@
|
||||
//@ check-fail
|
||||
//
|
||||
// issue: <https://github.com/rust-lang/rust/issues/120217>
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
|
||||
trait Static<'a> {
|
||||
fn proof(self: *const Self, s: &'a str) -> &'static str;
|
||||
}
|
||||
|
||||
fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
|
||||
x as _ //~ error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
impl Static<'static> for () {
|
||||
fn proof(self: *const Self, s: &'static str) -> &'static str {
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_lifetime(s: &str) -> &'static str {
|
||||
bad_cast(&()).proof(s)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = String::from("Hello World");
|
||||
let slice = extend_lifetime(&s);
|
||||
println!("Now it exists: {slice}");
|
||||
drop(s);
|
||||
println!("Now it’s gone: {slice}");
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-lt-ext.rs:12:5
|
||||
|
|
||||
LL | fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | x as _
|
||||
| ^^^^^^ returning this value requires that `'a` must outlive `'static`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
37
tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
Normal file
37
tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
Normal file
@ -0,0 +1,37 @@
|
||||
//@ check-fail
|
||||
|
||||
trait Trait<'a> {}
|
||||
|
||||
fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
x as _ //~ error: lifetime may not live long enough
|
||||
//~| error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
x as _ //~ error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
x as _ //~ error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
trait Assocked {
|
||||
type Assoc: ?Sized;
|
||||
}
|
||||
|
||||
fn change_assoc_0<'a, 'b>(
|
||||
x: *mut dyn Assocked<Assoc = dyn Send + 'a>,
|
||||
) -> *mut dyn Assocked<Assoc = dyn Send + 'b> {
|
||||
x as _ //~ error: lifetime may not live long enough
|
||||
//~| error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn change_assoc_1<'a, 'b>(
|
||||
x: *mut dyn Assocked<Assoc = dyn Trait<'a>>,
|
||||
) -> *mut dyn Assocked<Assoc = dyn Trait<'b>> {
|
||||
x as _ //~ error: lifetime may not live long enough
|
||||
//~| error: lifetime may not live long enough
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
136
tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
Normal file
136
tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
Normal file
@ -0,0 +1,136 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
|
||||
|
|
||||
LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
|
||||
|
|
||||
LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
||||
|
|
||||
= help: consider adding the following bound: `'a: 'b`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
help: `'b` and `'a` must be the same: replace one with the other
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:11:5
|
||||
|
|
||||
LL | fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:15:5
|
||||
|
|
||||
LL | fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
||||
|
|
||||
= help: consider adding the following bound: `'a: 'b`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
|
||||
|
|
||||
LL | fn change_assoc_0<'a, 'b>(
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
|
||||
|
|
||||
LL | fn change_assoc_0<'a, 'b>(
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
||||
|
|
||||
= help: consider adding the following bound: `'a: 'b`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
help: `'b` and `'a` must be the same: replace one with the other
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
|
||||
|
|
||||
LL | fn change_assoc_1<'a, 'b>(
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
|
||||
|
|
||||
LL | fn change_assoc_1<'a, 'b>(
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | x as _
|
||||
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
||||
|
|
||||
= help: consider adding the following bound: `'a: 'b`
|
||||
= note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
|
||||
= note: mutable pointers are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
help: `'b` and `'a` must be the same: replace one with the other
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
17
tests/ui/cast/ptr-to-trait-obj-ok.rs
Normal file
17
tests/ui/cast/ptr-to-trait-obj-ok.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//@ check-pass
|
||||
|
||||
trait Trait<'a> {}
|
||||
|
||||
fn remove_auto<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut dyn Trait<'a> {
|
||||
x as _
|
||||
}
|
||||
|
||||
fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trait<'static> + 'b) {
|
||||
x as _
|
||||
}
|
||||
|
||||
fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
|
||||
x as _
|
||||
}
|
||||
|
||||
fn main() {}
|
14
tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs
Normal file
14
tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs
Normal file
@ -0,0 +1,14 @@
|
||||
trait Super {}
|
||||
trait Sub: Super {}
|
||||
|
||||
struct Wrapper<T: ?Sized>(T);
|
||||
|
||||
// This cast should not compile.
|
||||
// Upcasting can't work here, because we are also changing the type (`Wrapper`),
|
||||
// and reinterpreting would be confusing/surprising.
|
||||
// See <https://github.com/rust-lang/rust/pull/120248#discussion_r1487739518>
|
||||
fn cast(ptr: *const dyn Sub) -> *const Wrapper<dyn Super> {
|
||||
ptr as _ //~ error: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
|
||||
}
|
||||
|
||||
fn main() {}
|
11
tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
Normal file
11
tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
|
||||
--> $DIR/ptr-to-trait-obj-wrap-upcast.rs:11:5
|
||||
|
|
||||
LL | ptr as _
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: vtable kinds may not match
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0606`.
|
@ -9,5 +9,5 @@ pub fn main() {
|
||||
}
|
||||
|
||||
let f = Foo { foo: 10 };
|
||||
format!("{:?}", f);
|
||||
let _ = format!("{:?}", f);
|
||||
}
|
||||
|
@ -8,11 +8,11 @@ struct Foo {
|
||||
fn main() {
|
||||
let foo = Foo { field: 0 };
|
||||
let bar = 3;
|
||||
format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
}
|
||||
|
@ -8,11 +8,11 @@ struct Foo {
|
||||
fn main() {
|
||||
let foo = Foo { field: 0 };
|
||||
let bar = 3;
|
||||
format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
let _ = format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
|
||||
}
|
||||
|
@ -1,79 +1,79 @@
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:11:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:11:23
|
||||
|
|
||||
LL | format!("{foo.field}");
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field}");
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{0}", foo.field);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{0}", foo.field);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:12:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:12:23
|
||||
|
|
||||
LL | format!("{foo.field} {} {bar}", "aa");
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field} {} {bar}", "aa");
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{1} {} {bar}", "aa", foo.field);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{1} {} {bar}", "aa", foo.field);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:13:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:13:23
|
||||
|
|
||||
LL | format!("{foo.field} {} {1} {bar}", "aa", "bb");
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field} {} {1} {bar}", "aa", "bb");
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:14:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:14:23
|
||||
|
|
||||
LL | format!("{foo.field} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{1} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{1} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:15:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:15:23
|
||||
|
|
||||
LL | format!("{foo.field:?} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field:?} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:16:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:16:23
|
||||
|
|
||||
LL | format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: invalid format string: field access isn't supported
|
||||
--> $DIR/struct-field-as-captured-argument.rs:17:15
|
||||
--> $DIR/struct-field-as-captured-argument.rs:17:23
|
||||
|
|
||||
LL | format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
LL | let _ = format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
|
||||
| ^^^^^^^^^ not supported in format string
|
||||
|
|
||||
help: consider using a positional formatting argument instead
|
||||
|
|
||||
LL | format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
LL | let _ = format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
|
||||
| ~ +++++++++++
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -8,5 +8,5 @@ use std::fmt;
|
||||
|
||||
fn main() {
|
||||
let a: &dyn fmt::Debug = &1;
|
||||
format!("{:?}", a);
|
||||
let _ = format!("{:?}", a);
|
||||
}
|
||||
|
8
tests/ui/mir/alignment/misaligned-constant-gvn.rs
Normal file
8
tests/ui/mir/alignment/misaligned-constant-gvn.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//@ build-pass
|
||||
//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+GVN
|
||||
|
||||
fn main() {
|
||||
let variant: Option<u32> = None;
|
||||
let transmuted: u64 = unsafe { std::mem::transmute(variant) };
|
||||
println!("{transmuted}");
|
||||
}
|
@ -66,7 +66,7 @@ fn main()
|
||||
|
||||
let cf: *const dyn Foo = &0;
|
||||
let _ = cf as *const [u16]; //~ ERROR is invalid
|
||||
let _ = cf as *const dyn Bar; //~ ERROR is invalid
|
||||
let _ = cf as *const dyn Bar; //~ ERROR casting `*const dyn Foo` as `*const dyn Bar` is invalid
|
||||
|
||||
vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>(); //~ ERROR is invalid
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
trait Trait {}
|
||||
|
||||
fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) {
|
||||
fn assert_send() -> *mut (dyn Trait + Send) {
|
||||
//~^ ERROR incorrect parentheses around trait bounds
|
||||
ptr as _
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn foo2(_: &(dyn Trait + Send)) {}
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
trait Trait {}
|
||||
|
||||
fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
|
||||
fn assert_send() -> *mut dyn (Trait + Send) {
|
||||
//~^ ERROR incorrect parentheses around trait bounds
|
||||
ptr as _
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn foo2(_: &dyn (Trait + Send)) {}
|
||||
|
@ -1,13 +1,13 @@
|
||||
error: incorrect parentheses around trait bounds
|
||||
--> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:6:49
|
||||
--> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:6:30
|
||||
|
|
||||
LL | fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
|
||||
| ^ ^
|
||||
LL | fn assert_send() -> *mut dyn (Trait + Send) {
|
||||
| ^ ^
|
||||
|
|
||||
help: fix the parentheses
|
||||
|
|
||||
LL - fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
|
||||
LL + fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) {
|
||||
LL - fn assert_send() -> *mut dyn (Trait + Send) {
|
||||
LL + fn assert_send() -> *mut (dyn Trait + Send) {
|
||||
|
|
||||
|
||||
error: incorrect parentheses around trait bounds
|
||||
|
@ -1,7 +1,8 @@
|
||||
#![feature(trait_upcasting)]
|
||||
//@ known-bug: #120222
|
||||
//@ check-pass
|
||||
//! This will segfault at runtime.
|
||||
//@ check-fail
|
||||
//
|
||||
// issue: <https://github.com/rust-lang/rust/pull/120222>
|
||||
//! This would segfault at runtime.
|
||||
|
||||
pub trait SupSupA {
|
||||
fn method(&self) {}
|
||||
@ -56,6 +57,7 @@ pub fn user2() -> &'static dyn Trait<u8, u16> {
|
||||
fn main() {
|
||||
let p: *const dyn Trait<u8, u8> = &();
|
||||
let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
|
||||
//~^ error: mismatched types
|
||||
let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry
|
||||
// accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)',
|
||||
// thus reading 'null pointer for missing_method'
|
||||
|
13
tests/ui/traits/upcast_soundness_bug.stderr
Normal file
13
tests/ui/traits/upcast_soundness_bug.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/upcast_soundness_bug.rs:59:13
|
||||
|
|
||||
LL | let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
|
||||
|
|
||||
= note: expected trait object `dyn Trait<u8, u8>`
|
||||
found trait object `dyn Trait<u8, u16>`
|
||||
= help: `dyn Trait<u8, u16>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user