Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-03-31 05:40:36 +00:00
commit eb8e8c06b6
83 changed files with 1395 additions and 723 deletions

View File

@ -14,7 +14,7 @@ index d0a119c..76fdece 100644
@@ -89,7 +89,6 @@
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
-#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(lazy_cell)]
@ -27,6 +27,6 @@ index d0a119c..76fdece 100644
mod slice;
mod str;
mod str_lossy;
--
--
2.42.1

View File

@ -243,6 +243,7 @@ where
T: Tag,
{
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
fn eq(&self, other: &Self) -> bool {
self.packed == other.packed
}

View File

@ -295,6 +295,8 @@ hir_analysis_not_supported_delegation =
{$descr} is not supported yet
.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_foreign = this is not defined in the current crate because this is a foreign trait

View File

@ -4,7 +4,7 @@
use crate::errors;
use rustc_errors::ErrorGuaranteed;
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::Span;
use rustc_trait_selection::traits::{self, IsFirstInputType};
@ -283,9 +283,14 @@ fn emit_orphan_check_error<'tcx>(
let self_ty = trait_ref.self_ty();
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
let mut sugg = None;
let mut diag = tcx.dcx().create_err(match self_ty.kind() {
ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () },
_ 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 {
let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
// 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 = 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 =
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
match *ty.kind() {
ty::Slice(_) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"slices",
);
if is_foreign {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsForeign { span },
);
} else {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "slices" },
);
}
}
ty::Array(..) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"arrays",
);
if is_foreign {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsForeign { span },
);
} else {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "arrays" },
);
}
}
ty::Tuple(..) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"tuples",
);
if is_foreign {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsForeign { span },
);
} else {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "tuples" },
);
}
}
ty::Alias(ty::Opaque, ..) => {
opaque.push(errors::OnlyCurrentTraitsOpaque { span })
diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
}
ty::RawPtr(ptr_ty, mutbl) => {
if !self_ty.has_param() {
let mut_key = mutbl.prefix_str();
sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
wrapper_span: self_ty_span,
struct_span: full_impl_span.shrink_to_lo(),
mut_key,
ptr_ty,
});
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsPointerSugg {
wrapper_span: self_ty_span,
struct_span: full_impl_span.shrink_to_lo(),
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() {
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)
diag.emit()
}
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
let mut sp = sp;

View File

