Auto merge of #3435 - rust-lang:rustup-2024-03-31, r=saethlin
Automatic Rustup
This commit is contained in:
commit
d5de305fef
84 changed files with 1396 additions and 724 deletions
|
@ -14,7 +14,7 @@ index d0a119c..76fdece 100644
|
||||||
@@ -89,7 +89,6 @@
|
@@ -89,7 +89,6 @@
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(unwrap_infallible)]
|
#![feature(unwrap_infallible)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
-#![feature(portable_simd)]
|
-#![feature(portable_simd)]
|
||||||
#![feature(ptr_metadata)]
|
#![feature(ptr_metadata)]
|
||||||
#![feature(lazy_cell)]
|
#![feature(lazy_cell)]
|
||||||
|
@ -27,6 +27,6 @@ index d0a119c..76fdece 100644
|
||||||
mod slice;
|
mod slice;
|
||||||
mod str;
|
mod str;
|
||||||
mod str_lossy;
|
mod str_lossy;
|
||||||
--
|
--
|
||||||
2.42.1
|
2.42.1
|
||||||
|
|
||||||
|
|
|
@ -243,6 +243,7 @@ where
|
||||||
T: Tag,
|
T: Tag,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(ambiguous_wide_pointer_comparisons)]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.packed == other.packed
|
self.packed == other.packed
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,6 +295,8 @@ hir_analysis_not_supported_delegation =
|
||||||
{$descr} is not supported yet
|
{$descr} is not supported yet
|
||||||
.label = callee defined here
|
.label = callee defined here
|
||||||
|
|
||||||
|
hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate
|
||||||
|
|
||||||
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
|
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
|
||||||
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
|
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, AliasKind, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::{self, IsFirstInputType};
|
use rustc_trait_selection::traits::{self, IsFirstInputType};
|
||||||
|
@ -283,9 +283,14 @@ fn emit_orphan_check_error<'tcx>(
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
Err(match err {
|
Err(match err {
|
||||||
traits::OrphanCheckErr::NonLocalInputType(tys) => {
|
traits::OrphanCheckErr::NonLocalInputType(tys) => {
|
||||||
let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
|
let mut diag = tcx.dcx().create_err(match self_ty.kind() {
|
||||||
(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
|
ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () },
|
||||||
let mut sugg = None;
|
_ if self_ty.is_primitive() => {
|
||||||
|
errors::OnlyCurrentTraits::Primitive { span: sp, note: () }
|
||||||
|
}
|
||||||
|
_ => errors::OnlyCurrentTraits::Arbitrary { span: sp, note: () },
|
||||||
|
});
|
||||||
|
|
||||||
for &(mut ty, is_target_ty) in &tys {
|
for &(mut ty, is_target_ty) in &tys {
|
||||||
let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
|
let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
|
||||||
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
|
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
|
||||||
|
@ -296,113 +301,86 @@ fn emit_orphan_check_error<'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
ty = tcx.erase_regions(ty);
|
ty = tcx.erase_regions(ty);
|
||||||
ty = match ty.kind() {
|
|
||||||
// Remove the type arguments from the output, as they are not relevant.
|
|
||||||
// You can think of this as the reverse of `resolve_vars_if_possible`.
|
|
||||||
// That way if we had `Vec<MyType>`, we will properly attribute the
|
|
||||||
// problem to `Vec<T>` and avoid confusing the user if they were to see
|
|
||||||
// `MyType` in the error.
|
|
||||||
ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
|
|
||||||
_ => ty,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn push_to_foreign_or_name<'tcx>(
|
|
||||||
is_foreign: bool,
|
|
||||||
foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
|
|
||||||
name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
|
|
||||||
span: Span,
|
|
||||||
sname: &'tcx str,
|
|
||||||
) {
|
|
||||||
if is_foreign {
|
|
||||||
foreign.push(errors::OnlyCurrentTraitsForeign { span })
|
|
||||||
} else {
|
|
||||||
name.push(errors::OnlyCurrentTraitsName { span, name: sname });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_foreign =
|
let is_foreign =
|
||||||
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
|
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
|
||||||
|
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Slice(_) => {
|
ty::Slice(_) => {
|
||||||
push_to_foreign_or_name(
|
if is_foreign {
|
||||||
is_foreign,
|
diag.subdiagnostic(
|
||||||
&mut foreign,
|
tcx.dcx(),
|
||||||
&mut name,
|
errors::OnlyCurrentTraitsForeign { span },
|
||||||
span,
|
);
|
||||||
"slices",
|
} else {
|
||||||
);
|
diag.subdiagnostic(
|
||||||
|
tcx.dcx(),
|
||||||
|
errors::OnlyCurrentTraitsName { span, name: "slices" },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ty::Array(..) => {
|
ty::Array(..) => {
|
||||||
push_to_foreign_or_name(
|
if is_foreign {
|
||||||
is_foreign,
|
diag.subdiagnostic(
|
||||||
&mut foreign,
|
tcx.dcx(),
|
||||||
&mut name,
|
errors::OnlyCurrentTraitsForeign { span },
|
||||||
span,
|
);
|
||||||
"arrays",
|
} else {
|
||||||
);
|
diag.subdiagnostic(
|
||||||
|
tcx.dcx(),
|
||||||
|
errors::OnlyCurrentTraitsName { span, name: "arrays" },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ty::Tuple(..) => {
|
ty::Tuple(..) => {
|
||||||
push_to_foreign_or_name(
|
if is_foreign {
|
||||||
is_foreign,
|
diag.subdiagnostic(
|
||||||
&mut foreign,
|
tcx.dcx(),
|
||||||
&mut name,
|
errors::OnlyCurrentTraitsForeign { span },
|
||||||
span,
|
);
|
||||||
"tuples",
|
} else {
|
||||||
);
|
diag.subdiagnostic(
|
||||||
|
tcx.dcx(),
|
||||||
|
errors::OnlyCurrentTraitsName { span, name: "tuples" },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ty::Alias(ty::Opaque, ..) => {
|
ty::Alias(ty::Opaque, ..) => {
|
||||||
opaque.push(errors::OnlyCurrentTraitsOpaque { span })
|
diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
|
||||||
}
|
}
|
||||||
ty::RawPtr(ptr_ty, mutbl) => {
|
ty::RawPtr(ptr_ty, mutbl) => {
|
||||||
if !self_ty.has_param() {
|
if !self_ty.has_param() {
|
||||||
let mut_key = mutbl.prefix_str();
|
diag.subdiagnostic(
|
||||||
sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
|
tcx.dcx(),
|
||||||
wrapper_span: self_ty_span,
|
errors::OnlyCurrentTraitsPointerSugg {
|
||||||
struct_span: full_impl_span.shrink_to_lo(),
|
wrapper_span: self_ty_span,
|
||||||
mut_key,
|
struct_span: full_impl_span.shrink_to_lo(),
|
||||||
ptr_ty,
|
mut_key: mutbl.prefix_str(),
|
||||||
});
|
ptr_ty,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
|
diag.subdiagnostic(
|
||||||
|
tcx.dcx(),
|
||||||
|
errors::OnlyCurrentTraitsPointer { span, pointer: ty },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ty::Adt(adt_def, _) => {
|
||||||
|
diag.subdiagnostic(
|
||||||
|
tcx.dcx(),
|
||||||
|
errors::OnlyCurrentTraitsAdt {
|
||||||
|
span,
|
||||||
|
name: tcx.def_path_str(adt_def.did()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty });
|
||||||
}
|
}
|
||||||
_ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let err_struct = match self_ty.kind() {
|
diag.emit()
|
||||||
ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
|
|
||||||
span: sp,
|
|
||||||
note: (),
|
|
||||||
opaque,
|
|
||||||
foreign,
|
|
||||||
name,
|
|
||||||
pointer,
|
|
||||||
ty: ty_diag,
|
|
||||||
sugg,
|
|
||||||
},
|
|
||||||
_ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
|
|
||||||
span: sp,
|
|
||||||
note: (),
|
|
||||||
opaque,
|
|
||||||
foreign,
|
|
||||||
name,
|
|
||||||
pointer,
|
|
||||||
ty: ty_diag,
|
|
||||||
sugg,
|
|
||||||
},
|
|
||||||
_ => errors::OnlyCurrentTraits::Arbitrary {
|
|
||||||
span: sp,
|
|
||||||
note: (),
|
|
||||||
opaque,
|
|
||||||
foreign,
|
|
||||||
name,
|
|
||||||
pointer,
|
|
||||||
ty: ty_diag,
|
|
||||||
sugg,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
tcx.dcx().emit_err(err_struct)
|
|
||||||
}
|
}
|
||||||
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
|
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
|
||||||
let mut sp = sp;
|
let mut sp = sp;
|
||||||
|
|
|
@ -1376,7 +1376,7 @@ pub struct TyParamSome<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
pub enum OnlyCurrentTraits<'a> {
|
pub enum OnlyCurrentTraits {
|
||||||
#[diag(hir_analysis_only_current_traits_outside, code = E0117)]
|
#[diag(hir_analysis_only_current_traits_outside, code = E0117)]
|
||||||
Outside {
|
Outside {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
|
@ -1384,18 +1384,6 @@ pub enum OnlyCurrentTraits<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
#[note(hir_analysis_only_current_traits_note)]
|
#[note(hir_analysis_only_current_traits_note)]
|
||||||
note: (),
|
note: (),
|
||||||
#[subdiagnostic]
|
|
||||||
opaque: Vec<OnlyCurrentTraitsOpaque>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
foreign: Vec<OnlyCurrentTraitsForeign>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
name: Vec<OnlyCurrentTraitsName<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
ty: Vec<OnlyCurrentTraitsTy<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
|
|
||||||
},
|
},
|
||||||
#[diag(hir_analysis_only_current_traits_primitive, code = E0117)]
|
#[diag(hir_analysis_only_current_traits_primitive, code = E0117)]
|
||||||
Primitive {
|
Primitive {
|
||||||
|
@ -1404,18 +1392,6 @@ pub enum OnlyCurrentTraits<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
#[note(hir_analysis_only_current_traits_note)]
|
#[note(hir_analysis_only_current_traits_note)]
|
||||||
note: (),
|
note: (),
|
||||||
#[subdiagnostic]
|
|
||||||
opaque: Vec<OnlyCurrentTraitsOpaque>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
foreign: Vec<OnlyCurrentTraitsForeign>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
name: Vec<OnlyCurrentTraitsName<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
ty: Vec<OnlyCurrentTraitsTy<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
|
|
||||||
},
|
},
|
||||||
#[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)]
|
#[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)]
|
||||||
Arbitrary {
|
Arbitrary {
|
||||||
|
@ -1424,18 +1400,6 @@ pub enum OnlyCurrentTraits<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
#[note(hir_analysis_only_current_traits_note)]
|
#[note(hir_analysis_only_current_traits_note)]
|
||||||
note: (),
|
note: (),
|
||||||
#[subdiagnostic]
|
|
||||||
opaque: Vec<OnlyCurrentTraitsOpaque>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
foreign: Vec<OnlyCurrentTraitsForeign>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
name: Vec<OnlyCurrentTraitsName<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
ty: Vec<OnlyCurrentTraitsTy<'a>>,
|
|
||||||
#[subdiagnostic]
|
|
||||||
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1445,7 +1409,6 @@ pub struct OnlyCurrentTraitsOpaque {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[label(hir_analysis_only_current_traits_foreign)]
|
#[label(hir_analysis_only_current_traits_foreign)]
|
||||||
pub struct OnlyCurrentTraitsForeign {
|
pub struct OnlyCurrentTraitsForeign {
|
||||||
|
@ -1477,6 +1440,14 @@ pub struct OnlyCurrentTraitsTy<'a> {
|
||||||
pub ty: Ty<'a>,
|
pub ty: Ty<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[label(hir_analysis_only_current_traits_adt)]
|
||||||
|
pub struct OnlyCurrentTraitsAdt {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
hir_analysis_only_current_traits_pointer_sugg,
|
hir_analysis_only_current_traits_pointer_sugg,
|
||||||
|
|
|
@ -1916,18 +1916,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pat: &'tcx hir::Pat<'tcx>,
|
pat: &'tcx hir::Pat<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) {
|
) {
|
||||||
struct V<'tcx> {
|
struct V {
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
pat_hir_ids: Vec<hir::HirId>,
|
pat_hir_ids: Vec<hir::HirId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for V<'tcx> {
|
impl<'tcx> Visitor<'tcx> for V {
|
||||||
type NestedFilter = rustc_middle::hir::nested_filter::All;
|
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> Self::Map {
|
|
||||||
self.tcx.hir()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
||||||
self.pat_hir_ids.push(p.hir_id);
|
self.pat_hir_ids.push(p.hir_id);
|
||||||
hir::intravisit::walk_pat(self, p);
|
hir::intravisit::walk_pat(self, p);
|
||||||
|
@ -1938,7 +1931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let err = Ty::new_error(self.tcx, guar);
|
let err = Ty::new_error(self.tcx, guar);
|
||||||
self.write_ty(hir_id, err);
|
self.write_ty(hir_id, err);
|
||||||
self.write_ty(pat.hir_id, err);
|
self.write_ty(pat.hir_id, err);
|
||||||
let mut visitor = V { tcx: self.tcx, pat_hir_ids: vec![] };
|
let mut visitor = V { pat_hir_ids: vec![] };
|
||||||
hir::intravisit::walk_pat(&mut visitor, pat);
|
hir::intravisit::walk_pat(&mut visitor, pat);
|
||||||
// Mark all the subpatterns as `{type error}` as well. This allows errors for specific
|
// Mark all the subpatterns as `{type error}` as well. This allows errors for specific
|
||||||
// subpatterns to be silenced.
|
// subpatterns to be silenced.
|
||||||
|
|
|
@ -1632,11 +1632,13 @@ pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> {
|
||||||
pub ne: &'a str,
|
pub ne: &'a str,
|
||||||
pub deref_left: &'a str,
|
pub deref_left: &'a str,
|
||||||
pub deref_right: &'a str,
|
pub deref_right: &'a str,
|
||||||
|
pub l_modifiers: &'a str,
|
||||||
|
pub r_modifiers: &'a str,
|
||||||
#[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")]
|
#[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")]
|
||||||
pub left: Span,
|
pub left: Span,
|
||||||
#[suggestion_part(code = ", {deref_right}")]
|
#[suggestion_part(code = "{l_modifiers}, {deref_right}")]
|
||||||
pub middle: Span,
|
pub middle: Span,
|
||||||
#[suggestion_part(code = ")")]
|
#[suggestion_part(code = "{r_modifiers})")]
|
||||||
pub right: Span,
|
pub right: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1652,11 +1654,13 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
|
||||||
ne: &'a str,
|
ne: &'a str,
|
||||||
deref_left: &'a str,
|
deref_left: &'a str,
|
||||||
deref_right: &'a str,
|
deref_right: &'a str,
|
||||||
|
l_modifiers: &'a str,
|
||||||
|
r_modifiers: &'a str,
|
||||||
#[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
|
#[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
|
||||||
left: Span,
|
left: Span,
|
||||||
#[suggestion_part(code = ", {deref_right}")]
|
#[suggestion_part(code = "{l_modifiers}, {deref_right}")]
|
||||||
middle: Span,
|
middle: Span,
|
||||||
#[suggestion_part(code = ")")]
|
#[suggestion_part(code = "{r_modifiers})")]
|
||||||
right: Span,
|
right: Span,
|
||||||
},
|
},
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
|
@ -1670,13 +1674,15 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
|
||||||
deref_right: &'a str,
|
deref_right: &'a str,
|
||||||
paren_left: &'a str,
|
paren_left: &'a str,
|
||||||
paren_right: &'a str,
|
paren_right: &'a str,
|
||||||
|
l_modifiers: &'a str,
|
||||||
|
r_modifiers: &'a str,
|
||||||
#[suggestion_part(code = "({deref_left}")]
|
#[suggestion_part(code = "({deref_left}")]
|
||||||
left_before: Option<Span>,
|
left_before: Option<Span>,
|
||||||
#[suggestion_part(code = "{paren_left}.cast::<()>()")]
|
#[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")]
|
||||||
left_after: Span,
|
left_after: Span,
|
||||||
#[suggestion_part(code = "({deref_right}")]
|
#[suggestion_part(code = "({deref_right}")]
|
||||||
right_before: Option<Span>,
|
right_before: Option<Span>,
|
||||||
#[suggestion_part(code = "{paren_right}.cast::<()>()")]
|
#[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")]
|
||||||
right_after: Span,
|
right_after: Span,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -670,7 +670,11 @@ fn lint_wide_pointer<'tcx>(
|
||||||
l: &'tcx hir::Expr<'tcx>,
|
l: &'tcx hir::Expr<'tcx>,
|
||||||
r: &'tcx hir::Expr<'tcx>,
|
r: &'tcx hir::Expr<'tcx>,
|
||||||
) {
|
) {
|
||||||
let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(usize, bool)> {
|
let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(
|
||||||
|
/* number of refs */ usize,
|
||||||
|
/* modifiers */ String,
|
||||||
|
/* is dyn */ bool,
|
||||||
|
)> {
|
||||||
let mut refs = 0;
|
let mut refs = 0;
|
||||||
// here we remove any "implicit" references and count the number
|
// here we remove any "implicit" references and count the number
|
||||||
// of them to correctly suggest the right number of deref
|
// of them to correctly suggest the right number of deref
|
||||||
|
@ -678,11 +682,20 @@ fn lint_wide_pointer<'tcx>(
|
||||||
ty = *inner_ty;
|
ty = *inner_ty;
|
||||||
refs += 1;
|
refs += 1;
|
||||||
}
|
}
|
||||||
match ty.kind() {
|
|
||||||
ty::RawPtr(ty, _) => (!ty.is_sized(cx.tcx, cx.param_env))
|
// get the inner type of a pointer (or akin)
|
||||||
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
|
let mut modifiers = String::new();
|
||||||
_ => None,
|
ty = match ty.kind() {
|
||||||
}
|
ty::RawPtr(ty, _) => *ty,
|
||||||
|
ty::Adt(def, args) if cx.tcx.is_diagnostic_item(sym::NonNull, def.did()) => {
|
||||||
|
modifiers.push_str(".as_ptr()");
|
||||||
|
args.type_at(0)
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
(!ty.is_sized(cx.tcx, cx.param_env))
|
||||||
|
.then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn))))
|
||||||
};
|
};
|
||||||
|
|
||||||
// the left and right operands can have references, remove any explicit references
|
// the left and right operands can have references, remove any explicit references
|
||||||
|
@ -696,10 +709,10 @@ fn lint_wide_pointer<'tcx>(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((l_ty_refs, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else {
|
let Some((l_ty_refs, l_modifiers, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some((r_ty_refs, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else {
|
let Some((r_ty_refs, r_modifiers, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -724,6 +737,9 @@ fn lint_wide_pointer<'tcx>(
|
||||||
let deref_left = &*"*".repeat(l_ty_refs);
|
let deref_left = &*"*".repeat(l_ty_refs);
|
||||||
let deref_right = &*"*".repeat(r_ty_refs);
|
let deref_right = &*"*".repeat(r_ty_refs);
|
||||||
|
|
||||||
|
let l_modifiers = &*l_modifiers;
|
||||||
|
let r_modifiers = &*r_modifiers;
|
||||||
|
|
||||||
cx.emit_span_lint(
|
cx.emit_span_lint(
|
||||||
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
|
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
|
||||||
e.span,
|
e.span,
|
||||||
|
@ -733,6 +749,8 @@ fn lint_wide_pointer<'tcx>(
|
||||||
ne,
|
ne,
|
||||||
deref_left,
|
deref_left,
|
||||||
deref_right,
|
deref_right,
|
||||||
|
l_modifiers,
|
||||||
|
r_modifiers,
|
||||||
left,
|
left,
|
||||||
middle,
|
middle,
|
||||||
right,
|
right,
|
||||||
|
@ -743,6 +761,8 @@ fn lint_wide_pointer<'tcx>(
|
||||||
ne,
|
ne,
|
||||||
deref_left,
|
deref_left,
|
||||||
deref_right,
|
deref_right,
|
||||||
|
l_modifiers,
|
||||||
|
r_modifiers,
|
||||||
left,
|
left,
|
||||||
middle,
|
middle,
|
||||||
right,
|
right,
|
||||||
|
@ -751,6 +771,8 @@ fn lint_wide_pointer<'tcx>(
|
||||||
AmbiguousWidePointerComparisonsAddrSuggestion::Cast {
|
AmbiguousWidePointerComparisonsAddrSuggestion::Cast {
|
||||||
deref_left,
|
deref_left,
|
||||||
deref_right,
|
deref_right,
|
||||||
|
l_modifiers,
|
||||||
|
r_modifiers,
|
||||||
paren_left: if l_ty_refs != 0 { ")" } else { "" },
|
paren_left: if l_ty_refs != 0 { ")" } else { "" },
|
||||||
paren_right: if r_ty_refs != 0 { ")" } else { "" },
|
paren_right: if r_ty_refs != 0 { ")" } else { "" },
|
||||||
left_before: (l_ty_refs != 0).then_some(l_span.shrink_to_lo()),
|
left_before: (l_ty_refs != 0).then_some(l_span.shrink_to_lo()),
|
||||||
|
|
|
@ -140,6 +140,10 @@ impl<'tcx> rustc_type_ir::new::Region<TyCtxt<'tcx>> for Region<'tcx> {
|
||||||
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
||||||
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
|
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_static(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
tcx.lifetimes.re_static
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Region utilities
|
/// Region utilities
|
||||||
|
|
|
@ -1624,6 +1624,13 @@ impl<'tcx> Ty<'tcx> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
|
pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
|
||||||
|
debug_assert_eq!(
|
||||||
|
tcx.generics_of(def.did()).count(),
|
||||||
|
args.len(),
|
||||||
|
"wrong number of args for ADT: {:#?} vs {:#?}",
|
||||||
|
tcx.generics_of(def.did()).params,
|
||||||
|
args
|
||||||
|
);
|
||||||
Ty::new(tcx, Adt(def, args))
|
Ty::new(tcx, Adt(def, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -650,12 +650,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(#29623): return `Some(1)` when the values are different.
|
(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
|
||||||
(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val })
|
if test_val == case_val {
|
||||||
if test_val == case_val =>
|
fully_matched = true;
|
||||||
{
|
Some(TestBranch::Success)
|
||||||
fully_matched = true;
|
} else {
|
||||||
Some(TestBranch::Success)
|
fully_matched = false;
|
||||||
|
Some(TestBranch::Failure)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
|
@ -296,10 +296,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||||
Region::new_anon_bound(self.interner(), self.binder_index, var)
|
Region::new_anon_bound(self.interner(), self.binder_index, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
|
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
let kind = match t.kind() {
|
let kind = match t.kind() {
|
||||||
ty::Infer(i) => match i {
|
ty::Infer(i) => match i {
|
||||||
ty::TyVar(vid) => {
|
ty::TyVar(vid) => {
|
||||||
|
@ -378,47 +375,48 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||||
Ty::new_anon_bound(self.interner(), self.binder_index, var)
|
Ty::new_anon_bound(self.interner(), self.binder_index, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: I::Const) -> I::Const
|
fn fold_const(&mut self, c: I::Const) -> I::Const {
|
||||||
where
|
// We could canonicalize all consts with static types, but the only ones we
|
||||||
I::Const: TypeSuperFoldable<I>,
|
// *really* need to worry about are the ones that we end up putting into `CanonicalVarKind`
|
||||||
{
|
// since canonical vars can't reference other canonical vars.
|
||||||
|
let ty = c
|
||||||
|
.ty()
|
||||||
|
.fold_with(&mut RegionsToStatic { interner: self.interner(), binder: ty::INNERMOST });
|
||||||
let kind = match c.kind() {
|
let kind = match c.kind() {
|
||||||
ty::ConstKind::Infer(i) => {
|
ty::ConstKind::Infer(i) => match i {
|
||||||
// FIXME: we should fold the ty too eventually
|
ty::InferConst::Var(vid) => {
|
||||||
match i {
|
assert_eq!(
|
||||||
ty::InferConst::Var(vid) => {
|
self.infcx.root_ct_var(vid),
|
||||||
assert_eq!(
|
vid,
|
||||||
self.infcx.root_ct_var(vid),
|
"region vid should have been resolved fully before canonicalization"
|
||||||
vid,
|
);
|
||||||
"region vid should have been resolved fully before canonicalization"
|
assert_eq!(
|
||||||
);
|
self.infcx.probe_ct_var(vid),
|
||||||
assert_eq!(
|
None,
|
||||||
self.infcx.probe_ct_var(vid),
|
"region vid should have been resolved fully before canonicalization"
|
||||||
None,
|
);
|
||||||
"region vid should have been resolved fully before canonicalization"
|
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)
|
||||||
);
|
|
||||||
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty())
|
|
||||||
}
|
|
||||||
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
|
|
||||||
ty::InferConst::Fresh(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
|
||||||
|
ty::InferConst::Fresh(_) => todo!(),
|
||||||
|
},
|
||||||
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
|
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
|
||||||
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
||||||
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
|
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
|
||||||
c.ty(),
|
ty,
|
||||||
),
|
),
|
||||||
CanonicalizeMode::Response { .. } => {
|
CanonicalizeMode::Response { .. } => {
|
||||||
CanonicalVarKind::PlaceholderConst(placeholder, c.ty())
|
CanonicalVarKind::PlaceholderConst(placeholder, ty)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ty::ConstKind::Param(_) => match self.canonicalize_mode {
|
ty::ConstKind::Param(_) => match self.canonicalize_mode {
|
||||||
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
||||||
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||||
c.ty(),
|
ty,
|
||||||
),
|
),
|
||||||
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
|
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
|
||||||
},
|
},
|
||||||
|
// FIXME: See comment above -- we could fold the region separately or something.
|
||||||
ty::ConstKind::Bound(_, _)
|
ty::ConstKind::Bound(_, _)
|
||||||
| ty::ConstKind::Unevaluated(_)
|
| ty::ConstKind::Unevaluated(_)
|
||||||
| ty::ConstKind::Value(_)
|
| ty::ConstKind::Value(_)
|
||||||
|
@ -435,6 +433,35 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
Const::new_anon_bound(self.interner(), self.binder_index, var, c.ty())
|
Const::new_anon_bound(self.interner(), self.binder_index, var, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RegionsToStatic<I> {
|
||||||
|
interner: I,
|
||||||
|
binder: ty::DebruijnIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> {
|
||||||
|
fn interner(&self) -> I {
|
||||||
|
self.interner
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
|
||||||
|
where
|
||||||
|
T: TypeFoldable<I>,
|
||||||
|
I::Binder<T>: TypeSuperFoldable<I>,
|
||||||
|
{
|
||||||
|
self.binder.shift_in(1);
|
||||||
|
let t = t.fold_with(self);
|
||||||
|
self.binder.shift_out(1);
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||||
|
match r.kind() {
|
||||||
|
ty::ReBound(db, _) if self.binder > db => r,
|
||||||
|
_ => Region::new_static(self.interner()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@ session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Cli
|
||||||
|
|
||||||
session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
|
session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
|
||||||
|
|
||||||
|
session_sanitizer_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort`
|
||||||
|
|
||||||
session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
|
session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
|
||||||
|
|
||||||
session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
|
session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
|
||||||
|
|
|
@ -145,6 +145,10 @@ pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi;
|
||||||
#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
|
#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
|
||||||
pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi;
|
pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(session_sanitizer_kcfi_requires_panic_abort)]
|
||||||
|
pub(crate) struct SanitizerKcfiRequiresPanicAbort;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(session_split_lto_unit_requires_lto)]
|
#[diag(session_split_lto_unit_requires_lto)]
|
||||||
pub(crate) struct SplitLtoUnitRequiresLto;
|
pub(crate) struct SplitLtoUnitRequiresLto;
|
||||||
|
|
|
@ -1211,6 +1211,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||||
sess.dcx().emit_err(errors::SanitizerCfiRequiresLto);
|
sess.dcx().emit_err(errors::SanitizerCfiRequiresLto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KCFI requires panic=abort
|
||||||
|
if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort {
|
||||||
|
sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort);
|
||||||
|
}
|
||||||
|
|
||||||
// LLVM CFI using rustc LTO requires a single codegen unit.
|
// LLVM CFI using rustc LTO requires a single codegen unit.
|
||||||
if sess.is_sanitizer_cfi_enabled()
|
if sess.is_sanitizer_cfi_enabled()
|
||||||
&& sess.lto() == config::Lto::Fat
|
&& sess.lto() == config::Lto::Fat
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
use rustc_data_structures::base_n;
|
use rustc_data_structures::base_n;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_middle::ty::layout::IntegerExt;
|
use rustc_middle::ty::layout::IntegerExt;
|
||||||
use rustc_middle::ty::TypeVisitableExt;
|
use rustc_middle::ty::TypeVisitableExt;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
|
@ -641,9 +642,7 @@ fn encode_ty<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function types
|
// Function types
|
||||||
ty::FnDef(def_id, args)
|
ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
|
||||||
| ty::Closure(def_id, args)
|
|
||||||
| ty::CoroutineClosure(def_id, args) => {
|
|
||||||
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
|
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
|
||||||
// as vendor extended type.
|
// as vendor extended type.
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
@ -654,6 +653,18 @@ fn encode_ty<'tcx>(
|
||||||
typeid.push_str(&s);
|
typeid.push_str(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::CoroutineClosure(def_id, args) => {
|
||||||
|
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
|
||||||
|
// as vendor extended type.
|
||||||
|
let mut s = String::new();
|
||||||
|
let name = encode_ty_name(tcx, *def_id);
|
||||||
|
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||||
|
let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args());
|
||||||
|
s.push_str(&encode_args(tcx, parent_args, dict, options));
|
||||||
|
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||||
|
typeid.push_str(&s);
|
||||||
|
}
|
||||||
|
|
||||||
ty::Coroutine(def_id, args, ..) => {
|
ty::Coroutine(def_id, args, ..) => {
|
||||||
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
|
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
|
||||||
// as vendor extended type.
|
// as vendor extended type.
|
||||||
|
@ -1140,45 +1151,102 @@ pub fn typeid_for_instance<'tcx>(
|
||||||
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
|
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
|
||||||
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
|
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
|
||||||
instance.args = tcx.mk_args_trait(self_ty, List::empty());
|
instance.args = tcx.mk_args_trait(self_ty, List::empty());
|
||||||
} else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
|
} else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
|
||||||
instance.args = strip_receiver_auto(tcx, instance.args);
|
let upcast_ty = match tcx.trait_of_item(def_id) {
|
||||||
|
Some(trait_id) => trait_object_ty(
|
||||||
|
tcx,
|
||||||
|
ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
|
||||||
|
),
|
||||||
|
// drop_in_place won't have a defining trait, skip the upcast
|
||||||
|
None => instance.args.type_at(0),
|
||||||
|
};
|
||||||
|
let stripped_ty = strip_receiver_auto(tcx, upcast_ty);
|
||||||
|
instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1));
|
||||||
|
} else if let ty::InstanceDef::VTableShim(def_id) = instance.def
|
||||||
|
&& let Some(trait_id) = tcx.trait_of_item(def_id)
|
||||||
|
{
|
||||||
|
// VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable,
|
||||||
|
// as the caller will not know the concrete Self.
|
||||||
|
let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args);
|
||||||
|
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
|
||||||
|
instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE)
|
if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) {
|
||||||
&& let Some(impl_id) = tcx.impl_of_method(instance.def_id())
|
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
|
||||||
&& let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
|
&& let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
|
||||||
{
|
|
||||||
let impl_method = tcx.associated_item(instance.def_id());
|
|
||||||
let method_id = impl_method
|
|
||||||
.trait_item_def_id
|
|
||||||
.expect("Part of a trait implementation, but not linked to the def_id?");
|
|
||||||
let trait_method = tcx.associated_item(method_id);
|
|
||||||
let trait_id = trait_ref.skip_binder().def_id;
|
|
||||||
if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
|
|
||||||
&& tcx.object_safety_violations(trait_id).is_empty()
|
|
||||||
{
|
{
|
||||||
// Trait methods will have a Self polymorphic parameter, where the concreteized
|
let impl_method = tcx.associated_item(instance.def_id());
|
||||||
// implementatation will not. We need to walk back to the more general trait method
|
let method_id = impl_method
|
||||||
let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
|
.trait_item_def_id
|
||||||
instance.args,
|
.expect("Part of a trait implementation, but not linked to the def_id?");
|
||||||
ty::ParamEnv::reveal_all(),
|
let trait_method = tcx.associated_item(method_id);
|
||||||
trait_ref,
|
let trait_id = trait_ref.skip_binder().def_id;
|
||||||
);
|
if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
|
||||||
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
|
&& tcx.object_safety_violations(trait_id).is_empty()
|
||||||
|
{
|
||||||
|
// Trait methods will have a Self polymorphic parameter, where the concreteized
|
||||||
|
// implementatation will not. We need to walk back to the more general trait method
|
||||||
|
let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
|
||||||
|
instance.args,
|
||||||
|
ty::ParamEnv::reveal_all(),
|
||||||
|
trait_ref,
|
||||||
|
);
|
||||||
|
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
|
||||||
|
|
||||||
// At the call site, any call to this concrete function through a vtable will be
|
// At the call site, any call to this concrete function through a vtable will be
|
||||||
// `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
|
// `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
|
||||||
// original method id, and we've recovered the trait arguments, we can make the callee
|
// original method id, and we've recovered the trait arguments, we can make the callee
|
||||||
// instance we're computing the alias set for match the caller instance.
|
// instance we're computing the alias set for match the caller instance.
|
||||||
//
|
//
|
||||||
// Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
|
// Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
|
||||||
// If we ever *do* start encoding the vtable index, we will need to generate an alias set
|
// If we ever *do* start encoding the vtable index, we will need to generate an alias set
|
||||||
// based on which vtables we are putting this method into, as there will be more than one
|
// based on which vtables we are putting this method into, as there will be more than one
|
||||||
// index value when supertraits are involved.
|
// index value when supertraits are involved.
|
||||||
instance.def = ty::InstanceDef::Virtual(method_id, 0);
|
instance.def = ty::InstanceDef::Virtual(method_id, 0);
|
||||||
let abstract_trait_args =
|
let abstract_trait_args =
|
||||||
tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
|
tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
|
||||||
instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
|
instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
|
||||||
|
}
|
||||||
|
} else if tcx.is_closure_like(instance.def_id()) {
|
||||||
|
// We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
|
||||||
|
// instantiate it, and take the type of its only method as our own.
|
||||||
|
let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
|
||||||
|
let (trait_id, inputs) = match closure_ty.kind() {
|
||||||
|
ty::Closure(..) => {
|
||||||
|
let closure_args = instance.args.as_closure();
|
||||||
|
let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
|
||||||
|
let tuple_args =
|
||||||
|
tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
|
||||||
|
(trait_id, tuple_args)
|
||||||
|
}
|
||||||
|
ty::Coroutine(..) => (
|
||||||
|
tcx.require_lang_item(LangItem::Coroutine, None),
|
||||||
|
instance.args.as_coroutine().resume_ty(),
|
||||||
|
),
|
||||||
|
ty::CoroutineClosure(..) => (
|
||||||
|
tcx.require_lang_item(LangItem::FnOnce, None),
|
||||||
|
tcx.instantiate_bound_regions_with_erased(
|
||||||
|
instance.args.as_coroutine_closure().coroutine_closure_sig(),
|
||||||
|
)
|
||||||
|
.tupled_inputs_ty,
|
||||||
|
),
|
||||||
|
x => bug!("Unexpected type kind for closure-like: {x:?}"),
|
||||||
|
};
|
||||||
|
let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]);
|
||||||
|
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
|
||||||
|
let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
|
||||||
|
// There should be exactly one method on this trait, and it should be the one we're
|
||||||
|
// defining.
|
||||||
|
let call = tcx
|
||||||
|
.associated_items(trait_id)
|
||||||
|
.in_definition_order()
|
||||||
|
.find(|it| it.kind == ty::AssocKind::Fn)
|
||||||
|
.expect("No call-family function on closure-like Fn trait?")
|
||||||
|
.def_id;
|
||||||
|
|
||||||
|
instance.def = ty::InstanceDef::Virtual(call, 0);
|
||||||
|
instance.args = abstract_args;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1191,15 +1259,11 @@ pub fn typeid_for_instance<'tcx>(
|
||||||
typeid_for_fnabi(tcx, fn_abi, options)
|
typeid_for_fnabi(tcx, fn_abi, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strip_receiver_auto<'tcx>(
|
fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
args: ty::GenericArgsRef<'tcx>,
|
|
||||||
) -> ty::GenericArgsRef<'tcx> {
|
|
||||||
let ty = args.type_at(0);
|
|
||||||
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
|
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
|
||||||
bug!("Tried to strip auto traits from non-dynamic type {ty}");
|
bug!("Tried to strip auto traits from non-dynamic type {ty}");
|
||||||
};
|
};
|
||||||
let new_rcvr = if preds.principal().is_some() {
|
if preds.principal().is_some() {
|
||||||
let filtered_preds =
|
let filtered_preds =
|
||||||
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
|
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
|
||||||
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
|
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
|
||||||
|
@ -1210,8 +1274,7 @@ fn strip_receiver_auto<'tcx>(
|
||||||
// about it. This technically discards the knowledge that it was a type that was made
|
// about it. This technically discards the knowledge that it was a type that was made
|
||||||
// into a trait object at some point, but that's not a lot.
|
// into a trait object at some point, but that's not a lot.
|
||||||
tcx.types.unit
|
tcx.types.unit
|
||||||
};
|
}
|
||||||
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(tcx), ret)]
|
#[instrument(skip(tcx), ret)]
|
||||||
|
|
|
@ -136,31 +136,21 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
|
||||||
t.super_fold_with(self)
|
t.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
|
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
t.super_fold_with(self)
|
t.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default region folder is a no-op because `Region` is non-recursive
|
// The default region folder is a no-op because `Region` is non-recursive
|
||||||
// and has no `super_fold_with` method to call. That also explains the
|
// and has no `super_fold_with` method to call.
|
||||||
// lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
|
|
||||||
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: I::Const) -> I::Const
|
fn fold_const(&mut self, c: I::Const) -> I::Const {
|
||||||
where
|
|
||||||
I::Const: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
c.super_fold_with(self)
|
c.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate
|
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
|
||||||
where
|
|
||||||
I::Predicate: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
p.super_fold_with(self)
|
p.super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,31 +175,21 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
|
||||||
t.try_super_fold_with(self)
|
t.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error>
|
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
t.try_super_fold_with(self)
|
t.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default region folder is a no-op because `Region` is non-recursive
|
// The default region folder is a no-op because `Region` is non-recursive
|
||||||
// and has no `super_fold_with` method to call. That also explains the
|
// and has no `super_fold_with` method to call.
|
||||||
// lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
|
|
||||||
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
|
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
|
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> {
|
||||||
where
|
|
||||||
I::Const: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
c.try_super_fold_with(self)
|
c.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error>
|
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
|
||||||
where
|
|
||||||
I::Predicate: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
p.try_super_fold_with(self)
|
p.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,10 +214,7 @@ where
|
||||||
Ok(self.fold_binder(t))
|
Ok(self.fold_binder(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never>
|
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never> {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_ty(t))
|
Ok(self.fold_ty(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,17 +222,11 @@ where
|
||||||
Ok(self.fold_region(r))
|
Ok(self.fold_region(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never>
|
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never> {
|
||||||
where
|
|
||||||
I::Const: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_const(c))
|
Ok(self.fold_const(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never>
|
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never> {
|
||||||
where
|
|
||||||
I::Predicate: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_predicate(p))
|
Ok(self.fold_predicate(p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,14 @@ use smallvec::SmallVec;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::fold::TypeSuperFoldable;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{
|
use crate::{
|
||||||
new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
|
new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
|
||||||
UniverseIndex,
|
UniverseIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Interner: Sized {
|
pub trait Interner: Sized + Copy {
|
||||||
type DefId: Copy + Debug + Hash + Eq;
|
type DefId: Copy + Debug + Hash + Eq;
|
||||||
type AdtDef: Copy + Debug + Hash + Eq;
|
type AdtDef: Copy + Debug + Hash + Eq;
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ pub trait Interner: Sized {
|
||||||
+ Into<Self::GenericArg>
|
+ Into<Self::GenericArg>
|
||||||
+ IntoKind<Kind = TyKind<Self>>
|
+ IntoKind<Kind = TyKind<Self>>
|
||||||
+ TypeSuperVisitable<Self>
|
+ TypeSuperVisitable<Self>
|
||||||
|
+ TypeSuperFoldable<Self>
|
||||||
+ Flags
|
+ Flags
|
||||||
+ new::Ty<Self>;
|
+ new::Ty<Self>;
|
||||||
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
|
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
|
||||||
|
@ -57,6 +59,7 @@ pub trait Interner: Sized {
|
||||||
+ IntoKind<Kind = ConstKind<Self>>
|
+ IntoKind<Kind = ConstKind<Self>>
|
||||||
+ ConstTy<Self>
|
+ ConstTy<Self>
|
||||||
+ TypeSuperVisitable<Self>
|
+ TypeSuperVisitable<Self>
|
||||||
|
+ TypeSuperFoldable<Self>
|
||||||
+ Flags
|
+ Flags
|
||||||
+ new::Const<Self>;
|
+ new::Const<Self>;
|
||||||
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||||
|
@ -82,7 +85,13 @@ pub trait Interner: Sized {
|
||||||
type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
|
type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
|
||||||
|
|
||||||
// Predicates
|
// Predicates
|
||||||
type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
type Predicate: Copy
|
||||||
|
+ Debug
|
||||||
|
+ Hash
|
||||||
|
+ Eq
|
||||||
|
+ TypeSuperVisitable<Self>
|
||||||
|
+ TypeSuperFoldable<Self>
|
||||||
|
+ Flags;
|
||||||
type TraitPredicate: Copy + Debug + Hash + Eq;
|
type TraitPredicate: Copy + Debug + Hash + Eq;
|
||||||
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||||
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||||
|
|
|
@ -6,6 +6,8 @@ pub trait Ty<I: Interner<Ty = Self>> {
|
||||||
|
|
||||||
pub trait Region<I: Interner<Region = Self>> {
|
pub trait Region<I: Interner<Region = Self>> {
|
||||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
||||||
|
|
||||||
|
fn new_static(interner: I) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Const<I: Interner<Const = Self>> {
|
pub trait Const<I: Interner<Const = Self>> {
|
||||||
|
|
|
@ -198,7 +198,6 @@
|
||||||
#![feature(multiple_supertrait_upcastable)]
|
#![feature(multiple_supertrait_upcastable)]
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(pointer_is_aligned)]
|
|
||||||
#![feature(rustc_allow_const_fn_unstable)]
|
#![feature(rustc_allow_const_fn_unstable)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(slice_internals)]
|
#![feature(slice_internals)]
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_str_from_utf8)]
|
#![feature(const_str_from_utf8)]
|
||||||
#![feature(panic_update_hook)]
|
#![feature(panic_update_hook)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
#![feature(slice_flatten)]
|
#![feature(slice_flatten)]
|
||||||
#![feature(thin_box)]
|
#![feature(thin_box)]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
|
|
@ -40,10 +40,10 @@
|
||||||
//!
|
//!
|
||||||
//! ## Examples
|
//! ## Examples
|
||||||
//!
|
//!
|
||||||
//! Consider a situation where we want to log out a value passed to a function.
|
//! Consider a situation where we want to log a value passed to a function.
|
||||||
//! We know the value we're working on implements Debug, but we don't know its
|
//! We know the value we're working on implements `Debug`, but we don't know its
|
||||||
//! concrete type. We want to give special treatment to certain types: in this
|
//! concrete type. We want to give special treatment to certain types: in this
|
||||||
//! case printing out the length of String values prior to their value.
|
//! case printing out the length of `String` values prior to their value.
|
||||||
//! We don't know the concrete type of our value at compile time, so we need to
|
//! We don't know the concrete type of our value at compile time, so we need to
|
||||||
//! use runtime reflection instead.
|
//! use runtime reflection instead.
|
||||||
//!
|
//!
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
//! use std::fmt::Debug;
|
//! use std::fmt::Debug;
|
||||||
//! use std::any::Any;
|
//! use std::any::Any;
|
||||||
//!
|
//!
|
||||||
//! // Logger function for any type that implements Debug.
|
//! // Logger function for any type that implements `Debug`.
|
||||||
//! fn log<T: Any + Debug>(value: &T) {
|
//! fn log<T: Any + Debug>(value: &T) {
|
||||||
//! let value_any = value as &dyn Any;
|
//! let value_any = value as &dyn Any;
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -227,7 +227,7 @@ mod impls {
|
||||||
impl_clone! {
|
impl_clone! {
|
||||||
usize u8 u16 u32 u64 u128
|
usize u8 u16 u32 u64 u128
|
||||||
isize i8 i16 i32 i64 i128
|
isize i8 i16 i32 i64 i128
|
||||||
f32 f64
|
f16 f32 f64 f128
|
||||||
bool char
|
bool char
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1493,7 +1493,7 @@ mod impls {
|
||||||
}
|
}
|
||||||
|
|
||||||
partial_eq_impl! {
|
partial_eq_impl! {
|
||||||
bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64
|
bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! eq_impl {
|
macro_rules! eq_impl {
|
||||||
|
@ -1546,7 +1546,7 @@ mod impls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial_ord_impl! { f32 f64 }
|
partial_ord_impl! { f16 f32 f64 f128 }
|
||||||
|
|
||||||
macro_rules! ord_impl {
|
macro_rules! ord_impl {
|
||||||
($($t:ty)*) => ($(
|
($($t:ty)*) => ($(
|
||||||
|
|
|
@ -178,5 +178,9 @@ default_impl! { i32, 0, "Returns the default value of `0`" }
|
||||||
default_impl! { i64, 0, "Returns the default value of `0`" }
|
default_impl! { i64, 0, "Returns the default value of `0`" }
|
||||||
default_impl! { i128, 0, "Returns the default value of `0`" }
|
default_impl! { i128, 0, "Returns the default value of `0`" }
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
default_impl! { f16, 0.0f16, "Returns the default value of `0.0`" }
|
||||||
default_impl! { f32, 0.0f32, "Returns the default value of `0.0`" }
|
default_impl! { f32, 0.0f32, "Returns the default value of `0.0`" }
|
||||||
default_impl! { f64, 0.0f64, "Returns the default value of `0.0`" }
|
default_impl! { f64, 0.0f64, "Returns the default value of `0.0`" }
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
default_impl! { f128, 0.0f128, "Returns the default value of `0.0`" }
|
||||||
|
|
|
@ -137,6 +137,7 @@
|
||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
#![feature(const_hint_assert_unchecked)]
|
#![feature(const_hint_assert_unchecked)]
|
||||||
#![feature(const_index_range_slice_index)]
|
#![feature(const_index_range_slice_index)]
|
||||||
|
#![feature(const_int_from_str)]
|
||||||
#![feature(const_intrinsic_copy)]
|
#![feature(const_intrinsic_copy)]
|
||||||
#![feature(const_intrinsic_forget)]
|
#![feature(const_intrinsic_forget)]
|
||||||
#![feature(const_ipv4)]
|
#![feature(const_ipv4)]
|
||||||
|
@ -228,6 +229,8 @@
|
||||||
#![feature(doc_notable_trait)]
|
#![feature(doc_notable_trait)]
|
||||||
#![feature(effects)]
|
#![feature(effects)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
|
#![feature(f128)]
|
||||||
|
#![feature(f16)]
|
||||||
#![feature(freeze_impls)]
|
#![feature(freeze_impls)]
|
||||||
#![feature(fundamental)]
|
#![feature(fundamental)]
|
||||||
#![feature(generic_arg_infer)]
|
#![feature(generic_arg_infer)]
|
||||||
|
|
|
@ -422,7 +422,7 @@ marker_impls! {
|
||||||
Copy for
|
Copy for
|
||||||
usize, u8, u16, u32, u64, u128,
|
usize, u8, u16, u32, u64, u128,
|
||||||
isize, i8, i16, i32, i64, i128,
|
isize, i8, i16, i32, i64, i128,
|
||||||
f32, f64,
|
f16, f32, f64, f128,
|
||||||
bool, char,
|
bool, char,
|
||||||
{T: ?Sized} *const T,
|
{T: ?Sized} *const T,
|
||||||
{T: ?Sized} *mut T,
|
{T: ?Sized} *mut T,
|
||||||
|
|
|
@ -113,8 +113,9 @@ pub enum IntErrorKind {
|
||||||
impl ParseIntError {
|
impl ParseIntError {
|
||||||
/// Outputs the detailed cause of parsing an integer failing.
|
/// Outputs the detailed cause of parsing an integer failing.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
|
||||||
#[stable(feature = "int_error_matching", since = "1.55.0")]
|
#[stable(feature = "int_error_matching", since = "1.55.0")]
|
||||||
pub fn kind(&self) -> &IntErrorKind {
|
pub const fn kind(&self) -> &IntErrorKind {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,32 +60,6 @@ macro_rules! int_impl {
|
||||||
#[stable(feature = "int_bits_const", since = "1.53.0")]
|
#[stable(feature = "int_bits_const", since = "1.53.0")]
|
||||||
pub const BITS: u32 = <$UnsignedT>::BITS;
|
pub const BITS: u32 = <$UnsignedT>::BITS;
|
||||||
|
|
||||||
/// Converts a string slice in a given base to an integer.
|
|
||||||
///
|
|
||||||
/// The string is expected to be an optional `+` or `-` sign followed by digits.
|
|
||||||
/// Leading and trailing whitespace represent an error. Digits are a subset of these characters,
|
|
||||||
/// depending on `radix`:
|
|
||||||
///
|
|
||||||
/// * `0-9`
|
|
||||||
/// * `a-z`
|
|
||||||
/// * `A-Z`
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This function panics if `radix` is not in the range from 2 to 36.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Basic usage:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
|
|
||||||
from_str_radix(src, radix)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of ones in the binary representation of `self`.
|
/// Returns the number of ones in the binary representation of `self`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -6,7 +6,6 @@ use crate::ascii;
|
||||||
use crate::hint;
|
use crate::hint;
|
||||||
use crate::intrinsics;
|
use crate::intrinsics;
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::ops::{Add, Mul, Sub};
|
|
||||||
use crate::str::FromStr;
|
use crate::str::FromStr;
|
||||||
|
|
||||||
// Used because the `?` operator is not allowed in a const context.
|
// Used because the `?` operator is not allowed in a const context.
|
||||||
|
@ -1386,51 +1385,19 @@ pub enum FpCategory {
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
trait FromStrRadixHelper:
|
|
||||||
PartialOrd + Copy + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self>
|
|
||||||
{
|
|
||||||
const MIN: Self;
|
|
||||||
fn from_u32(u: u32) -> Self;
|
|
||||||
fn checked_mul(&self, other: u32) -> Option<Self>;
|
|
||||||
fn checked_sub(&self, other: u32) -> Option<Self>;
|
|
||||||
fn checked_add(&self, other: u32) -> Option<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! from_str_radix_int_impl {
|
macro_rules! from_str_radix_int_impl {
|
||||||
($($t:ty)*) => {$(
|
($($t:ty)*) => {$(
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl FromStr for $t {
|
impl FromStr for $t {
|
||||||
type Err = ParseIntError;
|
type Err = ParseIntError;
|
||||||
fn from_str(src: &str) -> Result<Self, ParseIntError> {
|
fn from_str(src: &str) -> Result<Self, ParseIntError> {
|
||||||
from_str_radix(src, 10)
|
<$t>::from_str_radix(src, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*}
|
)*}
|
||||||
}
|
}
|
||||||
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
|
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
|
||||||
|
|
||||||
macro_rules! impl_helper_for {
|
|
||||||
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
|
|
||||||
const MIN: Self = Self::MIN;
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(u: u32) -> Self { u as Self }
|
|
||||||
#[inline]
|
|
||||||
fn checked_mul(&self, other: u32) -> Option<Self> {
|
|
||||||
Self::checked_mul(*self, other as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn checked_sub(&self, other: u32) -> Option<Self> {
|
|
||||||
Self::checked_sub(*self, other as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn checked_add(&self, other: u32) -> Option<Self> {
|
|
||||||
Self::checked_add(*self, other as Self)
|
|
||||||
}
|
|
||||||
})*)
|
|
||||||
}
|
|
||||||
impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
|
|
||||||
|
|
||||||
/// Determines if a string of text of that length of that radix could be guaranteed to be
|
/// Determines if a string of text of that length of that radix could be guaranteed to be
|
||||||
/// stored in the given type T.
|
/// stored in the given type T.
|
||||||
/// Note that if the radix is known to the compiler, it is just the check of digits.len that
|
/// Note that if the radix is known to the compiler, it is just the check of digits.len that
|
||||||
|
@ -1438,92 +1405,198 @@ impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[unstable(issue = "none", feature = "std_internals")]
|
#[unstable(issue = "none", feature = "std_internals")]
|
||||||
pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
|
pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
|
||||||
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
|
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
|
#[track_caller]
|
||||||
use self::IntErrorKind::*;
|
const fn from_str_radix_panic_ct(_radix: u32) -> ! {
|
||||||
use self::ParseIntError as PIE;
|
panic!("from_str_radix_int: must lie in the range `[2, 36]`");
|
||||||
|
|
||||||
assert!(
|
|
||||||
(2..=36).contains(&radix),
|
|
||||||
"from_str_radix_int: must lie in the range `[2, 36]` - found {}",
|
|
||||||
radix
|
|
||||||
);
|
|
||||||
|
|
||||||
if src.is_empty() {
|
|
||||||
return Err(PIE { kind: Empty });
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_signed_ty = T::from_u32(0) > T::MIN;
|
|
||||||
|
|
||||||
// all valid digits are ascii, so we will just iterate over the utf8 bytes
|
|
||||||
// and cast them to chars. .to_digit() will safely return None for anything
|
|
||||||
// other than a valid ascii digit for the given radix, including the first-byte
|
|
||||||
// of multi-byte sequences
|
|
||||||
let src = src.as_bytes();
|
|
||||||
|
|
||||||
let (is_positive, digits) = match src[0] {
|
|
||||||
b'+' | b'-' if src[1..].is_empty() => {
|
|
||||||
return Err(PIE { kind: InvalidDigit });
|
|
||||||
}
|
|
||||||
b'+' => (true, &src[1..]),
|
|
||||||
b'-' if is_signed_ty => (false, &src[1..]),
|
|
||||||
_ => (true, src),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut result = T::from_u32(0);
|
|
||||||
|
|
||||||
if can_not_overflow::<T>(radix, is_signed_ty, digits) {
|
|
||||||
// If the len of the str is short compared to the range of the type
|
|
||||||
// we are parsing into, then we can be certain that an overflow will not occur.
|
|
||||||
// This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
|
|
||||||
// above is a faster (conservative) approximation of this.
|
|
||||||
//
|
|
||||||
// Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
|
|
||||||
// `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
|
|
||||||
// `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
|
|
||||||
macro_rules! run_unchecked_loop {
|
|
||||||
($unchecked_additive_op:expr) => {
|
|
||||||
for &c in digits {
|
|
||||||
result = result * T::from_u32(radix);
|
|
||||||
let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
|
|
||||||
result = $unchecked_additive_op(result, T::from_u32(x));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if is_positive {
|
|
||||||
run_unchecked_loop!(<T as core::ops::Add>::add)
|
|
||||||
} else {
|
|
||||||
run_unchecked_loop!(<T as core::ops::Sub>::sub)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
macro_rules! run_checked_loop {
|
|
||||||
($checked_additive_op:ident, $overflow_err:expr) => {
|
|
||||||
for &c in digits {
|
|
||||||
// When `radix` is passed in as a literal, rather than doing a slow `imul`
|
|
||||||
// the compiler can use shifts if `radix` can be expressed as a
|
|
||||||
// sum of powers of 2 (x*10 can be written as x*8 + x*2).
|
|
||||||
// When the compiler can't use these optimisations,
|
|
||||||
// the latency of the multiplication can be hidden by issuing it
|
|
||||||
// before the result is needed to improve performance on
|
|
||||||
// modern out-of-order CPU as multiplication here is slower
|
|
||||||
// than the other instructions, we can get the end result faster
|
|
||||||
// doing multiplication first and let the CPU spends other cycles
|
|
||||||
// doing other computation and get multiplication result later.
|
|
||||||
let mul = result.checked_mul(radix);
|
|
||||||
let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
|
|
||||||
result = mul.ok_or_else($overflow_err)?;
|
|
||||||
result = T::$checked_additive_op(&result, x).ok_or_else($overflow_err)?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if is_positive {
|
|
||||||
run_checked_loop!(checked_add, || PIE { kind: PosOverflow })
|
|
||||||
} else {
|
|
||||||
run_checked_loop!(checked_sub, || PIE { kind: NegOverflow })
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn from_str_radix_panic_rt(radix: u32) -> ! {
|
||||||
|
panic!("from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||||
|
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||||
|
#[cold]
|
||||||
|
#[track_caller]
|
||||||
|
const fn from_str_radix_assert(radix: u32) {
|
||||||
|
if 2 > radix || radix > 36 {
|
||||||
|
// The only difference between these two functions is their panic message.
|
||||||
|
intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! from_str_radix {
|
||||||
|
($($int_ty:ty)+) => {$(
|
||||||
|
impl $int_ty {
|
||||||
|
/// Converts a string slice in a given base to an integer.
|
||||||
|
///
|
||||||
|
/// The string is expected to be an optional `+` sign
|
||||||
|
/// followed by digits.
|
||||||
|
/// Leading and trailing whitespace represent an error.
|
||||||
|
/// Digits are a subset of these characters, depending on `radix`:
|
||||||
|
///
|
||||||
|
/// * `0-9`
|
||||||
|
/// * `a-z`
|
||||||
|
/// * `A-Z`
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function panics if `radix` is not in the range from 2 to 36.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
#[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")]
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
|
||||||
|
pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> {
|
||||||
|
use self::IntErrorKind::*;
|
||||||
|
use self::ParseIntError as PIE;
|
||||||
|
|
||||||
|
from_str_radix_assert(radix);
|
||||||
|
|
||||||
|
if src.is_empty() {
|
||||||
|
return Err(PIE { kind: Empty });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_comparisons)]
|
||||||
|
let is_signed_ty = 0 > <$int_ty>::MIN;
|
||||||
|
|
||||||
|
// all valid digits are ascii, so we will just iterate over the utf8 bytes
|
||||||
|
// and cast them to chars. .to_digit() will safely return None for anything
|
||||||
|
// other than a valid ascii digit for the given radix, including the first-byte
|
||||||
|
// of multi-byte sequences
|
||||||
|
let src = src.as_bytes();
|
||||||
|
|
||||||
|
let (is_positive, mut digits) = match src {
|
||||||
|
[b'+' | b'-'] => {
|
||||||
|
return Err(PIE { kind: InvalidDigit });
|
||||||
|
}
|
||||||
|
[b'+', rest @ ..] => (true, rest),
|
||||||
|
[b'-', rest @ ..] if is_signed_ty => (false, rest),
|
||||||
|
_ => (true, src),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = 0;
|
||||||
|
|
||||||
|
macro_rules! unwrap_or_PIE {
|
||||||
|
($option:expr, $kind:ident) => {
|
||||||
|
match $option {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Err(PIE { kind: $kind }),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if can_not_overflow::<$int_ty>(radix, is_signed_ty, digits) {
|
||||||
|
// If the len of the str is short compared to the range of the type
|
||||||
|
// we are parsing into, then we can be certain that an overflow will not occur.
|
||||||
|
// This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
|
||||||
|
// above is a faster (conservative) approximation of this.
|
||||||
|
//
|
||||||
|
// Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
|
||||||
|
// `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
|
||||||
|
// `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
|
||||||
|
macro_rules! run_unchecked_loop {
|
||||||
|
($unchecked_additive_op:tt) => {{
|
||||||
|
while let [c, rest @ ..] = digits {
|
||||||
|
result = result * (radix as $int_ty);
|
||||||
|
let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit);
|
||||||
|
result = result $unchecked_additive_op (x as $int_ty);
|
||||||
|
digits = rest;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
if is_positive {
|
||||||
|
run_unchecked_loop!(+)
|
||||||
|
} else {
|
||||||
|
run_unchecked_loop!(-)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
macro_rules! run_checked_loop {
|
||||||
|
($checked_additive_op:ident, $overflow_err:ident) => {{
|
||||||
|
while let [c, rest @ ..] = digits {
|
||||||
|
// When `radix` is passed in as a literal, rather than doing a slow `imul`
|
||||||
|
// the compiler can use shifts if `radix` can be expressed as a
|
||||||
|
// sum of powers of 2 (x*10 can be written as x*8 + x*2).
|
||||||
|
// When the compiler can't use these optimisations,
|
||||||
|
// the latency of the multiplication can be hidden by issuing it
|
||||||
|
// before the result is needed to improve performance on
|
||||||
|
// modern out-of-order CPU as multiplication here is slower
|
||||||
|
// than the other instructions, we can get the end result faster
|
||||||
|
// doing multiplication first and let the CPU spends other cycles
|
||||||
|
// doing other computation and get multiplication result later.
|
||||||
|
let mul = result.checked_mul(radix as $int_ty);
|
||||||
|
let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit) as $int_ty;
|
||||||
|
result = unwrap_or_PIE!(mul, $overflow_err);
|
||||||
|
result = unwrap_or_PIE!(<$int_ty>::$checked_additive_op(result, x), $overflow_err);
|
||||||
|
digits = rest;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
if is_positive {
|
||||||
|
run_checked_loop!(checked_add, PosOverflow)
|
||||||
|
} else {
|
||||||
|
run_checked_loop!(checked_sub, NegOverflow)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+}
|
||||||
|
}
|
||||||
|
|
||||||
|
from_str_radix! { i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 }
|
||||||
|
|
||||||
|
// Re-use the relevant implementation of from_str_radix for isize and usize to avoid outputting two
|
||||||
|
// identical functions.
|
||||||
|
macro_rules! from_str_radix_size_impl {
|
||||||
|
($($t:ident $size:ty),*) => {$(
|
||||||
|
impl $size {
|
||||||
|
/// Converts a string slice in a given base to an integer.
|
||||||
|
///
|
||||||
|
/// The string is expected to be an optional `+` sign
|
||||||
|
/// followed by digits.
|
||||||
|
/// Leading and trailing whitespace represent an error.
|
||||||
|
/// Digits are a subset of these characters, depending on `radix`:
|
||||||
|
///
|
||||||
|
/// * `0-9`
|
||||||
|
/// * `a-z`
|
||||||
|
/// * `A-Z`
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function panics if `radix` is not in the range from 2 to 36.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
#[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")]
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
|
||||||
|
pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> {
|
||||||
|
match <$t>::from_str_radix(src, radix) {
|
||||||
|
Ok(x) => Ok(x as $size),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})*}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "16")]
|
||||||
|
from_str_radix_size_impl! { i16 isize, u16 usize }
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
from_str_radix_size_impl! { i32 isize, u32 usize }
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
from_str_radix_size_impl! { i64 isize, u64 usize }
|
||||||
|
|
|
@ -11,7 +11,6 @@ use crate::ptr;
|
||||||
use crate::str::FromStr;
|
use crate::str::FromStr;
|
||||||
use crate::ub_checks;
|
use crate::ub_checks;
|
||||||
|
|
||||||
use super::from_str_radix;
|
|
||||||
use super::{IntErrorKind, ParseIntError};
|
use super::{IntErrorKind, ParseIntError};
|
||||||
|
|
||||||
/// A marker trait for primitive types which can be zero.
|
/// A marker trait for primitive types which can be zero.
|
||||||
|
@ -804,7 +803,7 @@ macro_rules! nonzero_integer {
|
||||||
impl FromStr for $Ty {
|
impl FromStr for $Ty {
|
||||||
type Err = ParseIntError;
|
type Err = ParseIntError;
|
||||||
fn from_str(src: &str) -> Result<Self, Self::Err> {
|
fn from_str(src: &str) -> Result<Self, Self::Err> {
|
||||||
Self::new(from_str_radix(src, 10)?)
|
Self::new(<$Int>::from_str_radix(src, 10)?)
|
||||||
.ok_or(ParseIntError {
|
.ok_or(ParseIntError {
|
||||||
kind: IntErrorKind::Zero
|
kind: IntErrorKind::Zero
|
||||||
})
|
})
|
||||||
|
|
|
@ -58,33 +58,6 @@ macro_rules! uint_impl {
|
||||||
#[stable(feature = "int_bits_const", since = "1.53.0")]
|
#[stable(feature = "int_bits_const", since = "1.53.0")]
|
||||||
pub const BITS: u32 = Self::MAX.count_ones();
|
pub const BITS: u32 = Self::MAX.count_ones();
|
||||||
|
|
||||||
/// Converts a string slice in a given base to an integer.
|
|
||||||
///
|
|
||||||
/// The string is expected to be an optional `+` sign
|
|
||||||
/// followed by digits.
|
|
||||||
/// Leading and trailing whitespace represent an error.
|
|
||||||
/// Digits are a subset of these characters, depending on `radix`:
|
|
||||||
///
|
|
||||||
/// * `0-9`
|
|
||||||
/// * `a-z`
|
|
||||||
/// * `A-Z`
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This function panics if `radix` is not in the range from 2 to 36.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Basic usage:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
|
|
||||||
from_str_radix(src, radix)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of ones in the binary representation of `self`.
|
/// Returns the number of ones in the binary representation of `self`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -1401,8 +1401,6 @@ impl<T: ?Sized> *const T {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
///
|
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
/// #[repr(align(4))]
|
/// #[repr(align(4))]
|
||||||
/// struct AlignedI32(i32);
|
/// struct AlignedI32(i32);
|
||||||
|
@ -1425,7 +1423,6 @@ impl<T: ?Sized> *const T {
|
||||||
/// underlying allocation.
|
/// underlying allocation.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of primitives is less than their size.
|
/// // On some platforms, the alignment of primitives is less than their size.
|
||||||
|
@ -1451,7 +1448,6 @@ impl<T: ?Sized> *const T {
|
||||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of primitives is less than their size.
|
/// // On some platforms, the alignment of primitives is less than their size.
|
||||||
|
@ -1477,7 +1473,6 @@ impl<T: ?Sized> *const T {
|
||||||
/// runtime and compiletime.
|
/// runtime and compiletime.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of primitives is less than their size.
|
/// // On some platforms, the alignment of primitives is less than their size.
|
||||||
|
@ -1501,7 +1496,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
#[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||||
pub const fn is_aligned(self) -> bool
|
pub const fn is_aligned(self) -> bool
|
||||||
where
|
where
|
||||||
|
@ -1522,7 +1517,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
/// #[repr(align(4))]
|
/// #[repr(align(4))]
|
||||||
|
@ -1551,7 +1546,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// cannot be stricter aligned than the reference's underlying allocation.
|
/// cannot be stricter aligned than the reference's underlying allocation.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
|
@ -1576,7 +1571,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
|
@ -1600,7 +1595,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// runtime and compiletime.
|
/// runtime and compiletime.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// const _: () = {
|
/// const _: () = {
|
||||||
|
@ -1616,7 +1611,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
|
||||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||||
pub const fn is_aligned_to(self, align: usize) -> bool {
|
pub const fn is_aligned_to(self, align: usize) -> bool {
|
||||||
if !align.is_power_of_two() {
|
if !align.is_power_of_two() {
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub trait Pointee {
|
||||||
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
|
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
|
||||||
// in `library/core/src/ptr/metadata.rs`
|
// in `library/core/src/ptr/metadata.rs`
|
||||||
// in sync with those here:
|
// in sync with those here:
|
||||||
type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
|
type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pointers to types implementing this trait alias are “thin”.
|
/// Pointers to types implementing this trait alias are “thin”.
|
||||||
|
|
|
@ -1660,8 +1660,6 @@ impl<T: ?Sized> *mut T {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
///
|
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
/// #[repr(align(4))]
|
/// #[repr(align(4))]
|
||||||
/// struct AlignedI32(i32);
|
/// struct AlignedI32(i32);
|
||||||
|
@ -1684,7 +1682,6 @@ impl<T: ?Sized> *mut T {
|
||||||
/// underlying allocation.
|
/// underlying allocation.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
/// #![feature(const_mut_refs)]
|
/// #![feature(const_mut_refs)]
|
||||||
///
|
///
|
||||||
|
@ -1711,7 +1708,6 @@ impl<T: ?Sized> *mut T {
|
||||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of primitives is less than their size.
|
/// // On some platforms, the alignment of primitives is less than their size.
|
||||||
|
@ -1738,7 +1734,6 @@ impl<T: ?Sized> *mut T {
|
||||||
/// runtime and compiletime.
|
/// runtime and compiletime.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of primitives is less than their size.
|
/// // On some platforms, the alignment of primitives is less than their size.
|
||||||
|
@ -1762,7 +1757,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
#[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||||
pub const fn is_aligned(self) -> bool
|
pub const fn is_aligned(self) -> bool
|
||||||
where
|
where
|
||||||
|
@ -1783,7 +1778,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
/// #[repr(align(4))]
|
/// #[repr(align(4))]
|
||||||
|
@ -1812,7 +1807,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// cannot be stricter aligned than the reference's underlying allocation.
|
/// cannot be stricter aligned than the reference's underlying allocation.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
/// #![feature(const_mut_refs)]
|
/// #![feature(const_mut_refs)]
|
||||||
///
|
///
|
||||||
|
@ -1838,7 +1833,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
|
@ -1863,7 +1858,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// runtime and compiletime.
|
/// runtime and compiletime.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// const _: () = {
|
/// const _: () = {
|
||||||
|
@ -1879,7 +1874,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
|
||||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||||
pub const fn is_aligned_to(self, align: usize) -> bool {
|
pub const fn is_aligned_to(self, align: usize) -> bool {
|
||||||
if !align.is_power_of_two() {
|
if !align.is_power_of_two() {
|
||||||
|
|
|
@ -1288,7 +1288,6 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// use std::ptr::NonNull;
|
/// use std::ptr::NonNull;
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
|
@ -1313,7 +1312,6 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// underlying allocation.
|
/// underlying allocation.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
/// #![feature(non_null_convenience)]
|
/// #![feature(non_null_convenience)]
|
||||||
/// #![feature(const_option)]
|
/// #![feature(const_option)]
|
||||||
|
@ -1343,7 +1341,6 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of primitives is less than their size.
|
/// // On some platforms, the alignment of primitives is less than their size.
|
||||||
|
@ -1369,7 +1366,6 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// runtime and compiletime.
|
/// runtime and compiletime.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
/// #![feature(const_option)]
|
/// #![feature(const_option)]
|
||||||
/// #![feature(const_nonnull_new)]
|
/// #![feature(const_nonnull_new)]
|
||||||
|
@ -1394,7 +1390,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
#[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1417,7 +1413,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
/// #[repr(align(4))]
|
/// #[repr(align(4))]
|
||||||
|
@ -1446,7 +1442,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// cannot be stricter aligned than the reference's underlying allocation.
|
/// cannot be stricter aligned than the reference's underlying allocation.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
|
@ -1471,7 +1467,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// // On some platforms, the alignment of i32 is less than 4.
|
/// // On some platforms, the alignment of i32 is less than 4.
|
||||||
|
@ -1495,7 +1491,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// runtime and compiletime.
|
/// runtime and compiletime.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
/// #![feature(pointer_is_aligned_to)]
|
||||||
/// #![feature(const_pointer_is_aligned)]
|
/// #![feature(const_pointer_is_aligned)]
|
||||||
///
|
///
|
||||||
/// const _: () = {
|
/// const _: () = {
|
||||||
|
@ -1509,7 +1505,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
|
||||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -418,14 +418,12 @@ impl AtomicBool {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// use std::sync::atomic::{self, AtomicBool};
|
/// use std::sync::atomic::{self, AtomicBool};
|
||||||
/// use std::mem::align_of;
|
|
||||||
///
|
///
|
||||||
/// // Get a pointer to an allocated value
|
/// // Get a pointer to an allocated value
|
||||||
/// let ptr: *mut bool = Box::into_raw(Box::new(false));
|
/// let ptr: *mut bool = Box::into_raw(Box::new(false));
|
||||||
///
|
///
|
||||||
/// assert!(ptr.is_aligned_to(align_of::<AtomicBool>()));
|
/// assert!(ptr.cast::<AtomicBool>().is_aligned());
|
||||||
///
|
///
|
||||||
/// {
|
/// {
|
||||||
/// // Create an atomic view of the allocated value
|
/// // Create an atomic view of the allocated value
|
||||||
|
@ -1216,14 +1214,12 @@ impl<T> AtomicPtr<T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
/// use std::sync::atomic::{self, AtomicPtr};
|
/// use std::sync::atomic::{self, AtomicPtr};
|
||||||
/// use std::mem::align_of;
|
|
||||||
///
|
///
|
||||||
/// // Get a pointer to an allocated value
|
/// // Get a pointer to an allocated value
|
||||||
/// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut()));
|
/// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut()));
|
||||||
///
|
///
|
||||||
/// assert!(ptr.is_aligned_to(align_of::<AtomicPtr<u8>>()));
|
/// assert!(ptr.cast::<AtomicPtr<u8>>().is_aligned());
|
||||||
///
|
///
|
||||||
/// {
|
/// {
|
||||||
/// // Create an atomic view of the allocated value
|
/// // Create an atomic view of the allocated value
|
||||||
|
@ -2199,14 +2195,12 @@ macro_rules! atomic_int {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(pointer_is_aligned)]
|
|
||||||
#[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
|
#[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
|
||||||
/// use std::mem::align_of;
|
|
||||||
///
|
///
|
||||||
/// // Get a pointer to an allocated value
|
/// // Get a pointer to an allocated value
|
||||||
#[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")]
|
#[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")]
|
||||||
///
|
///
|
||||||
#[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")]
|
#[doc = concat!("assert!(ptr.cast::<", stringify!($atomic_type), ">().is_aligned());")]
|
||||||
///
|
///
|
||||||
/// {
|
/// {
|
||||||
/// // Create an atomic view of the allocated value
|
/// // Create an atomic view of the allocated value
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#![feature(const_hash)]
|
#![feature(const_hash)]
|
||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
#![feature(const_intrinsic_copy)]
|
#![feature(const_intrinsic_copy)]
|
||||||
|
#![feature(const_int_from_str)]
|
||||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||||
#![feature(const_nonnull_new)]
|
#![feature(const_nonnull_new)]
|
||||||
#![feature(const_pointer_is_aligned)]
|
#![feature(const_pointer_is_aligned)]
|
||||||
|
@ -95,7 +96,7 @@
|
||||||
#![feature(const_waker)]
|
#![feature(const_waker)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(unwrap_infallible)]
|
#![feature(unwrap_infallible)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
#![feature(portable_simd)]
|
#![feature(portable_simd)]
|
||||||
#![feature(ptr_metadata)]
|
#![feature(ptr_metadata)]
|
||||||
#![feature(lazy_cell)]
|
#![feature(lazy_cell)]
|
||||||
|
|
|
@ -214,6 +214,16 @@ fn test_infallible_try_from_int_error() {
|
||||||
assert!(func(0).is_ok());
|
assert!(func(0).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _TEST_CONST_PARSE: () = {
|
||||||
|
let Ok(-0x8000) = i16::from_str_radix("-8000", 16) else { panic!() };
|
||||||
|
let Ok(12345) = u64::from_str_radix("12345", 10) else { panic!() };
|
||||||
|
if let Err(e) = i8::from_str_radix("+", 10) {
|
||||||
|
let IntErrorKind::InvalidDigit = e.kind() else { panic!() };
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
macro_rules! test_impl_from {
|
macro_rules! test_impl_from {
|
||||||
($fn_name:ident, bool, $target: ty) => {
|
($fn_name:ident, bool, $target: ty) => {
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -841,11 +841,19 @@ fn ptr_metadata_bounds() {
|
||||||
fn static_assert_expected_bounds_for_metadata<Meta>()
|
fn static_assert_expected_bounds_for_metadata<Meta>()
|
||||||
where
|
where
|
||||||
// Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
|
// Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
|
||||||
Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
|
Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pointee_metadata_debug() {
|
||||||
|
assert_eq!("()", format!("{:?}", metadata::<u32>(&17)));
|
||||||
|
assert_eq!("2", format!("{:?}", metadata::<[u32]>(&[19, 23])));
|
||||||
|
let for_dyn = format!("{:?}", metadata::<dyn Debug>(&29));
|
||||||
|
assert!(for_dyn.starts_with("DynMetadata(0x"), "{:?}", for_dyn);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dyn_metadata() {
|
fn dyn_metadata() {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -341,7 +341,7 @@
|
||||||
#![feature(panic_can_unwind)]
|
#![feature(panic_can_unwind)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(panic_internals)]
|
#![feature(panic_internals)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
#![feature(portable_simd)]
|
#![feature(portable_simd)]
|
||||||
#![feature(prelude_2024)]
|
#![feature(prelude_2024)]
|
||||||
#![feature(ptr_as_uninit)]
|
#![feature(ptr_as_uninit)]
|
||||||
|
|
|
@ -571,7 +571,9 @@ pub fn make_tests(
|
||||||
&modified_tests,
|
&modified_tests,
|
||||||
&mut poisoned,
|
&mut poisoned,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display()));
|
.unwrap_or_else(|reason| {
|
||||||
|
panic!("Could not read tests from {}: {reason}", config.src_base.display())
|
||||||
|
});
|
||||||
|
|
||||||
if poisoned {
|
if poisoned {
|
||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
69fa40cb48384fad7930dce2d9a20d18fe4d1b51
|
5baf1e13f568b61e121953bf6a3d09faee7dd446
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//@ignore-target-windows: No libc on Windows
|
//@ignore-target-windows: No libc on Windows
|
||||||
|
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#![crate_type="rlib"]
|
#![crate_type="rlib"]
|
||||||
|
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
|
|
||||||
// CHECK-LABEL: is_aligned_to_unchecked
|
// CHECK-LABEL: is_aligned_to_unchecked
|
||||||
// CHECK: decq
|
// CHECK: decq
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
// MIR for `constant_eq` after SimplifyCfg-initial
|
||||||
|
|
||||||
|
fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||||
|
debug s => _1;
|
||||||
|
debug b => _2;
|
||||||
|
let mut _0: u32;
|
||||||
|
let mut _3: (&str, bool);
|
||||||
|
let mut _4: &str;
|
||||||
|
let mut _5: bool;
|
||||||
|
let mut _6: bool;
|
||||||
|
let mut _7: bool;
|
||||||
|
let mut _8: &&str;
|
||||||
|
let mut _9: &bool;
|
||||||
|
let mut _10: bool;
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_3);
|
||||||
|
StorageLive(_4);
|
||||||
|
_4 = _1;
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = _2;
|
||||||
|
_3 = (move _4, move _5);
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageDead(_4);
|
||||||
|
PlaceMention(_3);
|
||||||
|
_7 = <str as PartialEq>::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb3];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
_0 = const 5_u32;
|
||||||
|
goto -> bb18;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
falseEdge -> [real: bb17, imaginary: bb2];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
falseEdge -> [real: bb12, imaginary: bb9];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
falseEdge -> [real: bb16, imaginary: bb3];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
_6 = <str as PartialEq>::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb8: {
|
||||||
|
switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb9];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb9: {
|
||||||
|
falseEdge -> [real: bb15, imaginary: bb6];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb10: {
|
||||||
|
switchInt(move _6) -> [0: bb1, otherwise: bb8];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb11: {
|
||||||
|
switchInt(move _7) -> [0: bb7, otherwise: bb4];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb12: {
|
||||||
|
_8 = &fake (_3.0: &str);
|
||||||
|
_9 = &fake (_3.1: bool);
|
||||||
|
StorageLive(_10);
|
||||||
|
_10 = const true;
|
||||||
|
switchInt(move _10) -> [0: bb14, otherwise: bb13];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb13: {
|
||||||
|
StorageDead(_10);
|
||||||
|
FakeRead(ForMatchGuard, _8);
|
||||||
|
FakeRead(ForMatchGuard, _9);
|
||||||
|
_0 = const 1_u32;
|
||||||
|
goto -> bb18;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb14: {
|
||||||
|
StorageDead(_10);
|
||||||
|
falseEdge -> [real: bb5, imaginary: bb9];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb15: {
|
||||||
|
_0 = const 2_u32;
|
||||||
|
goto -> bb18;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb16: {
|
||||||
|
_0 = const 3_u32;
|
||||||
|
goto -> bb18;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb17: {
|
||||||
|
_0 = const 4_u32;
|
||||||
|
goto -> bb18;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb18: {
|
||||||
|
StorageDead(_3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb19 (cleanup): {
|
||||||
|
resume;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
// MIR for `disjoint_ranges` after SimplifyCfg-initial
|
||||||
|
|
||||||
|
fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||||
|
debug x => _1;
|
||||||
|
debug b => _2;
|
||||||
|
let mut _0: u32;
|
||||||
|
let mut _3: bool;
|
||||||
|
let mut _4: bool;
|
||||||
|
let mut _5: bool;
|
||||||
|
let mut _6: bool;
|
||||||
|
let mut _7: &i32;
|
||||||
|
let mut _8: bool;
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
PlaceMention(_1);
|
||||||
|
_5 = Le(const 0_i32, _1);
|
||||||
|
switchInt(move _5) -> [0: bb3, otherwise: bb8];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
_0 = const 3_u32;
|
||||||
|
goto -> bb14;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
falseEdge -> [real: bb9, imaginary: bb4];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
_3 = Le(const 10_i32, _1);
|
||||||
|
switchInt(move _3) -> [0: bb5, otherwise: bb7];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
falseEdge -> [real: bb12, imaginary: bb6];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
switchInt(_1) -> [4294967295: bb6, otherwise: bb1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
falseEdge -> [real: bb13, imaginary: bb1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
_4 = Le(_1, const 20_i32);
|
||||||
|
switchInt(move _4) -> [0: bb5, otherwise: bb4];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb8: {
|
||||||
|
_6 = Lt(_1, const 10_i32);
|
||||||
|
switchInt(move _6) -> [0: bb3, otherwise: bb2];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb9: {
|
||||||
|
_7 = &fake _1;
|
||||||
|
StorageLive(_8);
|
||||||
|
_8 = _2;
|
||||||
|
switchInt(move _8) -> [0: bb11, otherwise: bb10];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb10: {
|
||||||
|
StorageDead(_8);
|
||||||
|
FakeRead(ForMatchGuard, _7);
|
||||||
|
_0 = const 0_u32;
|
||||||
|
goto -> bb14;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb11: {
|
||||||
|
StorageDead(_8);
|
||||||
|
falseEdge -> [real: bb1, imaginary: bb4];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb12: {
|
||||||
|
_0 = const 1_u32;
|
||||||
|
goto -> bb14;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb13: {
|
||||||
|
_0 = const 2_u32;
|
||||||
|
goto -> bb14;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb14: {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
41
tests/mir-opt/building/match/sort_candidates.rs
Normal file
41
tests/mir-opt/building/match/sort_candidates.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Check specific cases of sorting candidates in match lowering.
|
||||||
|
#![feature(exclusive_range_pattern)]
|
||||||
|
|
||||||
|
// EMIT_MIR sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
|
||||||
|
fn constant_eq(s: &str, b: bool) -> u32 {
|
||||||
|
// Check that we only test "a" once
|
||||||
|
|
||||||
|
// CHECK-LABEL: fn constant_eq(
|
||||||
|
// CHECK: bb0: {
|
||||||
|
// CHECK: [[a:_.*]] = const "a";
|
||||||
|
// CHECK-NOT: {{_.*}} = const "a";
|
||||||
|
match (s, b) {
|
||||||
|
("a", _) if true => 1,
|
||||||
|
("b", true) => 2,
|
||||||
|
("a", true) => 3,
|
||||||
|
(_, true) => 4,
|
||||||
|
_ => 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EMIT_MIR sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
|
||||||
|
fn disjoint_ranges(x: i32, b: bool) -> u32 {
|
||||||
|
// When `(0..=10).contains(x) && !b`, we should jump to the last arm without testing the two
|
||||||
|
// other candidates.
|
||||||
|
|
||||||
|
// CHECK-LABEL: fn disjoint_ranges(
|
||||||
|
// CHECK: debug b => _2;
|
||||||
|
// CHECK: bb0: {
|
||||||
|
// CHECK: switchInt(_2) -> [0: [[jump:bb.*]], otherwise: {{bb.*}}];
|
||||||
|
// CHECK: [[jump]]: {
|
||||||
|
// CHECK-NEXT: _0 = const 3_u32;
|
||||||
|
// CHECK-NEXT: return;
|
||||||
|
match x {
|
||||||
|
0..10 if b => 0,
|
||||||
|
10..=20 => 1,
|
||||||
|
-1 => 2,
|
||||||
|
_ => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,106 +0,0 @@
|
||||||
// MIR for `main` after SimplifyCfg-initial
|
|
||||||
|
|
||||||
fn main() -> () {
|
|
||||||
let mut _0: ();
|
|
||||||
let _1: i32;
|
|
||||||
let _3: i32;
|
|
||||||
let mut _4: bool;
|
|
||||||
let mut _5: bool;
|
|
||||||
let mut _6: bool;
|
|
||||||
let mut _7: bool;
|
|
||||||
let mut _8: &i32;
|
|
||||||
let mut _9: bool;
|
|
||||||
scope 1 {
|
|
||||||
debug x => _1;
|
|
||||||
let _2: bool;
|
|
||||||
scope 2 {
|
|
||||||
debug b => _2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bb0: {
|
|
||||||
StorageLive(_1);
|
|
||||||
_1 = const 3_i32;
|
|
||||||
FakeRead(ForLet(None), _1);
|
|
||||||
StorageLive(_2);
|
|
||||||
_2 = const true;
|
|
||||||
FakeRead(ForLet(None), _2);
|
|
||||||
StorageLive(_3);
|
|
||||||
PlaceMention(_1);
|
|
||||||
_6 = Le(const 0_i32, _1);
|
|
||||||
switchInt(move _6) -> [0: bb3, otherwise: bb8];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb1: {
|
|
||||||
_3 = const 3_i32;
|
|
||||||
goto -> bb14;
|
|
||||||
}
|
|
||||||
|
|
||||||
bb2: {
|
|
||||||
falseEdge -> [real: bb9, imaginary: bb4];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb3: {
|
|
||||||
_4 = Le(const 10_i32, _1);
|
|
||||||
switchInt(move _4) -> [0: bb5, otherwise: bb7];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb4: {
|
|
||||||
falseEdge -> [real: bb12, imaginary: bb6];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb5: {
|
|
||||||
switchInt(_1) -> [4294967295: bb6, otherwise: bb1];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb6: {
|
|
||||||
falseEdge -> [real: bb13, imaginary: bb1];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb7: {
|
|
||||||
_5 = Le(_1, const 20_i32);
|
|
||||||
switchInt(move _5) -> [0: bb5, otherwise: bb4];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb8: {
|
|
||||||
_7 = Lt(_1, const 10_i32);
|
|
||||||
switchInt(move _7) -> [0: bb3, otherwise: bb2];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb9: {
|
|
||||||
_8 = &fake _1;
|
|
||||||
StorageLive(_9);
|
|
||||||
_9 = _2;
|
|
||||||
switchInt(move _9) -> [0: bb11, otherwise: bb10];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb10: {
|
|
||||||
StorageDead(_9);
|
|
||||||
FakeRead(ForMatchGuard, _8);
|
|
||||||
_3 = const 0_i32;
|
|
||||||
goto -> bb14;
|
|
||||||
}
|
|
||||||
|
|
||||||
bb11: {
|
|
||||||
StorageDead(_9);
|
|
||||||
falseEdge -> [real: bb1, imaginary: bb4];
|
|
||||||
}
|
|
||||||
|
|
||||||
bb12: {
|
|
||||||
_3 = const 1_i32;
|
|
||||||
goto -> bb14;
|
|
||||||
}
|
|
||||||
|
|
||||||
bb13: {
|
|
||||||
_3 = const 2_i32;
|
|
||||||
goto -> bb14;
|
|
||||||
}
|
|
||||||
|
|
||||||
bb14: {
|
|
||||||
StorageDead(_3);
|
|
||||||
_0 = const ();
|
|
||||||
StorageDead(_2);
|
|
||||||
StorageDead(_1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// skip-filecheck
|
|
||||||
// Make sure redundant testing paths in `match` expressions are sorted out.
|
|
||||||
|
|
||||||
#![feature(exclusive_range_pattern)]
|
|
||||||
|
|
||||||
// EMIT_MIR match_test.main.SimplifyCfg-initial.after.mir
|
|
||||||
fn main() {
|
|
||||||
let x = 3;
|
|
||||||
let b = true;
|
|
||||||
|
|
||||||
// When `(0..=10).contains(x) && !b`, we should jump to the last arm
|
|
||||||
// without testing two other candidates.
|
|
||||||
match x {
|
|
||||||
0..10 if b => 0,
|
|
||||||
10..=20 => 1,
|
|
||||||
-1 => 2,
|
|
||||||
_ => 3,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
// It is UB to unwind out of `fn start()` according to
|
||||||
|
// https://doc.rust-lang.org/beta/unstable-book/language-features/start.html so
|
||||||
|
// panic with abort to avoid UB:
|
||||||
|
//@ compile-flags: -Cpanic=abort
|
||||||
|
//@ no-prefer-dynamic so panic=abort works
|
||||||
|
|
||||||
|
#![feature(start, rustc_private)]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
// Use #[start] so we don't have a runtime that messes with SIGPIPE.
|
||||||
|
#[start]
|
||||||
|
fn start(argc: isize, argv: *const *const u8) -> isize {
|
||||||
|
assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
|
||||||
|
let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
|
||||||
|
.to_str()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let expected = match arg1 {
|
||||||
|
"SIG_IGN" => libc::SIG_IGN,
|
||||||
|
"SIG_DFL" => libc::SIG_DFL,
|
||||||
|
arg => panic!("Must pass SIG_IGN or SIG_DFL as first arg. Got: {}", arg),
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = unsafe {
|
||||||
|
let mut actual: libc::sigaction = std::mem::zeroed();
|
||||||
|
libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
|
||||||
|
actual.sa_sigaction
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs");
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
//@ revisions: default sig_dfl sig_ign inherit
|
||||||
|
//@ ignore-cross-compile because aux-bin does not yet support it
|
||||||
|
//@ only-unix because SIGPIPE is a unix thing
|
||||||
|
//@ run-pass
|
||||||
|
//@ aux-bin:assert-sigpipe-disposition.rs
|
||||||
|
//@ aux-crate:sigpipe_utils=sigpipe-utils.rs
|
||||||
|
|
||||||
|
// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
|
||||||
|
// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
|
||||||
|
// the default. But there is a difference in how `SIGPIPE` is treated in child
|
||||||
|
// processes with and without the attribute. Search for
|
||||||
|
// `unix_sigpipe_attr_specified()` in the code base to learn more.
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
extern crate sigpipe_utils;
|
||||||
|
|
||||||
|
use sigpipe_utils::*;
|
||||||
|
|
||||||
|
#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
|
||||||
|
#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
|
||||||
|
#[cfg_attr(inherit, unix_sigpipe = "inherit")]
|
||||||
|
fn main() {
|
||||||
|
// By default we get SIG_IGN but the child gets SIG_DFL through an explicit
|
||||||
|
// reset before exec:
|
||||||
|
// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L363-L384
|
||||||
|
#[cfg(default)]
|
||||||
|
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
|
||||||
|
|
||||||
|
// With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too
|
||||||
|
// without any special code running before exec.
|
||||||
|
#[cfg(sig_dfl)]
|
||||||
|
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
|
||||||
|
|
||||||
|
// With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too
|
||||||
|
// without any special code running before exec.
|
||||||
|
#[cfg(sig_ign)]
|
||||||
|
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
|
||||||
|
|
||||||
|
// With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too
|
||||||
|
// without any special code running before exec.
|
||||||
|
#[cfg(inherit)]
|
||||||
|
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
|
||||||
|
|
||||||
|
assert_sigpipe_handler(we_expect);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
std::process::Command::new("./auxiliary/bin/assert-sigpipe-disposition")
|
||||||
|
.arg(child_expects)
|
||||||
|
.status()
|
||||||
|
.unwrap()
|
||||||
|
.success()
|
||||||
|
);
|
||||||
|
}
|
|
@ -247,15 +247,15 @@ LL | _ = &&0 == Foo;
|
||||||
|
|
|
|
||||||
= help: the trait `PartialEq<Foo>` is not implemented for `&&{integer}`
|
= help: the trait `PartialEq<Foo>` is not implemented for `&&{integer}`
|
||||||
= help: the following other types implement trait `PartialEq<Rhs>`:
|
= help: the following other types implement trait `PartialEq<Rhs>`:
|
||||||
|
f128
|
||||||
|
f16
|
||||||
f32
|
f32
|
||||||
f64
|
f64
|
||||||
i128
|
i128
|
||||||
i16
|
i16
|
||||||
i32
|
i32
|
||||||
i64
|
i64
|
||||||
i8
|
and 8 others
|
||||||
isize
|
|
||||||
and 6 others
|
|
||||||
|
|
||||||
error[E0369]: binary operation `==` cannot be applied to type `Foo`
|
error[E0369]: binary operation `==` cannot be applied to type `Foo`
|
||||||
--> $DIR/binary-op-suggest-deref.rs:60:13
|
--> $DIR/binary-op-suggest-deref.rs:60:13
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(adt_const_params)]
|
||||||
|
//~^ WARN the feature `adt_const_params` is incomplete
|
||||||
|
#![feature(with_negative_coherence, negative_impls)]
|
||||||
|
|
||||||
|
pub trait A<const K: &'static str> {}
|
||||||
|
pub trait C {}
|
||||||
|
|
||||||
|
|
||||||
|
struct W<T>(T);
|
||||||
|
|
||||||
|
// Negative coherence:
|
||||||
|
// Proving `W<!T>: !A<"">` requires proving `CONST alias-eq ""`, which requires proving
|
||||||
|
// `CONST normalizes-to (?1c: &str)`. The type's region is uniquified, so it ends up being
|
||||||
|
// put in to the canonical vars list with an infer region => ICE.
|
||||||
|
impl<T> C for T where T: A<""> {}
|
||||||
|
impl<T> C for W<T> {}
|
||||||
|
|
||||||
|
impl<T> !A<CONST> for W<T> {}
|
||||||
|
const CONST: &str = "";
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/regions-in-canonical.rs:3:12
|
||||||
|
|
|
||||||
|
LL | #![feature(adt_const_params)]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//@ ignore-cross-compile because we run the compiled code
|
//@ ignore-cross-compile because aux-bin does not yet support it
|
||||||
//@ aux-bin: print-it-works.rs
|
//@ aux-bin: print-it-works.rs
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
|
||||||
|
|
10
tests/ui/consts/const-eval/parse_ints.rs
Normal file
10
tests/ui/consts/const-eval/parse_ints.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#![feature(const_int_from_str)]
|
||||||
|
|
||||||
|
const _OK: () = match i32::from_str_radix("-1234", 10) {
|
||||||
|
Ok(x) => assert!(x == -1234),
|
||||||
|
Err(_) => panic!(),
|
||||||
|
};
|
||||||
|
const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
|
||||||
|
const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
|
||||||
|
|
||||||
|
fn main () {}
|
31
tests/ui/consts/const-eval/parse_ints.stderr
Normal file
31
tests/ui/consts/const-eval/parse_ints.stderr
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
error[E0080]: evaluation of constant value failed
|
||||||
|
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
|
|
|
||||||
|
= note: the evaluated program panicked at 'from_str_radix_int: must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
|
|
|
||||||
|
note: inside `core::num::<impl u64>::from_str_radix`
|
||||||
|
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
|
note: inside `_TOO_LOW`
|
||||||
|
--> $DIR/parse_ints.rs:7:24
|
||||||
|
|
|
||||||
|
LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: this error originates in the macro `from_str_radix` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0080]: evaluation of constant value failed
|
||||||
|
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
|
|
|
||||||
|
= note: the evaluated program panicked at 'from_str_radix_int: must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
|
|
|
||||||
|
note: inside `core::num::<impl u64>::from_str_radix`
|
||||||
|
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
|
note: inside `_TOO_HIGH`
|
||||||
|
--> $DIR/parse_ints.rs:8:25
|
||||||
|
|
|
||||||
|
LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: this error originates in the macro `from_str_radix` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
|
@ -3,6 +3,7 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
struct A;
|
struct A;
|
||||||
struct B;
|
struct B;
|
||||||
|
@ -50,6 +51,17 @@ fn main() {
|
||||||
let _ = a.gt(&b);
|
let _ = a.gt(&b);
|
||||||
//~^ WARN ambiguous wide pointer comparison
|
//~^ WARN ambiguous wide pointer comparison
|
||||||
|
|
||||||
|
{
|
||||||
|
let a = NonNull::<dyn T>::new(a as *mut _).unwrap();
|
||||||
|
let b = NonNull::<dyn T>::new(b as *mut _).unwrap();
|
||||||
|
let _ = a == b;
|
||||||
|
//~^ WARN ambiguous wide pointer comparison
|
||||||
|
let _ = a >= b;
|
||||||
|
//~^ WARN ambiguous wide pointer comparison
|
||||||
|
let _ = &a == &b;
|
||||||
|
//~^ WARN ambiguous wide pointer comparison
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// &*const ?Sized
|
// &*const ?Sized
|
||||||
let a = &a;
|
let a = &a;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:19:13
|
--> $DIR/wide_pointer_comparisons.rs:20:13
|
||||||
|
|
|
|
||||||
LL | let _ = a == b;
|
LL | let _ = a == b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -11,7 +11,7 @@ LL | let _ = std::ptr::addr_eq(a, b);
|
||||||
| ++++++++++++++++++ ~ +
|
| ++++++++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:21:13
|
--> $DIR/wide_pointer_comparisons.rs:22:13
|
||||||
|
|
|
|
||||||
LL | let _ = a != b;
|
LL | let _ = a != b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -22,7 +22,7 @@ LL | let _ = !std::ptr::addr_eq(a, b);
|
||||||
| +++++++++++++++++++ ~ +
|
| +++++++++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:23:13
|
--> $DIR/wide_pointer_comparisons.rs:24:13
|
||||||
|
|
|
|
||||||
LL | let _ = a < b;
|
LL | let _ = a < b;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -33,7 +33,7 @@ LL | let _ = a.cast::<()>() < b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:25:13
|
--> $DIR/wide_pointer_comparisons.rs:26:13
|
||||||
|
|
|
|
||||||
LL | let _ = a <= b;
|
LL | let _ = a <= b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -44,7 +44,7 @@ LL | let _ = a.cast::<()>() <= b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:27:13
|
--> $DIR/wide_pointer_comparisons.rs:28:13
|
||||||
|
|
|
|
||||||
LL | let _ = a > b;
|
LL | let _ = a > b;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -55,7 +55,7 @@ LL | let _ = a.cast::<()>() > b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:29:13
|
--> $DIR/wide_pointer_comparisons.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let _ = a >= b;
|
LL | let _ = a >= b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -66,7 +66,7 @@ LL | let _ = a.cast::<()>() >= b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:32:13
|
--> $DIR/wide_pointer_comparisons.rs:33:13
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::eq(&a, &b);
|
LL | let _ = PartialEq::eq(&a, &b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -77,7 +77,7 @@ LL | let _ = std::ptr::addr_eq(a, b);
|
||||||
| ~~~~~~~~~~~~~~~~~~ ~ ~
|
| ~~~~~~~~~~~~~~~~~~ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:34:13
|
--> $DIR/wide_pointer_comparisons.rs:35:13
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::ne(&a, &b);
|
LL | let _ = PartialEq::ne(&a, &b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -88,7 +88,7 @@ LL | let _ = !std::ptr::addr_eq(a, b);
|
||||||
| ~~~~~~~~~~~~~~~~~~~ ~ ~
|
| ~~~~~~~~~~~~~~~~~~~ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:36:13
|
--> $DIR/wide_pointer_comparisons.rs:37:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.eq(&b);
|
LL | let _ = a.eq(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -99,7 +99,7 @@ LL | let _ = std::ptr::addr_eq(a, b);
|
||||||
| ++++++++++++++++++ ~ ~
|
| ++++++++++++++++++ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:38:13
|
--> $DIR/wide_pointer_comparisons.rs:39:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.ne(&b);
|
LL | let _ = a.ne(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -110,7 +110,7 @@ LL | let _ = !std::ptr::addr_eq(a, b);
|
||||||
| +++++++++++++++++++ ~ ~
|
| +++++++++++++++++++ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:40:13
|
--> $DIR/wide_pointer_comparisons.rs:41:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.cmp(&b);
|
LL | let _ = a.cmp(&b);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -121,7 +121,7 @@ LL | let _ = a.cast::<()>().cmp(&b.cast::<()>());
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:42:13
|
--> $DIR/wide_pointer_comparisons.rs:43:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.partial_cmp(&b);
|
LL | let _ = a.partial_cmp(&b);
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -132,7 +132,7 @@ LL | let _ = a.cast::<()>().partial_cmp(&b.cast::<()>());
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:44:13
|
--> $DIR/wide_pointer_comparisons.rs:45:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.le(&b);
|
LL | let _ = a.le(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -143,7 +143,7 @@ LL | let _ = a.cast::<()>().le(&b.cast::<()>());
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:46:13
|
--> $DIR/wide_pointer_comparisons.rs:47:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.lt(&b);
|
LL | let _ = a.lt(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -154,7 +154,7 @@ LL | let _ = a.cast::<()>().lt(&b.cast::<()>());
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:48:13
|
--> $DIR/wide_pointer_comparisons.rs:49:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.ge(&b);
|
LL | let _ = a.ge(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -165,7 +165,7 @@ LL | let _ = a.cast::<()>().ge(&b.cast::<()>());
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:50:13
|
--> $DIR/wide_pointer_comparisons.rs:51:13
|
||||||
|
|
|
|
||||||
LL | let _ = a.gt(&b);
|
LL | let _ = a.gt(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -176,7 +176,40 @@ LL | let _ = a.cast::<()>().gt(&b.cast::<()>());
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:58:17
|
--> $DIR/wide_pointer_comparisons.rs:57:17
|
||||||
|
|
|
||||||
|
LL | let _ = a == b;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::addr_eq(a.as_ptr(), b.as_ptr());
|
||||||
|
| ++++++++++++++++++ ~~~~~~~~~~ ++++++++++
|
||||||
|
|
||||||
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
|
--> $DIR/wide_pointer_comparisons.rs:59:17
|
||||||
|
|
|
||||||
|
LL | let _ = a >= b;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
||||||
|
|
|
||||||
|
LL | let _ = a.as_ptr().cast::<()>() >= b.as_ptr().cast::<()>();
|
||||||
|
| ++++++++++++++++++++++ ++++++++++++++++++++++
|
||||||
|
|
||||||
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
|
--> $DIR/wide_pointer_comparisons.rs:61:17
|
||||||
|
|
|
||||||
|
LL | let _ = &a == &b;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::addr_eq(a.as_ptr(), b.as_ptr());
|
||||||
|
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ++++++++++
|
||||||
|
|
||||||
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
|
--> $DIR/wide_pointer_comparisons.rs:70:17
|
||||||
|
|
|
|
||||||
LL | let _ = a == b;
|
LL | let _ = a == b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -187,7 +220,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b);
|
||||||
| +++++++++++++++++++ ~~~ +
|
| +++++++++++++++++++ ~~~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:60:17
|
--> $DIR/wide_pointer_comparisons.rs:72:17
|
||||||
|
|
|
|
||||||
LL | let _ = a != b;
|
LL | let _ = a != b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -198,7 +231,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b);
|
||||||
| ++++++++++++++++++++ ~~~ +
|
| ++++++++++++++++++++ ~~~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:62:17
|
--> $DIR/wide_pointer_comparisons.rs:74:17
|
||||||
|
|
|
|
||||||
LL | let _ = a < b;
|
LL | let _ = a < b;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -209,7 +242,7 @@ LL | let _ = (*a).cast::<()>() < (*b).cast::<()>();
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:64:17
|
--> $DIR/wide_pointer_comparisons.rs:76:17
|
||||||
|
|
|
|
||||||
LL | let _ = a <= b;
|
LL | let _ = a <= b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -220,7 +253,7 @@ LL | let _ = (*a).cast::<()>() <= (*b).cast::<()>();
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:66:17
|
--> $DIR/wide_pointer_comparisons.rs:78:17
|
||||||
|
|
|
|
||||||
LL | let _ = a > b;
|
LL | let _ = a > b;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -231,7 +264,7 @@ LL | let _ = (*a).cast::<()>() > (*b).cast::<()>();
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:68:17
|
--> $DIR/wide_pointer_comparisons.rs:80:17
|
||||||
|
|
|
|
||||||
LL | let _ = a >= b;
|
LL | let _ = a >= b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -242,7 +275,7 @@ LL | let _ = (*a).cast::<()>() >= (*b).cast::<()>();
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:71:17
|
--> $DIR/wide_pointer_comparisons.rs:83:17
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::eq(a, b);
|
LL | let _ = PartialEq::eq(a, b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -253,7 +286,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b);
|
||||||
| ~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
| ~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:73:17
|
--> $DIR/wide_pointer_comparisons.rs:85:17
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::ne(a, b);
|
LL | let _ = PartialEq::ne(a, b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -264,7 +297,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b);
|
||||||
| ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
| ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:75:17
|
--> $DIR/wide_pointer_comparisons.rs:87:17
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::eq(&a, &b);
|
LL | let _ = PartialEq::eq(&a, &b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -275,7 +308,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b);
|
||||||
| ~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
| ~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:77:17
|
--> $DIR/wide_pointer_comparisons.rs:89:17
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::ne(&a, &b);
|
LL | let _ = PartialEq::ne(&a, &b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -286,7 +319,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b);
|
||||||
| ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
| ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:79:17
|
--> $DIR/wide_pointer_comparisons.rs:91:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.eq(b);
|
LL | let _ = a.eq(b);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
@ -297,7 +330,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b);
|
||||||
| +++++++++++++++++++ ~~~ ~
|
| +++++++++++++++++++ ~~~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:81:17
|
--> $DIR/wide_pointer_comparisons.rs:93:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.ne(b);
|
LL | let _ = a.ne(b);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
@ -308,7 +341,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b);
|
||||||
| ++++++++++++++++++++ ~~~ ~
|
| ++++++++++++++++++++ ~~~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:83:17
|
--> $DIR/wide_pointer_comparisons.rs:95:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.cmp(&b);
|
LL | let _ = a.cmp(&b);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -319,7 +352,7 @@ LL | let _ = (*a).cast::<()>().cmp(&(*b).cast::<()>());
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:85:17
|
--> $DIR/wide_pointer_comparisons.rs:97:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.partial_cmp(&b);
|
LL | let _ = a.partial_cmp(&b);
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -330,7 +363,7 @@ LL | let _ = (*a).cast::<()>().partial_cmp(&(*b).cast::<()>());
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:87:17
|
--> $DIR/wide_pointer_comparisons.rs:99:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.le(&b);
|
LL | let _ = a.le(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -341,7 +374,7 @@ LL | let _ = (*a).cast::<()>().le(&(*b).cast::<()>());
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:89:17
|
--> $DIR/wide_pointer_comparisons.rs:101:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.lt(&b);
|
LL | let _ = a.lt(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -352,7 +385,7 @@ LL | let _ = (*a).cast::<()>().lt(&(*b).cast::<()>());
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:91:17
|
--> $DIR/wide_pointer_comparisons.rs:103:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.ge(&b);
|
LL | let _ = a.ge(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -363,7 +396,7 @@ LL | let _ = (*a).cast::<()>().ge(&(*b).cast::<()>());
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:93:17
|
--> $DIR/wide_pointer_comparisons.rs:105:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.gt(&b);
|
LL | let _ = a.gt(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -374,7 +407,7 @@ LL | let _ = (*a).cast::<()>().gt(&(*b).cast::<()>());
|
||||||
| ++ ++++++++++++++ ++ ++++++++++++++
|
| ++ ++++++++++++++ ++ ++++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:98:13
|
--> $DIR/wide_pointer_comparisons.rs:110:13
|
||||||
|
|
|
|
||||||
LL | let _ = s == s;
|
LL | let _ = s == s;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -389,7 +422,7 @@ LL | let _ = std::ptr::eq(s, s);
|
||||||
| +++++++++++++ ~ +
|
| +++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:102:13
|
--> $DIR/wide_pointer_comparisons.rs:114:13
|
||||||
|
|
|
|
||||||
LL | let _ = s == s;
|
LL | let _ = s == s;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -404,7 +437,7 @@ LL | let _ = std::ptr::eq(s, s);
|
||||||
| +++++++++++++ ~ +
|
| +++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:106:17
|
--> $DIR/wide_pointer_comparisons.rs:118:17
|
||||||
|
|
|
|
||||||
LL | let _ = a == b;
|
LL | let _ = a == b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -419,7 +452,7 @@ LL | let _ = std::ptr::eq(a, b);
|
||||||
| +++++++++++++ ~ +
|
| +++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:108:17
|
--> $DIR/wide_pointer_comparisons.rs:120:17
|
||||||
|
|
|
|
||||||
LL | let _ = a != b;
|
LL | let _ = a != b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -434,7 +467,7 @@ LL | let _ = !std::ptr::eq(a, b);
|
||||||
| ++++++++++++++ ~ +
|
| ++++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:110:17
|
--> $DIR/wide_pointer_comparisons.rs:122:17
|
||||||
|
|
|
|
||||||
LL | let _ = a < b;
|
LL | let _ = a < b;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -445,7 +478,7 @@ LL | let _ = a.cast::<()>() < b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:112:17
|
--> $DIR/wide_pointer_comparisons.rs:124:17
|
||||||
|
|
|
|
||||||
LL | let _ = a <= b;
|
LL | let _ = a <= b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -456,7 +489,7 @@ LL | let _ = a.cast::<()>() <= b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:114:17
|
--> $DIR/wide_pointer_comparisons.rs:126:17
|
||||||
|
|
|
|
||||||
LL | let _ = a > b;
|
LL | let _ = a > b;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -467,7 +500,7 @@ LL | let _ = a.cast::<()>() > b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:116:17
|
--> $DIR/wide_pointer_comparisons.rs:128:17
|
||||||
|
|
|
|
||||||
LL | let _ = a >= b;
|
LL | let _ = a >= b;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -478,7 +511,7 @@ LL | let _ = a.cast::<()>() >= b.cast::<()>();
|
||||||
| +++++++++++++ +++++++++++++
|
| +++++++++++++ +++++++++++++
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:119:17
|
--> $DIR/wide_pointer_comparisons.rs:131:17
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::eq(&a, &b);
|
LL | let _ = PartialEq::eq(&a, &b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -493,7 +526,7 @@ LL | let _ = std::ptr::eq(a, b);
|
||||||
| ~~~~~~~~~~~~~ ~ ~
|
| ~~~~~~~~~~~~~ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:121:17
|
--> $DIR/wide_pointer_comparisons.rs:133:17
|
||||||
|
|
|
|
||||||
LL | let _ = PartialEq::ne(&a, &b);
|
LL | let _ = PartialEq::ne(&a, &b);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -508,7 +541,7 @@ LL | let _ = !std::ptr::eq(a, b);
|
||||||
| ~~~~~~~~~~~~~~ ~ ~
|
| ~~~~~~~~~~~~~~ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:123:17
|
--> $DIR/wide_pointer_comparisons.rs:135:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.eq(&b);
|
LL | let _ = a.eq(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -523,7 +556,7 @@ LL | let _ = std::ptr::eq(a, b);
|
||||||
| +++++++++++++ ~ ~
|
| +++++++++++++ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:125:17
|
--> $DIR/wide_pointer_comparisons.rs:137:17
|
||||||
|
|
|
|
||||||
LL | let _ = a.ne(&b);
|
LL | let _ = a.ne(&b);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -538,7 +571,7 @@ LL | let _ = !std::ptr::eq(a, b);
|
||||||
| ++++++++++++++ ~ ~
|
| ++++++++++++++ ~ ~
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:130:9
|
--> $DIR/wide_pointer_comparisons.rs:142:9
|
||||||
|
|
|
|
||||||
LL | &*a == &*b
|
LL | &*a == &*b
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
@ -553,7 +586,7 @@ LL | std::ptr::eq(*a, *b)
|
||||||
| ~~~~~~~~~~~~~ ~ +
|
| ~~~~~~~~~~~~~ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:141:14
|
--> $DIR/wide_pointer_comparisons.rs:153:14
|
||||||
|
|
|
|
||||||
LL | cmp!(a, b);
|
LL | cmp!(a, b);
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -564,7 +597,7 @@ LL | cmp!(std::ptr::addr_eq(a, b));
|
||||||
| ++++++++++++++++++ ~ +
|
| ++++++++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:147:39
|
--> $DIR/wide_pointer_comparisons.rs:159:39
|
||||||
|
|
|
|
||||||
LL | ($a:ident, $b:ident) => { $a == $b }
|
LL | ($a:ident, $b:ident) => { $a == $b }
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -579,7 +612,7 @@ LL | ($a:ident, $b:ident) => { std::ptr::addr_eq($a, $b) }
|
||||||
| ++++++++++++++++++ ~ +
|
| ++++++++++++++++++ ~ +
|
||||||
|
|
||||||
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||||
--> $DIR/wide_pointer_comparisons.rs:157:37
|
--> $DIR/wide_pointer_comparisons.rs:169:37
|
||||||
|
|
|
|
||||||
LL | ($a:expr, $b:expr) => { $a == $b }
|
LL | ($a:expr, $b:expr) => { $a == $b }
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -591,5 +624,5 @@ LL | cmp!(&a, &b);
|
||||||
= help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
= help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
||||||
= note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
warning: 50 warnings emitted
|
warning: 53 warnings emitted
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
//@ compile-flags: -C debug-assertions
|
//@ compile-flags: -C debug-assertions
|
||||||
|
|
||||||
#![feature(strict_provenance, pointer_is_aligned)]
|
#![feature(strict_provenance)]
|
||||||
|
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
struct Misaligner {
|
struct Misaligner {
|
||||||
|
|
|
@ -73,15 +73,15 @@ LL | 5 < String::new();
|
||||||
|
|
|
|
||||||
= help: the trait `PartialOrd<String>` is not implemented for `{integer}`
|
= help: the trait `PartialOrd<String>` is not implemented for `{integer}`
|
||||||
= help: the following other types implement trait `PartialOrd<Rhs>`:
|
= help: the following other types implement trait `PartialOrd<Rhs>`:
|
||||||
|
f128
|
||||||
|
f16
|
||||||
f32
|
f32
|
||||||
f64
|
f64
|
||||||
i128
|
i128
|
||||||
i16
|
i16
|
||||||
i32
|
i32
|
||||||
i64
|
i64
|
||||||
i8
|
and 8 others
|
||||||
isize
|
|
||||||
and 6 others
|
|
||||||
|
|
||||||
error[E0277]: can't compare `{integer}` with `Result<{integer}, _>`
|
error[E0277]: can't compare `{integer}` with `Result<{integer}, _>`
|
||||||
--> $DIR/binops.rs:7:7
|
--> $DIR/binops.rs:7:7
|
||||||
|
@ -91,15 +91,15 @@ LL | 6 == Ok(1);
|
||||||
|
|
|
|
||||||
= help: the trait `PartialEq<Result<{integer}, _>>` is not implemented for `{integer}`
|
= help: the trait `PartialEq<Result<{integer}, _>>` is not implemented for `{integer}`
|
||||||
= help: the following other types implement trait `PartialEq<Rhs>`:
|
= help: the following other types implement trait `PartialEq<Rhs>`:
|
||||||
|
f128
|
||||||
|
f16
|
||||||
f32
|
f32
|
||||||
f64
|
f64
|
||||||
i128
|
i128
|
||||||
i16
|
i16
|
||||||
i32
|
i32
|
||||||
i64
|
i64
|
||||||
i8
|
and 8 others
|
||||||
isize
|
|
||||||
and 6 others
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//@[cfi]compile-flags: -Clto -Ccodegen-units=1
|
//@[cfi]compile-flags: -Clto -Ccodegen-units=1
|
||||||
//@[kcfi]needs-llvm-components: x86
|
//@[kcfi]needs-llvm-components: x86
|
||||||
//@[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi --target x86_64-unknown-none
|
//@[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi --target x86_64-unknown-none
|
||||||
|
//@[kcfi]compile-flags: -C panic=abort
|
||||||
//@[leak]needs-sanitizer-leak
|
//@[leak]needs-sanitizer-leak
|
||||||
//@[leak]compile-flags: -Zsanitizer=leak --cfg leak
|
//@[leak]compile-flags: -Zsanitizer=leak --cfg leak
|
||||||
//@[memory]needs-sanitizer-memory
|
//@[memory]needs-sanitizer-memory
|
||||||
|
|
33
tests/ui/sanitizer/cfi-async-closures.rs
Normal file
33
tests/ui/sanitizer/cfi-async-closures.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Check various forms of dynamic closure calls
|
||||||
|
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ revisions: cfi kcfi
|
||||||
|
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
|
||||||
|
//@ only-linux
|
||||||
|
//@ [cfi] needs-sanitizer-cfi
|
||||||
|
//@ [kcfi] needs-sanitizer-kcfi
|
||||||
|
//@ compile-flags: -C target-feature=-crt-static
|
||||||
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
|
||||||
|
//@ run-pass
|
||||||
|
|
||||||
|
#![feature(async_closure)]
|
||||||
|
#![feature(async_fn_traits)]
|
||||||
|
|
||||||
|
use std::ops::AsyncFn;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn identity<T>(x: T) -> T { x }
|
||||||
|
|
||||||
|
// We can't actually create a `dyn AsyncFn()`, because it's not object-safe, but we should check
|
||||||
|
// that we don't bug out when we encounter one.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let f = identity(async || ());
|
||||||
|
let _ = f.async_call(());
|
||||||
|
let _ = f();
|
||||||
|
let g: Box<dyn FnOnce() -> _> = Box::new(f) as _;
|
||||||
|
let _ = g();
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
// Tests that converting a closure to a function pointer works
|
|
||||||
// The notable thing being tested here is that when the closure does not capture anything,
|
|
||||||
// the call method from its Fn trait takes a ZST representing its environment. The compiler then
|
|
||||||
// uses the assumption that the ZST is non-passed to reify this into a function pointer.
|
|
||||||
//
|
|
||||||
// This checks that the reified function pointer will have the expected alias set at its call-site.
|
|
||||||
|
|
||||||
//@ revisions: cfi kcfi
|
|
||||||
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
|
|
||||||
//@ only-linux
|
|
||||||
//@ [cfi] needs-sanitizer-cfi
|
|
||||||
//@ [kcfi] needs-sanitizer-kcfi
|
|
||||||
//@ compile-flags: -C target-feature=-crt-static
|
|
||||||
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
|
||||||
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
|
||||||
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
|
||||||
//@ run-pass
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let f: &fn() = &((|| ()) as _);
|
|
||||||
f();
|
|
||||||
}
|
|
83
tests/ui/sanitizer/cfi-closures.rs
Normal file
83
tests/ui/sanitizer/cfi-closures.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Check various forms of dynamic closure calls
|
||||||
|
|
||||||
|
//@ revisions: cfi kcfi
|
||||||
|
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
|
||||||
|
//@ only-linux
|
||||||
|
//@ [cfi] needs-sanitizer-cfi
|
||||||
|
//@ [kcfi] needs-sanitizer-kcfi
|
||||||
|
//@ compile-flags: -C target-feature=-crt-static
|
||||||
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
|
||||||
|
//@ compile-flags: --test
|
||||||
|
//@ run-pass
|
||||||
|
|
||||||
|
#![feature(fn_traits)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![feature(cfg_sanitize)]
|
||||||
|
|
||||||
|
fn foo<'a, T>() -> Box<dyn Fn(&'a T) -> &'a T> {
|
||||||
|
Box::new(|x| x)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_fn_with_params() {
|
||||||
|
let x = 3;
|
||||||
|
let f = foo();
|
||||||
|
f(&x);
|
||||||
|
// FIXME remove once drops are working.
|
||||||
|
std::mem::forget(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_fn_trait() {
|
||||||
|
let f: &(dyn Fn()) = &(|| {}) as _;
|
||||||
|
f.call(());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_ptr_cast() {
|
||||||
|
let f: &fn() = &((|| ()) as _);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_fnmut<F: FnMut()>(mut f: F) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_to_fnmut() {
|
||||||
|
let f: &(dyn Fn()) = &(|| {}) as _;
|
||||||
|
use_fnmut(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hrtb_helper(f: &dyn for<'a> Fn(&'a usize)) {
|
||||||
|
f(&10)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hrtb_fn() {
|
||||||
|
hrtb_helper((&|x: &usize| println!("{}", *x)) as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fnonce() {
|
||||||
|
let f: Box<dyn FnOnce()> = Box::new(|| {}) as _;
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_closure<C>(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 {
|
||||||
|
call(f, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// FIXME after KCFI reify support is added, remove this
|
||||||
|
// It will appear to work if you test locally, set -C opt-level=0 to see it fail.
|
||||||
|
#[cfg_attr(sanitize = "kcfi", ignore)]
|
||||||
|
fn closure_addr_taken() {
|
||||||
|
let x = 3i32;
|
||||||
|
let f = || x;
|
||||||
|
let call = Fn::<()>::call;
|
||||||
|
use_closure(call, &f);
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
30
tests/ui/sanitizer/cfi-coroutine.rs
Normal file
30
tests/ui/sanitizer/cfi-coroutine.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Verifies that we can call dynamic coroutines
|
||||||
|
|
||||||
|
//@ revisions: cfi kcfi
|
||||||
|
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
|
||||||
|
//@ only-linux
|
||||||
|
//@ [cfi] needs-sanitizer-cfi
|
||||||
|
//@ [kcfi] needs-sanitizer-kcfi
|
||||||
|
//@ compile-flags: -C target-feature=-crt-static
|
||||||
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
|
||||||
|
//@ compile-flags: --test
|
||||||
|
//@ run-pass
|
||||||
|
|
||||||
|
#![feature(coroutines)]
|
||||||
|
#![feature(coroutine_trait)]
|
||||||
|
|
||||||
|
use std::ops::{Coroutine, CoroutineState};
|
||||||
|
use std::pin::{pin, Pin};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut coro = |x: i32| {
|
||||||
|
yield x;
|
||||||
|
"done"
|
||||||
|
};
|
||||||
|
let mut abstract_coro: Pin<&mut dyn Coroutine<i32,Yield=i32,Return=&'static str>> = pin!(coro);
|
||||||
|
assert_eq!(abstract_coro.as_mut().resume(2), CoroutineState::Yielded(2));
|
||||||
|
assert_eq!(abstract_coro.as_mut().resume(0), CoroutineState::Complete("done"));
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
73
tests/ui/sanitizer/cfi-supertraits.rs
Normal file
73
tests/ui/sanitizer/cfi-supertraits.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#![feature(trait_upcasting)]
|
||||||
|
// Check that super-traits are callable.
|
||||||
|
|
||||||
|
//@ revisions: cfi kcfi
|
||||||
|
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
|
||||||
|
//@ only-linux
|
||||||
|
//@ [cfi] needs-sanitizer-cfi
|
||||||
|
//@ [kcfi] needs-sanitizer-kcfi
|
||||||
|
//@ compile-flags: -C target-feature=-crt-static
|
||||||
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
|
||||||
|
//@ run-pass
|
||||||
|
|
||||||
|
trait Parent1 {
|
||||||
|
type P1;
|
||||||
|
fn p1(&self) -> Self::P1;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Parent2 {
|
||||||
|
type P2;
|
||||||
|
fn p2(&self) -> Self::P2;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Child : Parent1 + Parent2 {
|
||||||
|
type C;
|
||||||
|
fn c(&self) -> Self::C;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Parent1 for Foo {
|
||||||
|
type P1 = u16;
|
||||||
|
fn p1(&self) -> Self::P1 {
|
||||||
|
println!("p1");
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parent2 for Foo {
|
||||||
|
type P2 = u32;
|
||||||
|
fn p2(&self) -> Self::P2 {
|
||||||
|
println!("p2");
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Child for Foo {
|
||||||
|
type C = u8;
|
||||||
|
fn c(&self) -> Self::C {
|
||||||
|
println!("c");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Child can access its own methods and super methods.
|
||||||
|
let x = &Foo as &dyn Child<C=u8,P1=u16,P2=u32>;
|
||||||
|
x.c();
|
||||||
|
x.p1();
|
||||||
|
x.p2();
|
||||||
|
// Parents can be created and access their methods.
|
||||||
|
let y = &Foo as &dyn Parent1<P1=u16>;
|
||||||
|
y.p1();
|
||||||
|
let z = &Foo as &dyn Parent2<P2=u32>;
|
||||||
|
z.p2();
|
||||||
|
// Trait upcasting works
|
||||||
|
let x1 = x as &dyn Parent1<P1=u16>;
|
||||||
|
x1.p1();
|
||||||
|
let x2 = x as &dyn Parent2<P2=u32>;
|
||||||
|
x2.p2();
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
|
||||||
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
//@ [cfi] compile-flags: -Z sanitizer=cfi
|
||||||
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
|
||||||
|
//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
|
||||||
trait Foo {
|
trait Foo {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
|
//~^ ERROR expected a pattern, found an expression
|
||||||
|
//~| ERROR cannot find type `T` in this scope
|
||||||
|
//~| ERROR type and const arguments are not allowed on builtin type `str`
|
||||||
|
//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
error: expected a pattern, found an expression
|
||||||
|
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31
|
||||||
|
|
|
||||||
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `T` in this scope
|
||||||
|
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55
|
||||||
|
|
|
||||||
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error[E0109]: type and const arguments are not allowed on builtin type `str`
|
||||||
|
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
|
||||||
|
|
|
||||||
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
|
| --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ type and const arguments not allowed
|
||||||
|
| |
|
||||||
|
| not allowed on builtin type `str`
|
||||||
|
|
|
||||||
|
help: primitive type `str` doesn't have generic parameters
|
||||||
|
|
|
||||||
|
LL - let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
|
LL + let str::as_bytes;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0533]: expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
|
||||||
|
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:9
|
||||||
|
|
|
||||||
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0109, E0412, E0533.
|
||||||
|
For more information about an error, try `rustc --explain E0109`.
|
|
@ -4,7 +4,7 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![feature(generic_nonzero)]
|
#![feature(generic_nonzero)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned_to)]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue