mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Auto merge of #154137 - JonathanBrouwer:rollup-hTMxxjl, r=JonathanBrouwer
Rollup of 5 pull requests Successful merges: - rust-lang/rust#154103 (coretests: Expand ieee754 parsing and printing tests to f16) - rust-lang/rust#152669 (rustc_public: add `vtable_entries()` to `TraitRef`) - rust-lang/rust#153776 (Remove redundant `is_dyn_thread_safe` checks) - rust-lang/rust#154121 (Fix typos and markdown errors) - rust-lang/rust#154126 (refactor(attribute parser): move check_custom_mir to attribute parser)
This commit is contained in:
@@ -169,7 +169,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(classname) = nv.value_as_str() else {
|
let Some(classname) = nv.value_as_str() else {
|
||||||
// `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail
|
// `#[rustc_objc_class = ...]` is expected to be used as an implementation detail
|
||||||
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
|
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
|
||||||
// Use a custom error message instead.
|
// Use a custom error message instead.
|
||||||
cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
|
cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
|
||||||
@@ -201,7 +201,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(methname) = nv.value_as_str() else {
|
let Some(methname) = nv.value_as_str() else {
|
||||||
// `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail
|
// `#[rustc_objc_selector = ...]` is expected to be used as an implementation detail
|
||||||
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
|
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
|
||||||
// Use a custom error message instead.
|
// Use a custom error message instead.
|
||||||
cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
|
cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
use crate::attributes::SingleAttributeParser;
|
use crate::attributes::SingleAttributeParser;
|
||||||
use crate::context::{AcceptContext, Stage};
|
use crate::context::{AcceptContext, Stage};
|
||||||
use crate::parser::ArgParser;
|
use crate::parser::ArgParser;
|
||||||
|
use crate::session_diagnostics;
|
||||||
use crate::target_checking::AllowedTargets;
|
use crate::target_checking::AllowedTargets;
|
||||||
use crate::target_checking::Policy::Allow;
|
use crate::target_checking::Policy::Allow;
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
|||||||
|
|
||||||
let dialect = parse_dialect(cx, dialect, &mut failed);
|
let dialect = parse_dialect(cx, dialect, &mut failed);
|
||||||
let phase = parse_phase(cx, phase, &mut failed);
|
let phase = parse_phase(cx, phase, &mut failed);
|
||||||
|
check_custom_mir(cx, dialect, phase, &mut failed);
|
||||||
|
|
||||||
if failed {
|
if failed {
|
||||||
return None;
|
return None;
|
||||||
@@ -138,3 +140,51 @@ fn parse_phase<S: Stage>(
|
|||||||
|
|
||||||
Some((phase, span))
|
Some((phase, span))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_custom_mir<S: Stage>(
|
||||||
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
|
dialect: Option<(MirDialect, Span)>,
|
||||||
|
phase: Option<(MirPhase, Span)>,
|
||||||
|
failed: &mut bool,
|
||||||
|
) {
|
||||||
|
let attr_span = cx.attr_span;
|
||||||
|
let Some((dialect, dialect_span)) = dialect else {
|
||||||
|
if let Some((_, phase_span)) = phase {
|
||||||
|
*failed = true;
|
||||||
|
cx.emit_err(session_diagnostics::CustomMirPhaseRequiresDialect {
|
||||||
|
attr_span,
|
||||||
|
phase_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
match dialect {
|
||||||
|
MirDialect::Analysis => {
|
||||||
|
if let Some((MirPhase::Optimized, phase_span)) = phase {
|
||||||
|
*failed = true;
|
||||||
|
cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
|
||||||
|
dialect,
|
||||||
|
phase: MirPhase::Optimized,
|
||||||
|
attr_span,
|
||||||
|
dialect_span,
|
||||||
|
phase_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MirDialect::Built => {
|
||||||
|
if let Some((phase, phase_span)) = phase {
|
||||||
|
*failed = true;
|
||||||
|
cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
|
||||||
|
dialect,
|
||||||
|
phase,
|
||||||
|
attr_span,
|
||||||
|
dialect_span,
|
||||||
|
phase_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MirDialect::Runtime => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
};
|
};
|
||||||
use rustc_feature::AttributeTemplate;
|
use rustc_feature::AttributeTemplate;
|
||||||
use rustc_hir::AttrPath;
|
use rustc_hir::AttrPath;
|
||||||
|
use rustc_hir::attrs::{MirDialect, MirPhase};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::spec::TargetTuple;
|
use rustc_target::spec::TargetTuple;
|
||||||
@@ -1023,3 +1024,25 @@ pub(crate) struct UnsupportedInstructionSet<'a> {
|
|||||||
pub instruction_set: Symbol,
|
pub instruction_set: Symbol,
|
||||||
pub current_target: &'a TargetTuple,
|
pub current_target: &'a TargetTuple,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag("`dialect` key required")]
|
||||||
|
pub(crate) struct CustomMirPhaseRequiresDialect {
|
||||||
|
#[primary_span]
|
||||||
|
pub attr_span: Span,
|
||||||
|
#[label("`phase` argument requires a `dialect` argument")]
|
||||||
|
pub phase_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")]
|
||||||
|
pub(crate) struct CustomMirIncompatibleDialectAndPhase {
|
||||||
|
pub dialect: MirDialect,
|
||||||
|
pub phase: MirPhase,
|
||||||
|
#[primary_span]
|
||||||
|
pub attr_span: Span,
|
||||||
|
#[label("this dialect...")]
|
||||||
|
pub dialect_span: Span,
|
||||||
|
#[label("... is not compatible with this phase")]
|
||||||
|
pub phase_span: Span,
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ Date: Sun, 15 Feb 2026 14:06:49 +0000
|
|||||||
Subject: [PATCH] Disable f16 math tests for cranelift
|
Subject: [PATCH] Disable f16 math tests for cranelift
|
||||||
|
|
||||||
---
|
---
|
||||||
coretests/tests/floats/mod.rs | 26 +++++++++++++-------------
|
coretests/tests/num/floats.rs | 26 +++++++++++++-------------
|
||||||
1 file changed, 13 insertions(+), 13 deletions(-)
|
1 file changed, 13 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs
|
diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs
|
||||||
index c61961f8584..d7b4fa20322 100644
|
index c61961f8584..d7b4fa20322 100644
|
||||||
--- a/coretests/tests/floats/mod.rs
|
--- a/coretests/tests/num/floats.rs
|
||||||
+++ b/coretests/tests/floats/mod.rs
|
+++ b/coretests/tests/num/floats.rs
|
||||||
@@ -1534,7 +1534,7 @@ fn s_nan() -> Float {
|
@@ -1534,7 +1534,7 @@ fn s_nan() -> Float {
|
||||||
name: powf,
|
name: powf,
|
||||||
attrs: {
|
attrs: {
|
||||||
@@ -128,6 +128,5 @@ index c61961f8584..d7b4fa20322 100644
|
|||||||
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
|
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
|
||||||
},
|
},
|
||||||
test {
|
test {
|
||||||
--
|
--
|
||||||
2.50.1
|
2.50.1
|
||||||
|
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
None,
|
None,
|
||||||
num_untupled.replace(tupled_arg_tys.len()),
|
num_untupled.replace(tupled_arg_tys.len()),
|
||||||
"Replaced existing num_tupled"
|
"Replaced existing num_untupled"
|
||||||
);
|
);
|
||||||
|
|
||||||
return LocalRef::Place(place);
|
return LocalRef::Place(place);
|
||||||
|
|||||||
@@ -188,53 +188,6 @@ pub fn assert_dyn_send<T: ?Sized + PointeeSized + DynSend>() {}
|
|||||||
pub fn assert_dyn_send_val<T: ?Sized + PointeeSized + DynSend>(_t: &T) {}
|
pub fn assert_dyn_send_val<T: ?Sized + PointeeSized + DynSend>(_t: &T) {}
|
||||||
pub fn assert_dyn_send_sync_val<T: ?Sized + PointeeSized + DynSync + DynSend>(_t: &T) {}
|
pub fn assert_dyn_send_sync_val<T: ?Sized + PointeeSized + DynSync + DynSend>(_t: &T) {}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct FromDyn<T>(T);
|
|
||||||
|
|
||||||
impl<T> FromDyn<T> {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from(val: T) -> Self {
|
|
||||||
// Check that `sync::is_dyn_thread_safe()` is true on creation so we can
|
|
||||||
// implement `Send` and `Sync` for this structure when `T`
|
|
||||||
// implements `DynSend` and `DynSync` respectively.
|
|
||||||
assert!(crate::sync::is_dyn_thread_safe());
|
|
||||||
FromDyn(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn derive<O>(&self, val: O) -> FromDyn<O> {
|
|
||||||
// We already did the check for `sync::is_dyn_thread_safe()` when creating `Self`
|
|
||||||
FromDyn(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
|
|
||||||
unsafe impl<T: DynSend> Send for FromDyn<T> {}
|
|
||||||
|
|
||||||
// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
|
|
||||||
unsafe impl<T: DynSync> Sync for FromDyn<T> {}
|
|
||||||
|
|
||||||
impl<T> std::ops::Deref for FromDyn<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> std::ops::DerefMut for FromDyn<T> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A wrapper to convert a struct that is already a `Send` or `Sync` into
|
// A wrapper to convert a struct that is already a `Send` or `Sync` into
|
||||||
// an instance of `DynSend` and `DynSync`, since the compiler cannot infer
|
// an instance of `DynSend` and `DynSync`, since the compiler cannot infer
|
||||||
// it automatically in some cases. (e.g. Box<dyn Send / Sync>)
|
// it automatically in some cases. (e.g. Box<dyn Send / Sync>)
|
||||||
|
|||||||
@@ -34,7 +34,9 @@
|
|||||||
pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
|
pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use self::lock::{Lock, LockGuard, Mode};
|
pub use self::lock::{Lock, LockGuard, Mode};
|
||||||
pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
|
pub use self::mode::{
|
||||||
|
FromDyn, check_dyn_thread_safe, is_dyn_thread_safe, set_dyn_thread_safe_mode,
|
||||||
|
};
|
||||||
pub use self::parallel::{
|
pub use self::parallel::{
|
||||||
broadcast, par_fns, par_for_each_in, par_join, par_map, parallel_guard, spawn,
|
broadcast, par_fns, par_for_each_in, par_join, par_map, parallel_guard, spawn,
|
||||||
try_par_for_each_in,
|
try_par_for_each_in,
|
||||||
@@ -64,12 +66,20 @@ mod atomic {
|
|||||||
mod mode {
|
mod mode {
|
||||||
use std::sync::atomic::{AtomicU8, Ordering};
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
|
use crate::sync::{DynSend, DynSync};
|
||||||
|
|
||||||
const UNINITIALIZED: u8 = 0;
|
const UNINITIALIZED: u8 = 0;
|
||||||
const DYN_NOT_THREAD_SAFE: u8 = 1;
|
const DYN_NOT_THREAD_SAFE: u8 = 1;
|
||||||
const DYN_THREAD_SAFE: u8 = 2;
|
const DYN_THREAD_SAFE: u8 = 2;
|
||||||
|
|
||||||
static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED);
|
static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED);
|
||||||
|
|
||||||
|
// Whether thread safety is enabled (due to running under multiple threads).
|
||||||
|
#[inline]
|
||||||
|
pub fn check_dyn_thread_safe() -> Option<FromDyn<()>> {
|
||||||
|
is_dyn_thread_safe().then_some(FromDyn(()))
|
||||||
|
}
|
||||||
|
|
||||||
// Whether thread safety is enabled (due to running under multiple threads).
|
// Whether thread safety is enabled (due to running under multiple threads).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_dyn_thread_safe() -> bool {
|
pub fn is_dyn_thread_safe() -> bool {
|
||||||
@@ -99,6 +109,44 @@ pub fn set_dyn_thread_safe_mode(mode: bool) {
|
|||||||
// Check that the mode was either uninitialized or was already set to the requested mode.
|
// Check that the mode was either uninitialized or was already set to the requested mode.
|
||||||
assert!(previous.is_ok() || previous == Err(set));
|
assert!(previous.is_ok() || previous == Err(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct FromDyn<T>(T);
|
||||||
|
|
||||||
|
impl<T> FromDyn<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn derive<O>(&self, val: O) -> FromDyn<O> {
|
||||||
|
// We already did the check for `sync::is_dyn_thread_safe()` when creating `Self`
|
||||||
|
FromDyn(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
|
||||||
|
unsafe impl<T: DynSend> Send for FromDyn<T> {}
|
||||||
|
|
||||||
|
// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
|
||||||
|
unsafe impl<T: DynSync> Sync for FromDyn<T> {}
|
||||||
|
|
||||||
|
impl<T> std::ops::Deref for FromDyn<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::DerefMut for FromDyn<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This makes locks panic if they are already held.
|
/// This makes locks panic if they are already held.
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
|
pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let func = FromDyn::from(func);
|
let func = proof.derive(func);
|
||||||
rustc_thread_pool::spawn(|| {
|
rustc_thread_pool::spawn(|| {
|
||||||
(func.into_inner())();
|
(func.into_inner())();
|
||||||
});
|
});
|
||||||
@@ -73,8 +73,8 @@ pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
|
|||||||
/// Use that for the longest running function for better scheduling.
|
/// Use that for the longest running function for better scheduling.
|
||||||
pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
|
pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
|
||||||
parallel_guard(|guard: &ParallelGuard| {
|
parallel_guard(|guard: &ParallelGuard| {
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let funcs = FromDyn::from(funcs);
|
let funcs = proof.derive(funcs);
|
||||||
rustc_thread_pool::scope(|s| {
|
rustc_thread_pool::scope(|s| {
|
||||||
let Some((first, rest)) = funcs.into_inner().split_at_mut_checked(1) else {
|
let Some((first, rest)) = funcs.into_inner().split_at_mut_checked(1) else {
|
||||||
return;
|
return;
|
||||||
@@ -84,7 +84,7 @@ pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
|
|||||||
// order when using a single thread. This ensures the execution order matches
|
// order when using a single thread. This ensures the execution order matches
|
||||||
// that of a single threaded rustc.
|
// that of a single threaded rustc.
|
||||||
for f in rest.iter_mut().rev() {
|
for f in rest.iter_mut().rev() {
|
||||||
let f = FromDyn::from(f);
|
let f = proof.derive(f);
|
||||||
s.spawn(|_| {
|
s.spawn(|_| {
|
||||||
guard.run(|| (f.into_inner())());
|
guard.run(|| (f.into_inner())());
|
||||||
});
|
});
|
||||||
@@ -108,13 +108,13 @@ pub fn par_join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB
|
|||||||
A: FnOnce() -> RA + DynSend,
|
A: FnOnce() -> RA + DynSend,
|
||||||
B: FnOnce() -> RB + DynSend,
|
B: FnOnce() -> RB + DynSend,
|
||||||
{
|
{
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let oper_a = FromDyn::from(oper_a);
|
let oper_a = proof.derive(oper_a);
|
||||||
let oper_b = FromDyn::from(oper_b);
|
let oper_b = proof.derive(oper_b);
|
||||||
let (a, b) = parallel_guard(|guard| {
|
let (a, b) = parallel_guard(|guard| {
|
||||||
rustc_thread_pool::join(
|
rustc_thread_pool::join(
|
||||||
move || guard.run(move || FromDyn::from(oper_a.into_inner()())),
|
move || guard.run(move || proof.derive(oper_a.into_inner()())),
|
||||||
move || guard.run(move || FromDyn::from(oper_b.into_inner()())),
|
move || guard.run(move || proof.derive(oper_b.into_inner()())),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
(a.unwrap().into_inner(), b.unwrap().into_inner())
|
(a.unwrap().into_inner(), b.unwrap().into_inner())
|
||||||
@@ -127,8 +127,9 @@ fn par_slice<I: DynSend>(
|
|||||||
items: &mut [I],
|
items: &mut [I],
|
||||||
guard: &ParallelGuard,
|
guard: &ParallelGuard,
|
||||||
for_each: impl Fn(&mut I) + DynSync + DynSend,
|
for_each: impl Fn(&mut I) + DynSync + DynSend,
|
||||||
|
proof: FromDyn<()>,
|
||||||
) {
|
) {
|
||||||
let for_each = FromDyn::from(for_each);
|
let for_each = proof.derive(for_each);
|
||||||
let mut items = for_each.derive(items);
|
let mut items = for_each.derive(items);
|
||||||
rustc_thread_pool::scope(|s| {
|
rustc_thread_pool::scope(|s| {
|
||||||
let proof = items.derive(());
|
let proof = items.derive(());
|
||||||
@@ -150,9 +151,9 @@ pub fn par_for_each_in<I: DynSend, T: IntoIterator<Item = I>>(
|
|||||||
for_each: impl Fn(&I) + DynSync + DynSend,
|
for_each: impl Fn(&I) + DynSync + DynSend,
|
||||||
) {
|
) {
|
||||||
parallel_guard(|guard| {
|
parallel_guard(|guard| {
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let mut items: Vec<_> = t.into_iter().collect();
|
let mut items: Vec<_> = t.into_iter().collect();
|
||||||
par_slice(&mut items, guard, |i| for_each(&*i))
|
par_slice(&mut items, guard, |i| for_each(&*i), proof)
|
||||||
} else {
|
} else {
|
||||||
t.into_iter().for_each(|i| {
|
t.into_iter().for_each(|i| {
|
||||||
guard.run(|| for_each(&i));
|
guard.run(|| for_each(&i));
|
||||||
@@ -173,16 +174,21 @@ pub fn try_par_for_each_in<T: IntoIterator, E: DynSend>(
|
|||||||
<T as IntoIterator>::Item: DynSend,
|
<T as IntoIterator>::Item: DynSend,
|
||||||
{
|
{
|
||||||
parallel_guard(|guard| {
|
parallel_guard(|guard| {
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let mut items: Vec<_> = t.into_iter().collect();
|
let mut items: Vec<_> = t.into_iter().collect();
|
||||||
|
|
||||||
let error = Mutex::new(None);
|
let error = Mutex::new(None);
|
||||||
|
|
||||||
par_slice(&mut items, guard, |i| {
|
par_slice(
|
||||||
if let Err(err) = for_each(&*i) {
|
&mut items,
|
||||||
*error.lock() = Some(err);
|
guard,
|
||||||
}
|
|i| {
|
||||||
});
|
if let Err(err) = for_each(&*i) {
|
||||||
|
*error.lock() = Some(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
proof,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(err) = error.into_inner() { Err(err) } else { Ok(()) }
|
if let Some(err) = error.into_inner() { Err(err) } else { Ok(()) }
|
||||||
} else {
|
} else {
|
||||||
@@ -196,15 +202,20 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
|
|||||||
map: impl Fn(I) -> R + DynSync + DynSend,
|
map: impl Fn(I) -> R + DynSync + DynSend,
|
||||||
) -> C {
|
) -> C {
|
||||||
parallel_guard(|guard| {
|
parallel_guard(|guard| {
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let map = FromDyn::from(map);
|
let map = proof.derive(map);
|
||||||
|
|
||||||
let mut items: Vec<(Option<I>, Option<R>)> =
|
let mut items: Vec<(Option<I>, Option<R>)> =
|
||||||
t.into_iter().map(|i| (Some(i), None)).collect();
|
t.into_iter().map(|i| (Some(i), None)).collect();
|
||||||
|
|
||||||
par_slice(&mut items, guard, |i| {
|
par_slice(
|
||||||
i.1 = Some(map(i.0.take().unwrap()));
|
&mut items,
|
||||||
});
|
guard,
|
||||||
|
|i| {
|
||||||
|
i.1 = Some(map(i.0.take().unwrap()));
|
||||||
|
},
|
||||||
|
proof,
|
||||||
|
);
|
||||||
|
|
||||||
items.into_iter().filter_map(|i| i.1).collect()
|
items.into_iter().filter_map(|i| i.1).collect()
|
||||||
} else {
|
} else {
|
||||||
@@ -214,8 +225,8 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn broadcast<R: DynSend>(op: impl Fn(usize) -> R + DynSync) -> Vec<R> {
|
pub fn broadcast<R: DynSend>(op: impl Fn(usize) -> R + DynSync) -> Vec<R> {
|
||||||
if mode::is_dyn_thread_safe() {
|
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||||
let op = FromDyn::from(op);
|
let op = proof.derive(op);
|
||||||
let results = rustc_thread_pool::broadcast(|context| op.derive(op(context.index())));
|
let results = rustc_thread_pool::broadcast(|context| op.derive(op(context.index())));
|
||||||
results.into_iter().map(|r| r.into_inner()).collect()
|
results.into_iter().map(|r| r.into_inner()).collect()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ pub enum DefKind {
|
|||||||
/// These are all represented with the same `ExprKind::Closure` in the AST and HIR,
|
/// These are all represented with the same `ExprKind::Closure` in the AST and HIR,
|
||||||
/// which makes it difficult to distinguish these during def collection. Therefore,
|
/// which makes it difficult to distinguish these during def collection. Therefore,
|
||||||
/// we treat them all the same, and code which needs to distinguish them can match
|
/// we treat them all the same, and code which needs to distinguish them can match
|
||||||
/// or `hir::ClosureKind` or `type_of`.
|
/// on `hir::ClosureKind` or `type_of`.
|
||||||
Closure,
|
Closure,
|
||||||
/// The definition of a synthetic coroutine body created by the lowering of a
|
/// The definition of a synthetic coroutine body created by the lowering of a
|
||||||
/// coroutine-closure, such as an async closure.
|
/// coroutine-closure, such as an async closure.
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
//! This module implements some validity checks for attributes.
|
//! This module lists attribute targets, with conversions from other types.
|
||||||
//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
|
|
||||||
//! attached to items that actually support them and if there are
|
|
||||||
//! conflicts between multiple such attributes attached to the same
|
|
||||||
//! item.
|
|
||||||
|
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,6 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
|||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use rustc_data_structures::defer;
|
use rustc_data_structures::defer;
|
||||||
use rustc_data_structures::sync::FromDyn;
|
|
||||||
use rustc_middle::ty::tls;
|
use rustc_middle::ty::tls;
|
||||||
use rustc_query_impl::break_query_cycles;
|
use rustc_query_impl::break_query_cycles;
|
||||||
|
|
||||||
@@ -191,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
|||||||
|
|
||||||
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
||||||
|
|
||||||
if !sync::is_dyn_thread_safe() {
|
let Some(proof) = sync::check_dyn_thread_safe() else {
|
||||||
return run_in_thread_with_globals(
|
return run_in_thread_with_globals(
|
||||||
thread_stack_size,
|
thread_stack_size,
|
||||||
edition,
|
edition,
|
||||||
@@ -204,9 +203,9 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
|||||||
f(current_gcx, jobserver_proxy)
|
f(current_gcx, jobserver_proxy)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
let current_gcx = FromDyn::from(CurrentGcx::new());
|
let current_gcx = proof.derive(CurrentGcx::new());
|
||||||
let current_gcx2 = current_gcx.clone();
|
let current_gcx2 = current_gcx.clone();
|
||||||
|
|
||||||
let proxy = Proxy::new();
|
let proxy = Proxy::new();
|
||||||
@@ -278,7 +277,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
|||||||
// `Send` in the parallel compiler.
|
// `Send` in the parallel compiler.
|
||||||
rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || {
|
rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || {
|
||||||
rustc_span::with_session_globals(|session_globals| {
|
rustc_span::with_session_globals(|session_globals| {
|
||||||
let session_globals = FromDyn::from(session_globals);
|
let session_globals = proof.derive(session_globals);
|
||||||
builder
|
builder
|
||||||
.build_scoped(
|
.build_scoped(
|
||||||
// Initialize each new worker thread when created.
|
// Initialize each new worker thread when created.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
use rustc_hir::attrs::diagnostic::Directive;
|
use rustc_hir::attrs::diagnostic::Directive;
|
||||||
use rustc_hir::attrs::{
|
use rustc_hir::attrs::{
|
||||||
AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
|
AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
|
||||||
MirDialect, MirPhase, ReprAttr, SanitizerSet,
|
ReprAttr, SanitizerSet,
|
||||||
};
|
};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::LocalModDefId;
|
use rustc_hir::def_id::LocalModDefId;
|
||||||
@@ -212,9 +212,6 @@ fn check_attributes(
|
|||||||
Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
|
Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
|
||||||
self.check_may_dangle(hir_id, *attr_span)
|
self.check_may_dangle(hir_id, *attr_span)
|
||||||
}
|
}
|
||||||
&Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => {
|
|
||||||
self.check_custom_mir(dialect, phase, attr_span)
|
|
||||||
}
|
|
||||||
&Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span}) => {
|
&Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span}) => {
|
||||||
self.check_sanitize(attr_span, on_set | off_set, span, target);
|
self.check_sanitize(attr_span, on_set | off_set, span, target);
|
||||||
},
|
},
|
||||||
@@ -254,6 +251,7 @@ fn check_attributes(
|
|||||||
| AttributeKind::Coverage (..)
|
| AttributeKind::Coverage (..)
|
||||||
| AttributeKind::CrateName { .. }
|
| AttributeKind::CrateName { .. }
|
||||||
| AttributeKind::CrateType(..)
|
| AttributeKind::CrateType(..)
|
||||||
|
| AttributeKind::CustomMir(..)
|
||||||
| AttributeKind::DebuggerVisualizer(..)
|
| AttributeKind::DebuggerVisualizer(..)
|
||||||
| AttributeKind::DefaultLibAllocator
|
| AttributeKind::DefaultLibAllocator
|
||||||
// `#[doc]` is actually a lot more than just doc comments, so is checked below
|
// `#[doc]` is actually a lot more than just doc comments, so is checked below
|
||||||
@@ -1913,48 +1911,6 @@ fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) {
|
|||||||
self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
|
self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_custom_mir(
|
|
||||||
&self,
|
|
||||||
dialect: Option<(MirDialect, Span)>,
|
|
||||||
phase: Option<(MirPhase, Span)>,
|
|
||||||
attr_span: Span,
|
|
||||||
) {
|
|
||||||
let Some((dialect, dialect_span)) = dialect else {
|
|
||||||
if let Some((_, phase_span)) = phase {
|
|
||||||
self.dcx()
|
|
||||||
.emit_err(errors::CustomMirPhaseRequiresDialect { attr_span, phase_span });
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
match dialect {
|
|
||||||
MirDialect::Analysis => {
|
|
||||||
if let Some((MirPhase::Optimized, phase_span)) = phase {
|
|
||||||
self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
|
|
||||||
dialect,
|
|
||||||
phase: MirPhase::Optimized,
|
|
||||||
attr_span,
|
|
||||||
dialect_span,
|
|
||||||
phase_span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MirDialect::Built => {
|
|
||||||
if let Some((phase, phase_span)) = phase {
|
|
||||||
self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
|
|
||||||
dialect,
|
|
||||||
phase,
|
|
||||||
attr_span,
|
|
||||||
dialect_span,
|
|
||||||
phase_span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MirDialect::Runtime => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
MultiSpan, msg,
|
MultiSpan, msg,
|
||||||
};
|
};
|
||||||
use rustc_hir::Target;
|
use rustc_hir::Target;
|
||||||
use rustc_hir::attrs::{MirDialect, MirPhase};
|
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_middle::ty::{MainDefinition, Ty};
|
use rustc_middle::ty::{MainDefinition, Ty};
|
||||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
||||||
@@ -1274,28 +1273,6 @@ pub(crate) struct ReprAlignShouldBeAlignStatic {
|
|||||||
pub item: &'static str,
|
pub item: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("`dialect` key required")]
|
|
||||||
pub(crate) struct CustomMirPhaseRequiresDialect {
|
|
||||||
#[primary_span]
|
|
||||||
pub attr_span: Span,
|
|
||||||
#[label("`phase` argument requires a `dialect` argument")]
|
|
||||||
pub phase_span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")]
|
|
||||||
pub(crate) struct CustomMirIncompatibleDialectAndPhase {
|
|
||||||
pub dialect: MirDialect,
|
|
||||||
pub phase: MirPhase,
|
|
||||||
#[primary_span]
|
|
||||||
pub attr_span: Span,
|
|
||||||
#[label("this dialect...")]
|
|
||||||
pub dialect_span: Span,
|
|
||||||
#[label("... is not compatible with this phase")]
|
|
||||||
pub phase_span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`eii_macro_for` is only valid on functions")]
|
#[diag("`eii_macro_for` is only valid on functions")]
|
||||||
pub(crate) struct EiiImplNotFunction {
|
pub(crate) struct EiiImplNotFunction {
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
|
||||||
ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
|
ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
|
||||||
Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
|
Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
|
||||||
TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
|
TraitDecl, TraitDef, TraitRef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
|
||||||
|
VtblEntry,
|
||||||
};
|
};
|
||||||
use crate::unstable::{RustcInternal, Stable, new_item_kind};
|
use crate::unstable::{RustcInternal, Stable, new_item_kind};
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -838,6 +839,25 @@ pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
|
|||||||
let did = tables[def_id];
|
let did = tables[def_id];
|
||||||
cx.associated_items(did).iter().map(|assoc| assoc.stable(&mut *tables, cx)).collect()
|
cx.associated_items(did).iter().map(|assoc| assoc.stable(&mut *tables, cx)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all vtable entries of a trait.
|
||||||
|
pub(crate) fn vtable_entries(&self, trait_ref: &TraitRef) -> Vec<VtblEntry> {
|
||||||
|
let mut tables = self.tables.borrow_mut();
|
||||||
|
let cx = &*self.cx.borrow();
|
||||||
|
cx.vtable_entries(trait_ref.internal(&mut *tables, cx.tcx))
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.stable(&mut *tables, cx))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the vtable entry at the given index.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the index is out of bounds.
|
||||||
|
pub(crate) fn vtable_entry(&self, trait_ref: &TraitRef, idx: usize) -> Option<VtblEntry> {
|
||||||
|
let mut tables = self.tables.borrow_mut();
|
||||||
|
let cx = &*self.cx.borrow();
|
||||||
|
cx.vtable_entry(trait_ref.internal(&mut *tables, cx.tcx), idx).stable(&mut *tables, cx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A thread local variable that stores a pointer to [`CompilerInterface`].
|
// A thread local variable that stores a pointer to [`CompilerInterface`].
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
use crate::abi::{FnAbi, Layout};
|
use crate::abi::{FnAbi, Layout};
|
||||||
use crate::crate_def::{CrateDef, CrateDefType};
|
use crate::crate_def::{CrateDef, CrateDefType};
|
||||||
use crate::mir::alloc::{AllocId, read_target_int, read_target_uint};
|
use crate::mir::alloc::{AllocId, read_target_int, read_target_uint};
|
||||||
use crate::mir::mono::StaticDef;
|
use crate::mir::mono::{Instance, StaticDef};
|
||||||
use crate::target::MachineInfo;
|
use crate::target::MachineInfo;
|
||||||
use crate::{AssocItems, Filename, IndexedVal, Opaque, ThreadLocalIndex};
|
use crate::{AssocItems, Filename, IndexedVal, Opaque, ThreadLocalIndex};
|
||||||
|
|
||||||
@@ -1440,6 +1440,18 @@ pub fn self_ty(&self) -> Ty {
|
|||||||
};
|
};
|
||||||
self_ty
|
self_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve all vtable entries.
|
||||||
|
pub fn vtable_entries(&self) -> Vec<VtblEntry> {
|
||||||
|
with(|cx| cx.vtable_entries(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the vtable entry at the given index.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the index is out of bounds.
|
||||||
|
pub fn vtable_entry(&self, idx: usize) -> Option<VtblEntry> {
|
||||||
|
with(|cx| cx.vtable_entry(self, idx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
@@ -1656,3 +1668,19 @@ pub fn is_impl_trait_in_trait(&self) -> bool {
|
|||||||
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
|
pub enum VtblEntry {
|
||||||
|
/// destructor of this type (used in vtable header)
|
||||||
|
MetadataDropInPlace,
|
||||||
|
/// layout size of this type (used in vtable header)
|
||||||
|
MetadataSize,
|
||||||
|
/// layout align of this type (used in vtable header)
|
||||||
|
MetadataAlign,
|
||||||
|
/// non-dispatchable associated function that is excluded from trait object
|
||||||
|
Vacant,
|
||||||
|
/// dispatchable associated function
|
||||||
|
Method(Instance),
|
||||||
|
/// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
|
||||||
|
TraitVPtr(TraitRef),
|
||||||
|
}
|
||||||
|
|||||||
@@ -1139,3 +1139,25 @@ fn stable<'cx>(
|
|||||||
crate::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) }
|
crate::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Stable<'tcx> for rustc_middle::ty::VtblEntry<'tcx> {
|
||||||
|
type T = crate::ty::VtblEntry;
|
||||||
|
|
||||||
|
fn stable<'cx>(
|
||||||
|
&self,
|
||||||
|
tables: &mut Tables<'cx, BridgeTys>,
|
||||||
|
cx: &CompilerCtxt<'cx, BridgeTys>,
|
||||||
|
) -> Self::T {
|
||||||
|
use crate::ty::VtblEntry;
|
||||||
|
match self {
|
||||||
|
ty::VtblEntry::MetadataDropInPlace => VtblEntry::MetadataDropInPlace,
|
||||||
|
ty::VtblEntry::MetadataSize => VtblEntry::MetadataSize,
|
||||||
|
ty::VtblEntry::MetadataAlign => VtblEntry::MetadataAlign,
|
||||||
|
ty::VtblEntry::Vacant => VtblEntry::Vacant,
|
||||||
|
ty::VtblEntry::Method(instance) => VtblEntry::Method(instance.stable(tables, cx)),
|
||||||
|
ty::VtblEntry::TraitVPtr(trait_ref) => {
|
||||||
|
VtblEntry::TraitVPtr(trait_ref.stable(tables, cx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder,
|
AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder,
|
||||||
ExistentialTraitRef, FnSig, GenericArgsRef, Instance, InstanceKind, IntrinsicDef, List,
|
ExistentialTraitRef, FnSig, GenericArgsRef, Instance, InstanceKind, IntrinsicDef, List,
|
||||||
PolyFnSig, ScalarInt, TraitDef, TraitRef, Ty, TyCtxt, TyKind, TypeVisitableExt, UintTy,
|
PolyFnSig, ScalarInt, TraitDef, TraitRef, Ty, TyCtxt, TyKind, TypeVisitableExt, UintTy,
|
||||||
ValTree, VariantDef,
|
ValTree, VariantDef, VtblEntry,
|
||||||
};
|
};
|
||||||
use rustc_middle::{mir, ty};
|
use rustc_middle::{mir, ty};
|
||||||
use rustc_session::cstore::ForeignModule;
|
use rustc_session::cstore::ForeignModule;
|
||||||
@@ -757,4 +757,16 @@ pub fn associated_items(&self, def_id: DefId) -> Vec<AssocItem> {
|
|||||||
};
|
};
|
||||||
assoc_items
|
assoc_items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all vtable entries of a trait.
|
||||||
|
pub fn vtable_entries(&self, trait_ref: TraitRef<'tcx>) -> Vec<VtblEntry<'tcx>> {
|
||||||
|
self.tcx.vtable_entries(trait_ref).to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the vtable entry at the given index.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the index is out of bounds.
|
||||||
|
pub fn vtable_entry(&self, trait_ref: TraitRef<'tcx>, idx: usize) -> Option<VtblEntry<'tcx>> {
|
||||||
|
self.vtable_entries(trait_ref).get(idx).copied()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,6 @@ fn $test() $block
|
|||||||
mod const_ptr;
|
mod const_ptr;
|
||||||
mod convert;
|
mod convert;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
mod floats;
|
|
||||||
mod fmt;
|
mod fmt;
|
||||||
mod future;
|
mod future;
|
||||||
mod hash;
|
mod hash;
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
//! IEEE 754 floating point compliance tests
|
||||||
|
//!
|
||||||
|
//! To understand IEEE 754's requirements on a programming language, one must understand that the
|
||||||
|
//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any
|
||||||
|
//! one component. That means the hardware, language, and even libraries are considered part of
|
||||||
|
//! conforming floating point support in a programming environment.
|
||||||
|
//!
|
||||||
|
//! A programming language's duty, accordingly, is:
|
||||||
|
//! 1. offer access to the hardware where the hardware offers support
|
||||||
|
//! 2. provide operations that fulfill the remaining requirements of the standard
|
||||||
|
//! 3. provide the ability to write additional software that can fulfill those requirements
|
||||||
|
//!
|
||||||
|
//! This may be fulfilled in any combination that the language sees fit. However, to claim that
|
||||||
|
//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without
|
||||||
|
//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined
|
||||||
|
//! as complete support for at least one specified floating point type as an "arithmetic" and
|
||||||
|
//! "interchange" format, plus specified type conversions to "external character sequences" and
|
||||||
|
//! integer types.
|
||||||
|
//!
|
||||||
|
//! For our purposes,
|
||||||
|
//! "interchange format" => f16, f32, f64, f128
|
||||||
|
//! "arithmetic format" => f16, f32, f64, f128, and any "soft floats"
|
||||||
|
//! "external character sequence" => str from any float
|
||||||
|
//! "integer format" => {i,u}{8,16,32,64,128}
|
||||||
|
//!
|
||||||
|
//! None of these tests are against Rust's own implementation. They are only tests against the
|
||||||
|
//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests.
|
||||||
|
//! Please consider this carefully when adding, removing, or reorganizing these tests. They are
|
||||||
|
//! here so that it is clear what tests are required by the standard and what can be changed.
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
|
use crate::num::{assert_biteq, float_test};
|
||||||
|
|
||||||
|
/// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
|
||||||
|
/// of the formatting infrastructure, which makes it ideal for testing here.
|
||||||
|
#[track_caller]
|
||||||
|
fn string_roundtrip<T>(x: T) -> T
|
||||||
|
where
|
||||||
|
T: FromStr<Err: fmt::Debug> + fmt::Display,
|
||||||
|
{
|
||||||
|
x.to_string().parse::<T>().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(f128): Tests are disabled while we don't have parsing / printing
|
||||||
|
|
||||||
|
// We must preserve signs on all numbers. That includes zero.
|
||||||
|
// -0 and 0 are == normally, so test bit equality.
|
||||||
|
float_test! {
|
||||||
|
name: preserve_signed_zero,
|
||||||
|
attrs: {
|
||||||
|
const: #[cfg(false)],
|
||||||
|
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||||
|
f128: #[cfg(false)],
|
||||||
|
},
|
||||||
|
test {
|
||||||
|
let neg0 = flt(-0.0);
|
||||||
|
let pos0 = flt(0.0);
|
||||||
|
assert_biteq!(neg0, string_roundtrip(neg0));
|
||||||
|
assert_biteq!(pos0, string_roundtrip(pos0));
|
||||||
|
assert_ne!(neg0.to_bits(), pos0.to_bits());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float_test! {
|
||||||
|
name: preserve_signed_infinity,
|
||||||
|
attrs: {
|
||||||
|
const: #[cfg(false)],
|
||||||
|
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||||
|
f128: #[cfg(false)],
|
||||||
|
},
|
||||||
|
test {
|
||||||
|
let neg_inf = Float::NEG_INFINITY;
|
||||||
|
let pos_inf = Float::INFINITY;
|
||||||
|
assert_biteq!(neg_inf, string_roundtrip(neg_inf));
|
||||||
|
assert_biteq!(pos_inf, string_roundtrip(pos_inf));
|
||||||
|
assert_ne!(neg_inf.to_bits(), pos_inf.to_bits());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float_test! {
|
||||||
|
name: infinity_to_str,
|
||||||
|
attrs: {
|
||||||
|
const: #[cfg(false)],
|
||||||
|
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||||
|
f128: #[cfg(false)],
|
||||||
|
},
|
||||||
|
test {
|
||||||
|
assert!(
|
||||||
|
match Float::INFINITY.to_string().to_lowercase().as_str() {
|
||||||
|
"+infinity" | "infinity" => true,
|
||||||
|
"+inf" | "inf" => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
"Infinity must write to a string as some casing of inf or infinity, with an optional +."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
match Float::NEG_INFINITY.to_string().to_lowercase().as_str() {
|
||||||
|
"-infinity" | "-inf" => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
"Negative Infinity must write to a string as some casing of -inf or -infinity"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float_test! {
|
||||||
|
name: nan_to_str,
|
||||||
|
attrs: {
|
||||||
|
const: #[cfg(false)],
|
||||||
|
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||||
|
f128: #[cfg(false)],
|
||||||
|
},
|
||||||
|
test {
|
||||||
|
assert!(
|
||||||
|
match Float::NAN.to_string().to_lowercase().as_str() {
|
||||||
|
"nan" | "+nan" | "-nan" => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
"NaNs must write to a string as some casing of nan."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float_test! {
|
||||||
|
name: infinity_from_str,
|
||||||
|
attrs: {
|
||||||
|
const: #[cfg(false)],
|
||||||
|
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||||
|
f128: #[cfg(false)],
|
||||||
|
},
|
||||||
|
test {
|
||||||
|
// "+"?("inf"|"infinity") in any case => Infinity
|
||||||
|
assert_biteq!(Float::INFINITY, Float::from_str("infinity").unwrap());
|
||||||
|
assert_biteq!(Float::INFINITY, Float::from_str("inf").unwrap());
|
||||||
|
assert_biteq!(Float::INFINITY, Float::from_str("+infinity").unwrap());
|
||||||
|
assert_biteq!(Float::INFINITY, Float::from_str("+inf").unwrap());
|
||||||
|
// yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd
|
||||||
|
assert_biteq!(Float::INFINITY, Float::from_str("+iNfInItY").unwrap());
|
||||||
|
|
||||||
|
// "-inf"|"-infinity" in any case => Negative Infinity
|
||||||
|
assert_biteq!(Float::NEG_INFINITY, Float::from_str("-infinity").unwrap());
|
||||||
|
assert_biteq!(Float::NEG_INFINITY, Float::from_str("-inf").unwrap());
|
||||||
|
assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INF").unwrap());
|
||||||
|
assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INFinity").unwrap());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float_test! {
|
||||||
|
name: qnan_from_str,
|
||||||
|
attrs: {
|
||||||
|
const: #[cfg(false)],
|
||||||
|
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||||
|
f128: #[cfg(false)],
|
||||||
|
},
|
||||||
|
test {
|
||||||
|
// ("+"|"-"")?"s"?"nan" in any case => qNaN
|
||||||
|
assert!("nan".parse::<Float>().unwrap().is_nan());
|
||||||
|
assert!("-nan".parse::<Float>().unwrap().is_nan());
|
||||||
|
assert!("+nan".parse::<Float>().unwrap().is_nan());
|
||||||
|
assert!("+NAN".parse::<Float>().unwrap().is_nan());
|
||||||
|
assert!("-NaN".parse::<Float>().unwrap().is_nan());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
use std::num::FpCategory as Fp;
|
use std::num::FpCategory as Fp;
|
||||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
use std::ops::{Add, Div, Mul, Rem, Sub};
|
||||||
|
|
||||||
trait TestableFloat: Sized {
|
pub(crate) trait TestableFloat: Sized {
|
||||||
const BITS: u32;
|
const BITS: u32;
|
||||||
/// Unsigned int with the same size, for converting to/from bits.
|
/// Unsigned int with the same size, for converting to/from bits.
|
||||||
type Int;
|
type Int;
|
||||||
@@ -224,7 +224,7 @@ impl TestableFloat for f128 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the tolerance for values of the argument type.
|
/// Determine the tolerance for values of the argument type.
|
||||||
const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
|
pub(crate) const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
|
||||||
T::APPROX
|
T::APPROX
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +232,9 @@ const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
|
|||||||
|
|
||||||
/// Verify that floats are within a tolerance of each other.
|
/// Verify that floats are within a tolerance of each other.
|
||||||
macro_rules! assert_approx_eq {
|
macro_rules! assert_approx_eq {
|
||||||
($a:expr, $b:expr $(,)?) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }};
|
($a:expr, $b:expr $(,)?) => {{
|
||||||
|
assert_approx_eq!($a, $b, $crate::num::floats::lim_for_ty($a))
|
||||||
|
}};
|
||||||
($a:expr, $b:expr, $lim:expr) => {{
|
($a:expr, $b:expr, $lim:expr) => {{
|
||||||
let (a, b) = (&$a, &$b);
|
let (a, b) = (&$a, &$b);
|
||||||
let diff = (*a - *b).abs();
|
let diff = (*a - *b).abs();
|
||||||
@@ -270,8 +272,8 @@ macro_rules! assert_biteq {
|
|||||||
// We rely on the `Float` type being brought in scope by the macros below.
|
// We rely on the `Float` type being brought in scope by the macros below.
|
||||||
l: Float = l,
|
l: Float = l,
|
||||||
r: Float = r,
|
r: Float = r,
|
||||||
lb: <Float as TestableFloat>::Int = l.to_bits(),
|
lb: <Float as $crate::num::floats::TestableFloat>::Int = l.to_bits(),
|
||||||
rb: <Float as TestableFloat>::Int = r.to_bits(),
|
rb: <Float as $crate::num::floats::TestableFloat>::Int = r.to_bits(),
|
||||||
width: usize = ((bits / 4) + 2) as usize,
|
width: usize = ((bits / 4) + 2) as usize,
|
||||||
);
|
);
|
||||||
}};
|
}};
|
||||||
@@ -312,6 +314,7 @@ macro_rules! float_test {
|
|||||||
test $test:block
|
test $test:block
|
||||||
) => {
|
) => {
|
||||||
mod $name {
|
mod $name {
|
||||||
|
#[allow(unused_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -360,6 +363,7 @@ const fn flt (x: Float) -> Float { x }
|
|||||||
|
|
||||||
$( $( #[$const_meta] )+ )?
|
$( $( #[$const_meta] )+ )?
|
||||||
mod const_ {
|
mod const_ {
|
||||||
|
#[allow(unused_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -410,6 +414,9 @@ const fn flt (x: Float) -> Float { x }
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) use assert_biteq;
|
||||||
|
pub(crate) use float_test;
|
||||||
|
|
||||||
float_test! {
|
float_test! {
|
||||||
name: num,
|
name: num,
|
||||||
attrs: {
|
attrs: {
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
//! IEEE 754 floating point compliance tests
|
|
||||||
//!
|
|
||||||
//! To understand IEEE 754's requirements on a programming language, one must understand that the
|
|
||||||
//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any
|
|
||||||
//! one component. That means the hardware, language, and even libraries are considered part of
|
|
||||||
//! conforming floating point support in a programming environment.
|
|
||||||
//!
|
|
||||||
//! A programming language's duty, accordingly, is:
|
|
||||||
//! 1. offer access to the hardware where the hardware offers support
|
|
||||||
//! 2. provide operations that fulfill the remaining requirements of the standard
|
|
||||||
//! 3. provide the ability to write additional software that can fulfill those requirements
|
|
||||||
//!
|
|
||||||
//! This may be fulfilled in any combination that the language sees fit. However, to claim that
|
|
||||||
//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without
|
|
||||||
//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined
|
|
||||||
//! as complete support for at least one specified floating point type as an "arithmetic" and
|
|
||||||
//! "interchange" format, plus specified type conversions to "external character sequences" and
|
|
||||||
//! integer types.
|
|
||||||
//!
|
|
||||||
//! For our purposes,
|
|
||||||
//! "interchange format" => f32, f64
|
|
||||||
//! "arithmetic format" => f32, f64, and any "soft floats"
|
|
||||||
//! "external character sequence" => str from any float
|
|
||||||
//! "integer format" => {i,u}{8,16,32,64,128}
|
|
||||||
//!
|
|
||||||
//! None of these tests are against Rust's own implementation. They are only tests against the
|
|
||||||
//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests.
|
|
||||||
//! Please consider this carefully when adding, removing, or reorganizing these tests. They are
|
|
||||||
//! here so that it is clear what tests are required by the standard and what can be changed.
|
|
||||||
|
|
||||||
use ::core::str::FromStr;
|
|
||||||
|
|
||||||
// IEEE 754 for many tests is applied to specific bit patterns.
|
|
||||||
// These generally are not applicable to NaN, however.
|
|
||||||
macro_rules! assert_biteq {
|
|
||||||
($lhs:expr, $rhs:expr) => {
|
|
||||||
assert_eq!($lhs.to_bits(), $rhs.to_bits())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
|
|
||||||
// of the formatting infrastructure, which makes it ideal for testing here.
|
|
||||||
macro_rules! roundtrip {
|
|
||||||
($f:expr => $t:ty) => {
|
|
||||||
($f).to_string().parse::<$t>().unwrap()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_floats_roundtrip {
|
|
||||||
($f:ident) => {
|
|
||||||
assert_biteq!(f32::$f, roundtrip!(f32::$f => f32));
|
|
||||||
assert_biteq!(f64::$f, roundtrip!(f64::$f => f64));
|
|
||||||
};
|
|
||||||
($f:expr) => {
|
|
||||||
assert_biteq!($f as f32, roundtrip!($f => f32));
|
|
||||||
assert_biteq!($f as f64, roundtrip!($f => f64));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_floats_bitne {
|
|
||||||
($lhs:ident, $rhs:ident) => {
|
|
||||||
assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits());
|
|
||||||
assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits());
|
|
||||||
};
|
|
||||||
($lhs:expr, $rhs:expr) => {
|
|
||||||
assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs));
|
|
||||||
assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// We must preserve signs on all numbers. That includes zero.
|
|
||||||
// -0 and 0 are == normally, so test bit equality.
|
|
||||||
#[test]
|
|
||||||
fn preserve_signed_zero() {
|
|
||||||
assert_floats_roundtrip!(-0.0);
|
|
||||||
assert_floats_roundtrip!(0.0);
|
|
||||||
assert_floats_bitne!(0.0, -0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preserve_signed_infinity() {
|
|
||||||
assert_floats_roundtrip!(INFINITY);
|
|
||||||
assert_floats_roundtrip!(NEG_INFINITY);
|
|
||||||
assert_floats_bitne!(INFINITY, NEG_INFINITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn infinity_to_str() {
|
|
||||||
assert!(match f32::INFINITY.to_string().to_lowercase().as_str() {
|
|
||||||
"+infinity" | "infinity" => true,
|
|
||||||
"+inf" | "inf" => true,
|
|
||||||
_ => false,
|
|
||||||
});
|
|
||||||
assert!(
|
|
||||||
match f64::INFINITY.to_string().to_lowercase().as_str() {
|
|
||||||
"+infinity" | "infinity" => true,
|
|
||||||
"+inf" | "inf" => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
"Infinity must write to a string as some casing of inf or infinity, with an optional +."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn neg_infinity_to_str() {
|
|
||||||
assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() {
|
|
||||||
"-infinity" | "-inf" => true,
|
|
||||||
_ => false,
|
|
||||||
});
|
|
||||||
assert!(
|
|
||||||
match f64::NEG_INFINITY.to_string().to_lowercase().as_str() {
|
|
||||||
"-infinity" | "-inf" => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
"Negative Infinity must write to a string as some casing of -inf or -infinity"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn nan_to_str() {
|
|
||||||
assert!(
|
|
||||||
match f32::NAN.to_string().to_lowercase().as_str() {
|
|
||||||
"nan" | "+nan" | "-nan" => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
"NaNs must write to a string as some casing of nan."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// "+"?("inf"|"infinity") in any case => Infinity
|
|
||||||
#[test]
|
|
||||||
fn infinity_from_str() {
|
|
||||||
assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap());
|
|
||||||
assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap());
|
|
||||||
assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap());
|
|
||||||
assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap());
|
|
||||||
// yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd
|
|
||||||
assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
// "-inf"|"-infinity" in any case => Negative Infinity
|
|
||||||
#[test]
|
|
||||||
fn neg_infinity_from_str() {
|
|
||||||
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap());
|
|
||||||
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap());
|
|
||||||
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap());
|
|
||||||
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ("+"|"-"")?"s"?"nan" in any case => qNaN
|
|
||||||
#[test]
|
|
||||||
fn qnan_from_str() {
|
|
||||||
assert!("nan".parse::<f32>().unwrap().is_nan());
|
|
||||||
assert!("-nan".parse::<f32>().unwrap().is_nan());
|
|
||||||
assert!("+nan".parse::<f32>().unwrap().is_nan());
|
|
||||||
assert!("+NAN".parse::<f32>().unwrap().is_nan());
|
|
||||||
assert!("-NaN".parse::<f32>().unwrap().is_nan());
|
|
||||||
}
|
|
||||||
@@ -25,9 +25,10 @@
|
|||||||
mod carryless_mul;
|
mod carryless_mul;
|
||||||
mod const_from;
|
mod const_from;
|
||||||
mod dec2flt;
|
mod dec2flt;
|
||||||
|
mod float_ieee754_flt2dec_dec2flt;
|
||||||
mod float_iter_sum_identity;
|
mod float_iter_sum_identity;
|
||||||
|
mod floats;
|
||||||
mod flt2dec;
|
mod flt2dec;
|
||||||
mod ieee754;
|
|
||||||
mod int_log;
|
mod int_log;
|
||||||
mod int_sqrt;
|
mod int_sqrt;
|
||||||
mod midpoint;
|
mod midpoint;
|
||||||
@@ -36,6 +37,8 @@
|
|||||||
mod ops;
|
mod ops;
|
||||||
mod wrapping;
|
mod wrapping;
|
||||||
|
|
||||||
|
use floats::{assert_biteq, float_test};
|
||||||
|
|
||||||
/// Adds the attribute to all items in the block.
|
/// Adds the attribute to all items in the block.
|
||||||
macro_rules! cfg_block {
|
macro_rules! cfg_block {
|
||||||
($(#[$attr:meta]{$($it:item)*})*) => {$($(
|
($(#[$attr:meta]{$($it:item)*})*) => {$($(
|
||||||
|
|||||||
@@ -2121,7 +2121,7 @@ fn output_base_name(&self) -> Utf8PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a message to (captured) stdout if `config.verbose` is true.
|
/// Prints a message to (captured) stdout if `config.verbose` is true.
|
||||||
/// The message is also logged to `tracing::debug!` regardles of verbosity.
|
/// The message is also logged to `tracing::debug!` regardless of verbosity.
|
||||||
///
|
///
|
||||||
/// Use `format_args!` as the argument to perform formatting if required.
|
/// Use `format_args!` as the argument to perform formatting if required.
|
||||||
fn logv(&self, message: impl fmt::Display) {
|
fn logv(&self, message: impl fmt::Display) {
|
||||||
@@ -2748,7 +2748,7 @@ fn compare_output(
|
|||||||
return CompareOutcome::Same;
|
return CompareOutcome::Same;
|
||||||
}
|
}
|
||||||
if expected_lines.is_empty() {
|
if expected_lines.is_empty() {
|
||||||
// if we have no lines to check, force a full overwite
|
// if we have no lines to check, force a full overwrite
|
||||||
("", actual)
|
("", actual)
|
||||||
} else {
|
} else {
|
||||||
// this prints/blesses the subset, not the actual
|
// this prints/blesses the subset, not the actual
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
//@ run-pass
|
||||||
|
// Test that users are able to use rustc_public to retrieve vtable info.
|
||||||
|
|
||||||
|
//@ ignore-stage1
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
//@ ignore-remote
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
|
||||||
|
extern crate rustc_middle;
|
||||||
|
extern crate rustc_driver;
|
||||||
|
extern crate rustc_interface;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rustc_public;
|
||||||
|
|
||||||
|
use rustc_public::ty::VtblEntry;
|
||||||
|
use rustc_public::CrateDef;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
const CRATE_NAME: &str = "vtable_test";
|
||||||
|
|
||||||
|
/// This function uses the rustc_public APIs to test the `vtable_entries()`.
|
||||||
|
fn test_vtable_entries() -> ControlFlow<()> {
|
||||||
|
let local_crate = rustc_public::local_crate();
|
||||||
|
let local_impls = local_crate.trait_impls();
|
||||||
|
let child_impl = local_impls
|
||||||
|
.iter()
|
||||||
|
.find(|i| i.trimmed_name() == "<Concrete as Child>")
|
||||||
|
.expect("Could not find <Concrete as Child>");
|
||||||
|
|
||||||
|
let child_trait_ref = child_impl.trait_impl().value;
|
||||||
|
let entries = child_trait_ref.vtable_entries();
|
||||||
|
match &entries[..] {
|
||||||
|
[
|
||||||
|
VtblEntry::MetadataDropInPlace,
|
||||||
|
VtblEntry::MetadataSize,
|
||||||
|
VtblEntry::MetadataAlign,
|
||||||
|
VtblEntry::Method(primary),
|
||||||
|
VtblEntry::Method(secondary),
|
||||||
|
VtblEntry::TraitVPtr(secondary_vptr),
|
||||||
|
VtblEntry::Method(child),
|
||||||
|
] => {
|
||||||
|
assert!(
|
||||||
|
primary.name().contains("primary"),
|
||||||
|
"Expected primary method at index 3"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
secondary.name().contains("secondary"),
|
||||||
|
"Expected secondary method at index 4"
|
||||||
|
);
|
||||||
|
let vptr_str = secondary_vptr.def_id.name();
|
||||||
|
assert!(
|
||||||
|
vptr_str.contains("Secondary"),
|
||||||
|
"Expected Secondary VPtr at index 5"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
child.name().contains("child"),
|
||||||
|
"Expected child method at index 6"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"Unexpected vtable layout for <Concrete as Child>. Found: {:#?}",
|
||||||
|
entries
|
||||||
|
),
|
||||||
|
}
|
||||||
|
let vacant_impl = local_impls
|
||||||
|
.iter()
|
||||||
|
.find(|i| i.trimmed_name() == "<Concrete as WithVacant>")
|
||||||
|
.expect("Could not find <Concrete as WithVacant>");
|
||||||
|
let vacant_trait_ref = vacant_impl.trait_impl().value;
|
||||||
|
let vacant_entries = vacant_trait_ref.vtable_entries();
|
||||||
|
match &vacant_entries[..] {
|
||||||
|
[
|
||||||
|
VtblEntry::MetadataDropInPlace,
|
||||||
|
VtblEntry::MetadataSize,
|
||||||
|
VtblEntry::MetadataAlign,
|
||||||
|
VtblEntry::Method(valid),
|
||||||
|
] => {
|
||||||
|
assert!(valid.name().contains("valid"), "Expected valid method");
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"Unexpected vtable layout for <Concrete as WithVacant>. Found: {:#?}",
|
||||||
|
vacant_entries
|
||||||
|
),
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let path = "vtable_input.rs";
|
||||||
|
generate_input(&path).unwrap();
|
||||||
|
let args = &[
|
||||||
|
"rustc".to_string(),
|
||||||
|
"--crate-type=lib".to_string(),
|
||||||
|
"--crate-name".to_string(),
|
||||||
|
CRATE_NAME.to_string(),
|
||||||
|
path.to_string(),
|
||||||
|
];
|
||||||
|
run!(args, test_vtable_entries).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
|
let mut file = std::fs::File::create(path)?;
|
||||||
|
write!(
|
||||||
|
file,
|
||||||
|
r#"
|
||||||
|
pub struct Concrete;
|
||||||
|
|
||||||
|
pub trait Primary {{
|
||||||
|
fn primary(&self);
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub trait Secondary {{
|
||||||
|
fn secondary(&self);
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub trait Child: Primary + Secondary {{
|
||||||
|
fn child(&self);
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Primary for Concrete {{
|
||||||
|
fn primary(&self) {{}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Secondary for Concrete {{
|
||||||
|
fn secondary(&self) {{}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Child for Concrete {{
|
||||||
|
fn child(&self) {{}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub trait WithVacant {{
|
||||||
|
fn valid(&self);
|
||||||
|
|
||||||
|
fn excluded<T>(&self, meow: T) where Self: Sized;
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl WithVacant for Concrete {{
|
||||||
|
fn valid(&self) {{}}
|
||||||
|
fn excluded<T>(&self, meow: T) {{}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
fn main() {{}}
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
+4
-7
@@ -133,7 +133,7 @@ Runtime panics and error handling generate backtraces to assist in debugging and
|
|||||||
|
|
||||||
This directory was originally meant to contain tests related to time complexity and benchmarking.
|
This directory was originally meant to contain tests related to time complexity and benchmarking.
|
||||||
|
|
||||||
However, only a single test was ever added to this category: https://github.com/rust-lang/rust/pull/32062
|
However, only a single test was ever added to this category: <https://github.com/rust-lang/rust/pull/32062>
|
||||||
|
|
||||||
**FIXME**: It is also unclear what would happen were this test to "fail" - would it cause the test suite to remain stuck on this test for a much greater duration than normal?
|
**FIXME**: It is also unclear what would happen were this test to "fail" - would it cause the test suite to remain stuck on this test for a much greater duration than normal?
|
||||||
|
|
||||||
@@ -694,9 +694,7 @@ This test category revolves around trait objects with `Sized` having illegal ope
|
|||||||
Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html).
|
Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html).
|
||||||
|
|
||||||
## `tests/ui/impl-restriction/`
|
## `tests/ui/impl-restriction/`
|
||||||
Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077
|
Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077](https://github.com/rust-lang/rust/issues/105077).
|
||||||
](https://github.com/rust-lang/rust/issues/105077).
|
|
||||||
|
|
||||||
|
|
||||||
## `tests/ui/impl-trait/`
|
## `tests/ui/impl-trait/`
|
||||||
|
|
||||||
@@ -796,8 +794,7 @@ See [Type Layout | Reference](https://doc.rust-lang.org/reference/type-layout.ht
|
|||||||
|
|
||||||
## `tests/ui/lazy-type-alias/`
|
## `tests/ui/lazy-type-alias/`
|
||||||
|
|
||||||
Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792
|
Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792](https://github.com/rust-lang/rust/issues/112792).
|
||||||
](https://github.com/rust-lang/rust/issues/112792).
|
|
||||||
|
|
||||||
## `tests/ui/lazy-type-alias-impl-trait/`
|
## `tests/ui/lazy-type-alias-impl-trait/`
|
||||||
|
|
||||||
@@ -852,7 +849,7 @@ See:
|
|||||||
|
|
||||||
Tests exercising analysis for unused variables, unreachable statements, functions which are supposed to return a value but do not, as well as values moved elsewhere before they could be used by a function.
|
Tests exercising analysis for unused variables, unreachable statements, functions which are supposed to return a value but do not, as well as values moved elsewhere before they could be used by a function.
|
||||||
|
|
||||||
**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions
|
**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions>
|
||||||
|
|
||||||
## `tests/ui/loop-match`
|
## `tests/ui/loop-match`
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ extend-exclude = [
|
|||||||
# right now. Entries should look like `mipsel = "mipsel"`.
|
# right now. Entries should look like `mipsel = "mipsel"`.
|
||||||
#
|
#
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
|
anser = "anser" # an ANSI parsing package used by rust-analyzer
|
||||||
arange = "arange" # short for A-range
|
arange = "arange" # short for A-range
|
||||||
childs = "childs"
|
childs = "childs"
|
||||||
clonable = "clonable"
|
clonable = "clonable"
|
||||||
@@ -29,10 +30,12 @@ makro = "makro" # deliberate misspelling to avoid `macro` keyword
|
|||||||
misformed = "misformed"
|
misformed = "misformed"
|
||||||
moreso = "moreso"
|
moreso = "moreso"
|
||||||
numer = "numer" # short for numerator, not a typo for "number"
|
numer = "numer" # short for numerator, not a typo for "number"
|
||||||
|
old-skool = "old-skool" # variant spelling of "old-school"
|
||||||
optin = "optin" # short for opt-in
|
optin = "optin" # short for opt-in
|
||||||
publically = "publically"
|
publically = "publically"
|
||||||
rplace = "rplace" # short for R-place
|
rplace = "rplace" # short for R-place
|
||||||
splitted = "splitted"
|
splitted = "splitted"
|
||||||
|
sythetic = "sythetic" # typo in vendored LLVM sources
|
||||||
taits = "taits" # lowercase for TAITs (type alias impl trait)
|
taits = "taits" # lowercase for TAITs (type alias impl trait)
|
||||||
targetting = "targetting"
|
targetting = "targetting"
|
||||||
unparseable = "unparseable"
|
unparseable = "unparseable"
|
||||||
|
|||||||
Reference in New Issue
Block a user