@ -1376,7 +1376,7 @@ pub struct TyParamSome<'a> {
}
#[derive(Diagnostic)]
pub enum OnlyCurrentTraits<'a> {
pub enum OnlyCurrentTraits {
#[diag(hir_analysis_only_current_traits_outside, code = E0117)]
Outside {
#[primary_span]
@ -1384,18 +1384,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span,
#[note(hir_analysis_only_current_traits_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)]
Primitive {
@ -1404,18 +1392,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span,
#[note(hir_analysis_only_current_traits_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)]
Arbitrary {
@ -1424,18 +1400,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span,
#[note(hir_analysis_only_current_traits_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]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_foreign)]
pub struct OnlyCurrentTraitsForeign {
@ -1477,6 +1440,14 @@ pub struct OnlyCurrentTraitsTy<'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)]
#[multipart_suggestion(
hir_analysis_only_current_traits_pointer_sugg,

View File

@ -1916,18 +1916,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat: &'tcx hir::Pat<'tcx>,
ty: Ty<'tcx>,
) {
struct V<'tcx> {
tcx: TyCtxt<'tcx>,
struct V {
pat_hir_ids: Vec<hir::HirId>,
}
impl<'tcx> Visitor<'tcx> for V<'tcx> {
type NestedFilter = rustc_middle::hir::nested_filter::All;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
impl<'tcx> Visitor<'tcx> for V {
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
self.pat_hir_ids.push(p.hir_id);
hir::intravisit::walk_pat(self, p);
@ -1938,7 +1931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let err = Ty::new_error(self.tcx, guar);
self.write_ty(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);
// Mark all the subpatterns as `{type error}` as well. This allows errors for specific
// subpatterns to be silenced.

View File

@ -1632,11 +1632,13 @@ pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> {
pub ne: &'a str,
pub deref_left: &'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}")]
pub left: Span,
#[suggestion_part(code = ", {deref_right}")]
#[suggestion_part(code = "{l_modifiers}, {deref_right}")]
pub middle: Span,
#[suggestion_part(code = ")")]
#[suggestion_part(code = "{r_modifiers})")]
pub right: Span,
}
@ -1652,11 +1654,13 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
ne: &'a str,
deref_left: &'a str,
deref_right: &'a str,
l_modifiers: &'a str,
r_modifiers: &'a str,
#[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
left: Span,
#[suggestion_part(code = ", {deref_right}")]
#[suggestion_part(code = "{l_modifiers}, {deref_right}")]
middle: Span,
#[suggestion_part(code = ")")]
#[suggestion_part(code = "{r_modifiers})")]
right: Span,
},
#[multipart_suggestion(
@ -1670,13 +1674,15 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
deref_right: &'a str,
paren_left: &'a str,
paren_right: &'a str,
l_modifiers: &'a str,
r_modifiers: &'a str,
#[suggestion_part(code = "({deref_left}")]
left_before: Option<Span>,
#[suggestion_part(code = "{paren_left}.cast::<()>()")]
#[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")]
left_after: Span,
#[suggestion_part(code = "({deref_right}")]
right_before: Option<Span>,
#[suggestion_part(code = "{paren_right}.cast::<()>()")]
#[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")]
right_after: Span,
},
}

View File

@ -670,7 +670,11 @@ fn lint_wide_pointer<'tcx>(
l: &'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;
// here we remove any "implicit" references and count the number
// of them to correctly suggest the right number of deref
@ -678,11 +682,20 @@ fn lint_wide_pointer<'tcx>(
ty = *inner_ty;
refs += 1;
}
match ty.kind() {
ty::RawPtr(ty, _) => (!ty.is_sized(cx.tcx, cx.param_env))
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
_ => None,
}
// get the inner type of a pointer (or akin)
let mut modifiers = String::new();
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
@ -696,10 +709,10 @@ fn lint_wide_pointer<'tcx>(
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;
};
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;
};
@ -724,6 +737,9 @@ fn lint_wide_pointer<'tcx>(
let deref_left = &*"*".repeat(l_ty_refs);
let deref_right = &*"*".repeat(r_ty_refs);
let l_modifiers = &*l_modifiers;
let r_modifiers = &*r_modifiers;
cx.emit_span_lint(
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
e.span,
@ -733,6 +749,8 @@ fn lint_wide_pointer<'tcx>(
ne,
deref_left,
deref_right,
l_modifiers,
r_modifiers,
left,
middle,
right,
@ -743,6 +761,8 @@ fn lint_wide_pointer<'tcx>(
ne,
deref_left,
deref_right,
l_modifiers,
r_modifiers,
left,
middle,
right,
@ -751,6 +771,8 @@ fn lint_wide_pointer<'tcx>(
AmbiguousWidePointerComparisonsAddrSuggestion::Cast {
deref_left,
deref_right,
l_modifiers,
r_modifiers,
paren_left: if l_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()),

View File

@ -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 {
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

View File

@ -1624,6 +1624,13 @@ impl<'tcx> Ty<'tcx> {
#[inline]
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))
}

View File

@ -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 })
if test_val == case_val =>
{
fully_matched = true;
Some(TestBranch::Success)
(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
if test_val == case_val {
fully_matched = true;
Some(TestBranch::Success)
} else {
fully_matched = false;
Some(TestBranch::Failure)
}
}
(

View File

@ -296,10 +296,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
Region::new_anon_bound(self.interner(), self.binder_index, var)
}
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
where
I::Ty: TypeSuperFoldable<I>,
{
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
let kind = match t.kind() {
ty::Infer(i) => match i {
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)
}
fn fold_const(&mut self, c: I::Const) -> I::Const
where
I::Const: TypeSuperFoldable<I>,
{
fn fold_const(&mut self, c: I::Const) -> I::Const {
// We could canonicalize all consts with static types, but the only ones we
// *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() {
ty::ConstKind::Infer(i) => {
// FIXME: we should fold the ty too eventually
match i {
ty::InferConst::Var(vid) => {
assert_eq!(
self.infcx.root_ct_var(vid),
vid,
"region vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_ct_var(vid),
None,
"region vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty())
}
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
ty::InferConst::Fresh(_) => todo!(),
ty::ConstKind::Infer(i) => match i {
ty::InferConst::Var(vid) => {
assert_eq!(
self.infcx.root_ct_var(vid),
vid,
"region vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_ct_var(vid),
None,
"region vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)
}
}
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
ty::InferConst::Fresh(_) => todo!(),
},
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
c.ty(),
ty,
),
CanonicalizeMode::Response { .. } => {
CanonicalVarKind::PlaceholderConst(placeholder, c.ty())
CanonicalVarKind::PlaceholderConst(placeholder, ty)
}
},
ty::ConstKind::Param(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
c.ty(),
ty,
),
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::Unevaluated(_)
| 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()),
}
}
}

View File

@ -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_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort`
session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
session_sanitizers_not_supported = {$us} sanitizers are not supported for this target

View File

@ -145,6 +145,10 @@ pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi;
#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi;
#[derive(Diagnostic)]
#[diag(session_sanitizer_kcfi_requires_panic_abort)]
pub(crate) struct SanitizerKcfiRequiresPanicAbort;
#[derive(Diagnostic)]
#[diag(session_split_lto_unit_requires_lto)]
pub(crate) struct SplitLtoUnitRequiresLto;

View File

@ -1211,6 +1211,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
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.
if sess.is_sanitizer_cfi_enabled()
&& sess.lto() == config::Lto::Fat

View File

@ -10,6 +10,7 @@
use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{
@ -641,9 +642,7 @@ fn encode_ty<'tcx>(
}
// Function types
ty::FnDef(def_id, args)
| ty::Closure(def_id, args)
| ty::CoroutineClosure(def_id, args) => {
ty::FnDef(def_id, args) | ty::Closure(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();
@ -654,6 +653,18 @@ fn encode_ty<'tcx>(
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, ..) => {
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
// 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 self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
instance.args = tcx.mk_args_trait(self_ty, List::empty());
} else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
instance.args = strip_receiver_auto(tcx, instance.args);
} else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
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)
&& let Some(impl_id) = tcx.impl_of_method(instance.def_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()
if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) {
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
&& let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
{
// 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));
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
// 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
// `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
// 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.
// 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
// index value when supertraits are involved.
instance.def = ty::InstanceDef::Virtual(method_id, 0);
let abstract_trait_args =
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);
// 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
// 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.
//
// 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
// based on which vtables we are putting this method into, as there will be more than one
// index value when supertraits are involved.
instance.def = ty::InstanceDef::Virtual(method_id, 0);
let abstract_trait_args =
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);
}
} 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)
}
fn strip_receiver_auto<'tcx>(
tcx: TyCtxt<'tcx>,
args: ty::GenericArgsRef<'tcx>,
) -> ty::GenericArgsRef<'tcx> {
let ty = args.type_at(0);
fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
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 =
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
!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
// into a trait object at some point, but that's not a lot.
tcx.types.unit
};
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
}
}
#[instrument(skip(tcx), ret)]

View File

@ -136,31 +136,21 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
t.super_fold_with(self)
}
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
where
I::Ty: TypeSuperFoldable<I>,
{
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
t.super_fold_with(self)
}
// 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
// lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
// and has no `super_fold_with` method to call.
fn fold_region(&mut self, r: I::Region) -> I::Region {
r
}
fn fold_const(&mut self, c: I::Const) -> I::Const
where
I::Const: TypeSuperFoldable<I>,
{
fn fold_const(&mut self, c: I::Const) -> I::Const {
c.super_fold_with(self)
}
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate
where
I::Predicate: TypeSuperFoldable<I>,
{
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
p.super_fold_with(self)
}
}
@ -185,31 +175,21 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
t.try_super_fold_with(self)
}
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error>
where
I::Ty: TypeSuperFoldable<I>,
{
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> {
t.try_super_fold_with(self)
}
// 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
// lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
// and has no `super_fold_with` method to call.
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
Ok(r)
}
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
where
I::Const: TypeSuperFoldable<I>,
{
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> {
c.try_super_fold_with(self)
}
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error>
where
I::Predicate: TypeSuperFoldable<I>,
{
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
p.try_super_fold_with(self)
}
}
@ -234,10 +214,7 @@ where
Ok(self.fold_binder(t))
}
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never>
where
I::Ty: TypeSuperFoldable<I>,
{
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never> {
Ok(self.fold_ty(t))
}
@ -245,17 +222,11 @@ where
Ok(self.fold_region(r))
}
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never>
where
I::Const: TypeSuperFoldable<I>,
{
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never> {
Ok(self.fold_const(c))
}
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never>
where
I::Predicate: TypeSuperFoldable<I>,
{
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never> {
Ok(self.fold_predicate(p))
}
}

View File

@ -2,13 +2,14 @@ use smallvec::SmallVec;
use std::fmt::Debug;
use std::hash::Hash;
use crate::fold::TypeSuperFoldable;
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{
new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
UniverseIndex,
};
pub trait Interner: Sized {
pub trait Interner: Sized + Copy {
type DefId: Copy + Debug + Hash + Eq;
type AdtDef: Copy + Debug + Hash + Eq;
@ -34,6 +35,7 @@ pub trait Interner: Sized {
+ Into<Self::GenericArg>
+ IntoKind<Kind = TyKind<Self>>
+ TypeSuperVisitable<Self>
+ TypeSuperFoldable<Self>
+ Flags
+ new::Ty<Self>;
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
@ -57,6 +59,7 @@ pub trait Interner: Sized {
+ IntoKind<Kind = ConstKind<Self>>
+ ConstTy<Self>
+ TypeSuperVisitable<Self>
+ TypeSuperFoldable<Self>
+ Flags
+ new::Const<Self>;
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
@ -82,7 +85,13 @@ pub trait Interner: Sized {
type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
// 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 RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;

View File

@ -6,6 +6,8 @@ pub trait Ty<I: Interner<Ty = Self>> {
pub trait Region<I: Interner<Region = 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>> {

View File

@ -198,7 +198,6 @@
#![feature(multiple_supertrait_upcastable)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(pointer_is_aligned)]
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)]
#![feature(slice_internals)]

View File

@ -37,7 +37,7 @@
#![feature(const_trait_impl)]
#![feature(const_str_from_utf8)]
#![feature(panic_update_hook)]
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
#![feature(slice_flatten)]
#![feature(thin_box)]
#![feature(strict_provenance)]

View File

@ -40,10 +40,10 @@
//!
//! ## Examples
//!
//! Consider a situation where we want to log out a value passed to a function.
//! We know the value we're working on implements Debug, but we don't know its
//! 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
//! 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
//! use runtime reflection instead.
//!
@ -51,7 +51,7 @@
//! use std::fmt::Debug;
//! 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) {
//! let value_any = value as &dyn Any;
//!

View File

@ -227,7 +227,7 @@ mod impls {
impl_clone! {
usize u8 u16 u32 u64 u128
isize i8 i16 i32 i64 i128
f32 f64
f16 f32 f64 f128
bool char
}

View File

@ -1493,7 +1493,7 @@ mod impls {
}
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 {
@ -1546,7 +1546,7 @@ mod impls {
}
}
partial_ord_impl! { f32 f64 }
partial_ord_impl! { f16 f32 f64 f128 }
macro_rules! ord_impl {
($($t:ty)*) => ($(

View File

@ -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! { 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! { 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`" }

View File

@ -137,6 +137,7 @@
#![feature(const_heap)]
#![feature(const_hint_assert_unchecked)]
#![feature(const_index_range_slice_index)]
#![feature(const_int_from_str)]
#![feature(const_intrinsic_copy)]
#![feature(const_intrinsic_forget)]
#![feature(const_ipv4)]
@ -228,6 +229,8 @@
#![feature(doc_notable_trait)]
#![feature(effects)]
#![feature(extern_types)]
#![feature(f128)]
#![feature(f16)]
#![feature(freeze_impls)]
#![feature(fundamental)]
#![feature(generic_arg_infer)]

View File

@ -422,7 +422,7 @@ marker_impls! {
Copy for
usize, u8, u16, u32, u64, u128,
isize, i8, i16, i32, i64, i128,
f32, f64,
f16, f32, f64, f128,
bool, char,
{T: ?Sized} *const T,
{T: ?Sized} *mut T,

View File

@ -113,8 +113,9 @@ pub enum IntErrorKind {
impl ParseIntError {
/// Outputs the detailed cause of parsing an integer failing.
#[must_use]
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
#[stable(feature = "int_error_matching", since = "1.55.0")]
pub fn kind(&self) -> &IntErrorKind {
pub const fn kind(&self) -> &IntErrorKind {
&self.kind
}
}

View File

@ -60,32 +60,6 @@ macro_rules! int_impl {
#[stable(feature = "int_bits_const", since = "1.53.0")]
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`.
///
/// # Examples

View File

@ -6,7 +6,6 @@ use crate::ascii;
use crate::hint;
use crate::intrinsics;
use crate::mem;
use crate::ops::{Add, Mul, Sub};
use crate::str::FromStr;
// Used because the `?` operator is not allowed in a const context.
@ -1386,51 +1385,19 @@ pub enum FpCategory {
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 {
($($t:ty)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for $t {
type Err = 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 }
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
/// 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
@ -1438,92 +1405,198 @@ impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
#[doc(hidden)]
#[inline(always)]
#[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
}
fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
use self::IntErrorKind::*;
use self::ParseIntError as PIE;
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]
const fn from_str_radix_panic_ct(_radix: u32) -> ! {
panic!("from_str_radix_int: must lie in the range `[2, 36]`");
}
#[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 }

View File

@ -11,7 +11,6 @@ use crate::ptr;
use crate::str::FromStr;
use crate::ub_checks;
use super::from_str_radix;
use super::{IntErrorKind, ParseIntError};
/// A marker trait for primitive types which can be zero.
@ -804,7 +803,7 @@ macro_rules! nonzero_integer {
impl FromStr for $Ty {
type Err = ParseIntError;
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 {
kind: IntErrorKind::Zero
})

View File

@ -58,33 +58,6 @@ macro_rules! uint_impl {
#[stable(feature = "int_bits_const", since = "1.53.0")]
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`.
///
/// # Examples

View File

@ -1401,8 +1401,6 @@ impl<T: ?Sized> *const T {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
@ -1425,7 +1423,6 @@ impl<T: ?Sized> *const T {
/// underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
@ -1477,7 +1473,6 @@ impl<T: ?Sized> *const T {
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // 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
#[must_use]
#[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")]
pub const fn is_aligned(self) -> bool
where
@ -1522,7 +1517,7 @@ impl<T: ?Sized> *const T {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
@ -1551,7 +1546,7 @@ impl<T: ?Sized> *const T {
/// cannot be stricter aligned than the reference's underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
@ -1600,7 +1595,7 @@ impl<T: ?Sized> *const T {
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
@ -1616,7 +1611,7 @@ impl<T: ?Sized> *const T {
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[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")]
pub const fn is_aligned_to(self, align: usize) -> bool {
if !align.is_power_of_two() {

View File

@ -57,7 +57,7 @@ pub trait Pointee {
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
// in `library/core/src/ptr/metadata.rs`
// 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”.

View File

@ -1660,8 +1660,6 @@ impl<T: ?Sized> *mut T {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
@ -1684,7 +1682,6 @@ impl<T: ?Sized> *mut T {
/// underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_mut_refs)]
///
@ -1711,7 +1708,6 @@ impl<T: ?Sized> *mut T {
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
@ -1738,7 +1734,6 @@ impl<T: ?Sized> *mut T {
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // 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
#[must_use]
#[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")]
pub const fn is_aligned(self) -> bool
where
@ -1783,7 +1778,7 @@ impl<T: ?Sized> *mut T {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
@ -1812,7 +1807,7 @@ impl<T: ?Sized> *mut T {
/// 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_mut_refs)]
///
@ -1838,7 +1833,7 @@ impl<T: ?Sized> *mut T {
/// 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)]
///
/// // On some platforms, the alignment of i32 is less than 4.
@ -1863,7 +1858,7 @@ impl<T: ?Sized> *mut T {
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
@ -1879,7 +1874,7 @@ impl<T: ?Sized> *mut T {
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[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")]
pub const fn is_aligned_to(self, align: usize) -> bool {
if !align.is_power_of_two() {

View File

@ -1288,7 +1288,6 @@ impl<T: ?Sized> NonNull<T> {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
/// use std::ptr::NonNull;
///
/// // On some platforms, the alignment of i32 is less than 4.
@ -1313,7 +1312,6 @@ impl<T: ?Sized> NonNull<T> {
/// underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(non_null_convenience)]
/// #![feature(const_option)]
@ -1343,7 +1341,6 @@ impl<T: ?Sized> NonNull<T> {
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
@ -1369,7 +1366,6 @@ impl<T: ?Sized> NonNull<T> {
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_option)]
/// #![feature(const_nonnull_new)]
@ -1394,7 +1390,7 @@ impl<T: ?Sized> NonNull<T> {
/// ```
///
/// [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")]
#[must_use]
#[inline]
@ -1417,7 +1413,7 @@ impl<T: ?Sized> NonNull<T> {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
@ -1446,7 +1442,7 @@ impl<T: ?Sized> NonNull<T> {
/// cannot be stricter aligned than the reference's underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
@ -1495,7 +1491,7 @@ impl<T: ?Sized> NonNull<T> {
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
@ -1509,7 +1505,7 @@ impl<T: ?Sized> NonNull<T> {
/// ```
///
/// [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")]
#[must_use]
#[inline]

View File

@ -418,14 +418,12 @@ impl AtomicBool {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
/// use std::sync::atomic::{self, AtomicBool};
/// use std::mem::align_of;
///
/// // Get a pointer to an allocated value
/// 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
@ -1216,14 +1214,12 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
/// use std::sync::atomic::{self, AtomicPtr};
/// use std::mem::align_of;
///
/// // Get a pointer to an allocated value
/// 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
@ -2199,14 +2195,12 @@ macro_rules! atomic_int {
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
#[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
/// use std::mem::align_of;
///
/// // Get a pointer to an allocated value
#[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

View File

@ -16,6 +16,7 @@
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_intrinsic_copy)]
#![feature(const_int_from_str)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_nonnull_new)]
#![feature(const_pointer_is_aligned)]
@ -95,7 +96,7 @@
#![feature(const_waker)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(lazy_cell)]

View File

@ -214,6 +214,16 @@ fn test_infallible_try_from_int_error() {
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 {
($fn_name:ident, bool, $target: ty) => {
#[test]

View File

@ -841,11 +841,19 @@ fn ptr_metadata_bounds() {
fn static_assert_expected_bounds_for_metadata<Meta>()
where
// 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]
fn dyn_metadata() {
#[derive(Debug)]

View File

@ -341,7 +341,7 @@
#![feature(panic_can_unwind)]
#![feature(panic_info_message)]
#![feature(panic_internals)]
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
#![feature(portable_simd)]
#![feature(prelude_2024)]
#![feature(ptr_as_uninit)]

View File

@ -571,7 +571,9 @@ pub fn make_tests(
&modified_tests,
&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 {
eprintln!();

View File

@ -1,6 +1,6 @@
//@ignore-target-windows: No libc on Windows
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
#![feature(strict_provenance)]
use core::ptr;

View File

@ -7,7 +7,7 @@
#![crate_type="rlib"]
#![feature(core_intrinsics)]
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
// CHECK-LABEL: is_aligned_to_unchecked
// CHECK: decq

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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() {}

View File

@ -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;
}
}

View File

@ -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,
};
}

View File

@ -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
}

View File

@ -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()
);
}

View File

@ -247,15 +247,15 @@ LL | _ = &&0 == Foo;
|
= help: the trait `PartialEq<Foo>` is not implemented for `&&{integer}`
= help: the following other types implement trait `PartialEq<Rhs>`:
f128
f16
f32
f64
i128
i16
i32
i64
i8
isize
and 6 others
and 8 others
error[E0369]: binary operation `==` cannot be applied to type `Foo`
--> $DIR/binary-op-suggest-deref.rs:60:13

View File

@ -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() {}

View File

@ -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

View File

@ -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
//@ run-pass

View 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 () {}

View 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`.

View File

@ -3,6 +3,7 @@
use std::rc::Rc;
use std::sync::Arc;
use std::cmp::PartialEq;
use std::ptr::NonNull;
struct A;
struct B;
@ -50,6 +51,17 @@ fn main() {
let _ = a.gt(&b);
//~^ 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
let a = &a;

View File

@ -1,5 +1,5 @@
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;
| ^^^^^^
@ -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
--> $DIR/wide_pointer_comparisons.rs:21:13
--> $DIR/wide_pointer_comparisons.rs:22:13
|
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
--> $DIR/wide_pointer_comparisons.rs:23:13
--> $DIR/wide_pointer_comparisons.rs:24:13
|
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
--> $DIR/wide_pointer_comparisons.rs:25:13
--> $DIR/wide_pointer_comparisons.rs:26:13
|
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
--> $DIR/wide_pointer_comparisons.rs:27:13
--> $DIR/wide_pointer_comparisons.rs:28:13
|
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
--> $DIR/wide_pointer_comparisons.rs:29:13
--> $DIR/wide_pointer_comparisons.rs:30:13
|
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
--> $DIR/wide_pointer_comparisons.rs:32:13
--> $DIR/wide_pointer_comparisons.rs:33:13
|
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
--> $DIR/wide_pointer_comparisons.rs:34:13
--> $DIR/wide_pointer_comparisons.rs:35:13
|
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
--> $DIR/wide_pointer_comparisons.rs:36:13
--> $DIR/wide_pointer_comparisons.rs:37:13
|
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
--> $DIR/wide_pointer_comparisons.rs:38:13
--> $DIR/wide_pointer_comparisons.rs:39:13
|
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
--> $DIR/wide_pointer_comparisons.rs:40:13
--> $DIR/wide_pointer_comparisons.rs:41:13
|
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
--> $DIR/wide_pointer_comparisons.rs:42:13
--> $DIR/wide_pointer_comparisons.rs:43:13
|
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
--> $DIR/wide_pointer_comparisons.rs:44:13
--> $DIR/wide_pointer_comparisons.rs:45:13
|
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
--> $DIR/wide_pointer_comparisons.rs:46:13
--> $DIR/wide_pointer_comparisons.rs:47:13
|
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
--> $DIR/wide_pointer_comparisons.rs:48:13
--> $DIR/wide_pointer_comparisons.rs:49:13
|
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
--> $DIR/wide_pointer_comparisons.rs:50:13
--> $DIR/wide_pointer_comparisons.rs:51:13
|
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
--> $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;
| ^^^^^^
@ -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
--> $DIR/wide_pointer_comparisons.rs:60:17
--> $DIR/wide_pointer_comparisons.rs:72:17
|
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
--> $DIR/wide_pointer_comparisons.rs:62:17
--> $DIR/wide_pointer_comparisons.rs:74:17
|
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
--> $DIR/wide_pointer_comparisons.rs:64:17
--> $DIR/wide_pointer_comparisons.rs:76:17
|
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
--> $DIR/wide_pointer_comparisons.rs:66:17
--> $DIR/wide_pointer_comparisons.rs:78:17
|
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
--> $DIR/wide_pointer_comparisons.rs:68:17
--> $DIR/wide_pointer_comparisons.rs:80:17
|
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
--> $DIR/wide_pointer_comparisons.rs:71:17
--> $DIR/wide_pointer_comparisons.rs:83:17
|
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
--> $DIR/wide_pointer_comparisons.rs:73:17
--> $DIR/wide_pointer_comparisons.rs:85:17
|
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
--> $DIR/wide_pointer_comparisons.rs:75:17
--> $DIR/wide_pointer_comparisons.rs:87:17
|
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
--> $DIR/wide_pointer_comparisons.rs:77:17
--> $DIR/wide_pointer_comparisons.rs:89:17
|
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
--> $DIR/wide_pointer_comparisons.rs:79:17
--> $DIR/wide_pointer_comparisons.rs:91:17
|
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
--> $DIR/wide_pointer_comparisons.rs:81:17
--> $DIR/wide_pointer_comparisons.rs:93:17
|
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
--> $DIR/wide_pointer_comparisons.rs:83:17
--> $DIR/wide_pointer_comparisons.rs:95:17
|
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
--> $DIR/wide_pointer_comparisons.rs:85:17
--> $DIR/wide_pointer_comparisons.rs:97:17
|
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
--> $DIR/wide_pointer_comparisons.rs:87:17
--> $DIR/wide_pointer_comparisons.rs:99:17
|
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
--> $DIR/wide_pointer_comparisons.rs:89:17
--> $DIR/wide_pointer_comparisons.rs:101:17
|
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
--> $DIR/wide_pointer_comparisons.rs:91:17
--> $DIR/wide_pointer_comparisons.rs:103:17
|
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
--> $DIR/wide_pointer_comparisons.rs:93:17
--> $DIR/wide_pointer_comparisons.rs:105:17
|
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
--> $DIR/wide_pointer_comparisons.rs:98:13
--> $DIR/wide_pointer_comparisons.rs:110:13
|
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
--> $DIR/wide_pointer_comparisons.rs:102:13
--> $DIR/wide_pointer_comparisons.rs:114:13
|
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
--> $DIR/wide_pointer_comparisons.rs:106:17
--> $DIR/wide_pointer_comparisons.rs:118:17
|
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
--> $DIR/wide_pointer_comparisons.rs:108:17
--> $DIR/wide_pointer_comparisons.rs:120:17
|
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
--> $DIR/wide_pointer_comparisons.rs:110:17
--> $DIR/wide_pointer_comparisons.rs:122:17
|
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
--> $DIR/wide_pointer_comparisons.rs:112:17
--> $DIR/wide_pointer_comparisons.rs:124:17
|
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
--> $DIR/wide_pointer_comparisons.rs:114:17
--> $DIR/wide_pointer_comparisons.rs:126:17
|
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
--> $DIR/wide_pointer_comparisons.rs:116:17
--> $DIR/wide_pointer_comparisons.rs:128:17
|
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
--> $DIR/wide_pointer_comparisons.rs:119:17
--> $DIR/wide_pointer_comparisons.rs:131:17
|
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
--> $DIR/wide_pointer_comparisons.rs:121:17
--> $DIR/wide_pointer_comparisons.rs:133:17
|
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
--> $DIR/wide_pointer_comparisons.rs:123:17
--> $DIR/wide_pointer_comparisons.rs:135:17
|
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
--> $DIR/wide_pointer_comparisons.rs:125:17
--> $DIR/wide_pointer_comparisons.rs:137:17
|
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
--> $DIR/wide_pointer_comparisons.rs:130:9
--> $DIR/wide_pointer_comparisons.rs:142:9
|
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
--> $DIR/wide_pointer_comparisons.rs:141:14
--> $DIR/wide_pointer_comparisons.rs:153:14
|
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
--> $DIR/wide_pointer_comparisons.rs:147:39
--> $DIR/wide_pointer_comparisons.rs:159:39
|
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
--> $DIR/wide_pointer_comparisons.rs:157:37
--> $DIR/wide_pointer_comparisons.rs:169:37
|
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
= 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

View File

@ -1,7 +1,7 @@
//@ run-pass
//@ compile-flags: -C debug-assertions
#![feature(strict_provenance, pointer_is_aligned)]
#![feature(strict_provenance)]
#[repr(packed)]
struct Misaligner {

View File

@ -73,15 +73,15 @@ LL | 5 < String::new();
|
= help: the trait `PartialOrd<String>` is not implemented for `{integer}`
= help: the following other types implement trait `PartialOrd<Rhs>`:
f128
f16
f32
f64
i128
i16
i32
i64
i8
isize
and 6 others
and 8 others
error[E0277]: can't compare `{integer}` with `Result<{integer}, _>`
--> $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 following other types implement trait `PartialEq<Rhs>`:
f128
f16
f32
f64
i128
i16
i32
i64
i8
isize
and 6 others
and 8 others
error: aborting due to 6 previous errors

View File

@ -11,6 +11,7 @@
//@[cfi]compile-flags: -Clto -Ccodegen-units=1
//@[kcfi]needs-llvm-components: x86
//@[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi --target x86_64-unknown-none
//@[kcfi]compile-flags: -C panic=abort
//@[leak]needs-sanitizer-leak
//@[leak]compile-flags: -Zsanitizer=leak --cfg leak
//@[memory]needs-sanitizer-memory

View 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();
}

View File

@ -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();
}

View 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);
}

View File

@ -11,6 +11,7 @@
//@ [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
use std::sync::Arc;

View 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"));
}

View File

@ -9,6 +9,7 @@
//@ [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
use std::marker::PhantomData;

View 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();
}

View File

@ -9,6 +9,7 @@
//@ [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 Foo {

View File

@ -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`
}

View File

@ -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`.

View File

@ -4,7 +4,7 @@
#![allow(dead_code)]
#![feature(generic_nonzero)]
#![feature(never_type)]
#![feature(pointer_is_aligned)]
#![feature(pointer_is_aligned_to)]
#![feature(strict_provenance)]
use std::mem::size_of;