Auto merge of #3306 - rust-lang:rustup-2024-02-19, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
010f029c90
460 changed files with 10180 additions and 3980 deletions
80
Cargo.lock
80
Cargo.lock
|
|
@ -931,43 +931,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.4"
|
||||
version = "0.20.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955"
|
||||
dependencies = [
|
||||
"darling_core 0.14.4",
|
||||
"darling_macro 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8"
|
||||
dependencies = [
|
||||
"darling_core 0.20.5",
|
||||
"darling_macro 0.20.5",
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.4"
|
||||
version = "0.20.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3"
|
||||
checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
|
|
@ -979,22 +955,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.4"
|
||||
version = "0.20.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be"
|
||||
dependencies = [
|
||||
"darling_core 0.14.4",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77"
|
||||
dependencies = [
|
||||
"darling_core 0.20.5",
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
|
@ -1036,33 +1001,33 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.12.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
|
||||
checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.12.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
|
||||
checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
|
||||
dependencies = [
|
||||
"darling 0.14.4",
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.12.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
||||
checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1084,7 +1049,7 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
|
||||
dependencies = [
|
||||
"darling 0.20.5",
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
|
|
@ -6206,11 +6171,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
"windows-core",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ fn start<T: Termination + 'static>(
|
|||
|
||||
static mut NUM: u8 = 6 * 7;
|
||||
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
|
||||
#[allow(static_mut_ref)]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
|
||||
#[allow(static_mut_refs)]
|
||||
static NUM_REF: &'static u8 = unsafe { &NUM };
|
||||
|
||||
unsafe fn zeroed<T>() -> T {
|
||||
|
|
|
|||
|
|
@ -99,8 +99,8 @@ fn start<T: Termination + 'static>(
|
|||
|
||||
static mut NUM: u8 = 6 * 7;
|
||||
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
|
||||
#[allow(static_mut_ref)]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
|
||||
#[allow(static_mut_refs)]
|
||||
static NUM_REF: &'static u8 = unsafe { &NUM };
|
||||
|
||||
macro_rules! assert {
|
||||
|
|
|
|||
|
|
@ -51,5 +51,5 @@ default-features = false
|
|||
features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write"]
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
features = ["Win32_Globalization"]
|
||||
|
|
|
|||
|
|
@ -362,8 +362,11 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for LinkingFailed<'_> {
|
|||
// which by now we have no way to translate.
|
||||
if contains_undefined_ref {
|
||||
diag.note(fluent::codegen_ssa_extern_funcs_not_found)
|
||||
.note(fluent::codegen_ssa_specify_libraries_to_link)
|
||||
.note(fluent::codegen_ssa_use_cargo_directive);
|
||||
.note(fluent::codegen_ssa_specify_libraries_to_link);
|
||||
|
||||
if rustc_session::utils::was_invoked_from_cargo() {
|
||||
diag.note(fluent::codegen_ssa_use_cargo_directive);
|
||||
}
|
||||
}
|
||||
diag
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ tracing = "0.1"
|
|||
version = "0.12"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Storage_FileSystem",
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ impl Lock {
|
|||
&mut overlapped,
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.map_err(|e| {
|
||||
let err = io::Error::from_raw_os_error(e.code().0);
|
||||
debug!("failed acquiring file lock: {}", err);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::sync::Lrc;
|
|||
// Use our fake Send/Sync traits when on not parallel compiler,
|
||||
// so that `OwnedSlice` only implements/requires Send/Sync
|
||||
// for parallel compiler builds.
|
||||
use crate::sync::{Send, Sync};
|
||||
use crate::sync;
|
||||
|
||||
/// An owned slice.
|
||||
///
|
||||
|
|
@ -33,7 +33,7 @@ pub struct OwnedSlice {
|
|||
// \/
|
||||
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
|
||||
#[expect(dead_code)]
|
||||
owner: Lrc<dyn Send + Sync>,
|
||||
owner: Lrc<dyn sync::Send + sync::Sync>,
|
||||
}
|
||||
|
||||
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
|
||||
|
|
@ -60,7 +60,7 @@ pub struct OwnedSlice {
|
|||
/// ```
|
||||
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
|
||||
where
|
||||
O: Send + Sync + 'static,
|
||||
O: sync::Send + sync::Sync + 'static,
|
||||
F: FnOnce(&O) -> &[u8],
|
||||
{
|
||||
try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
|
||||
|
|
@ -71,7 +71,7 @@ where
|
|||
/// See [`slice_owned`] for the infallible version.
|
||||
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
|
||||
where
|
||||
O: Send + Sync + 'static,
|
||||
O: sync::Send + sync::Sync + 'static,
|
||||
F: FnOnce(&O) -> Result<&[u8], E>,
|
||||
{
|
||||
// We wrap the owner of the bytes in, so it doesn't move.
|
||||
|
|
@ -139,11 +139,11 @@ impl Borrow<[u8]> for OwnedSlice {
|
|||
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Send for OwnedSlice {}
|
||||
unsafe impl sync::Send for OwnedSlice {}
|
||||
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Sync for OwnedSlice {}
|
||||
unsafe impl sync::Sync for OwnedSlice {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -866,16 +866,14 @@ cfg_match! {
|
|||
use std::mem;
|
||||
|
||||
use windows::{
|
||||
// FIXME: change back to K32GetProcessMemoryInfo when windows crate
|
||||
// updated to 0.49.0+ to drop dependency on psapi.dll
|
||||
Win32::System::ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
|
||||
Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
|
||||
Win32::System::Threading::GetCurrentProcess,
|
||||
};
|
||||
|
||||
let mut pmc = PROCESS_MEMORY_COUNTERS::default();
|
||||
let pmc_size = mem::size_of_val(&pmc);
|
||||
unsafe {
|
||||
GetProcessMemoryInfo(
|
||||
K32GetProcessMemoryInfo(
|
||||
GetCurrentProcess(),
|
||||
&mut pmc,
|
||||
pmc_size as u32,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ libc = "0.2"
|
|||
# tidy-alphabetical-end
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
features = [
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,22 +1,26 @@
|
|||
Reference of mutable static.
|
||||
You have created a reference to a mutable static.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,edition2024,E0796
|
||||
static mut X: i32 = 23;
|
||||
static mut Y: i32 = 24;
|
||||
|
||||
unsafe {
|
||||
let y = &X;
|
||||
let ref x = X;
|
||||
let (x, y) = (&X, &Y);
|
||||
foo(&X);
|
||||
fn work() {
|
||||
let _val = unsafe { X };
|
||||
}
|
||||
|
||||
fn foo<'a>(_x: &'a i32) {}
|
||||
let x_ref = unsafe { &mut X };
|
||||
work();
|
||||
// The next line has Undefined Behavior!
|
||||
// `x_ref` is a mutable reference and allows no aliases,
|
||||
// but `work` has been reading the reference between
|
||||
// the moment `x_ref` was created and when it was used.
|
||||
// This violates the uniqueness of `x_ref`.
|
||||
*x_ref = 42;
|
||||
```
|
||||
|
||||
Mutable statics can be written to by multiple threads: aliasing violations or
|
||||
data races will cause undefined behavior.
|
||||
A reference to a mutable static has lifetime `'static`. This is very dangerous
|
||||
as it is easy to accidentally overlap the lifetime of that reference with
|
||||
other, conflicting accesses to the same static.
|
||||
|
||||
Reference of mutable static is a hard error from 2024 edition.
|
||||
References to mutable statics are a hard error in the 2024 edition.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ unicode-width = "0.1.4"
|
|||
# tidy-alphabetical-end
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
|
|||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
CloseHandle(self.0);
|
||||
// FIXME can panic here
|
||||
CloseHandle(self.0).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +38,8 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
|
|||
impl Drop for Guard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ReleaseMutex((self.0).0);
|
||||
// FIXME can panic here
|
||||
ReleaseMutex((self.0).0).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
|
|||
expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
|
||||
expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
|
||||
expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
|
||||
|
||||
expand_invalid_fragment_specifier =
|
||||
invalid fragment specifier `{$fragment}`
|
||||
.help = {$help}
|
||||
|
||||
expand_macro_body_stability =
|
||||
macros cannot have body stability attributes
|
||||
.label = invalid body stability attribute
|
||||
|
|
|
|||
|
|
@ -408,3 +408,13 @@ pub struct DuplicateMatcherBinding {
|
|||
#[label(expand_label2)]
|
||||
pub prev: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(expand_invalid_fragment_specifier)]
|
||||
#[help]
|
||||
pub struct InvalidFragmentSpecifier {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub fragment: Ident,
|
||||
pub help: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_span)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::errors;
|
||||
use crate::mbe::macro_parser::count_metavar_decls;
|
||||
use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
|
||||
|
||||
|
|
@ -60,11 +61,11 @@ pub(super) fn parse(
|
|||
Some(&tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => {
|
||||
match trees.next() {
|
||||
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
||||
Some((frag, _)) => {
|
||||
Some((fragment, _)) => {
|
||||
let span = token.span.with_lo(start_sp.lo());
|
||||
|
||||
let kind =
|
||||
token::NonterminalKind::from_symbol(frag.name, || {
|
||||
token::NonterminalKind::from_symbol(fragment.name, || {
|
||||
// FIXME(#85708) - once we properly decode a foreign
|
||||
// crate's `SyntaxContext::root`, then we can replace
|
||||
// this with just `span.edition()`. A
|
||||
|
|
@ -81,14 +82,13 @@ pub(super) fn parse(
|
|||
})
|
||||
.unwrap_or_else(
|
||||
|| {
|
||||
let msg = format!(
|
||||
"invalid fragment specifier `{}`",
|
||||
frag.name
|
||||
sess.dcx().emit_err(
|
||||
errors::InvalidFragmentSpecifier {
|
||||
span,
|
||||
fragment,
|
||||
help: VALID_FRAGMENT_NAMES_MSG.into(),
|
||||
},
|
||||
);
|
||||
sess.dcx()
|
||||
.struct_span_err(span, msg)
|
||||
.with_help(VALID_FRAGMENT_NAMES_MSG)
|
||||
.emit();
|
||||
token::NonterminalKind::Ident
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_errors::DiagnosticBuilder;
|
|||
use rustc_errors::{pluralize, PResult};
|
||||
use rustc_span::hygiene::{LocalExpnId, Transparency};
|
||||
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
|
||||
use rustc_span::{Span, SyntaxContext};
|
||||
use rustc_span::{with_metavar_spans, Span, SyntaxContext};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::mem;
|
||||
|
|
@ -254,7 +254,8 @@ pub(super) fn transcribe<'a>(
|
|||
MatchedTokenTree(tt) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
// without wrapping them into groups.
|
||||
result.push(maybe_use_metavar_location(cx, &stack, sp, tt));
|
||||
let tt = maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker);
|
||||
result.push(tt);
|
||||
}
|
||||
MatchedNonterminal(nt) => {
|
||||
// Other variables are emitted into the output stream as groups with
|
||||
|
|
@ -319,6 +320,17 @@ pub(super) fn transcribe<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Store the metavariable span for this original span into a side table.
|
||||
/// FIXME: Try to put the metavariable span into `SpanData` instead of a side table (#118517).
|
||||
/// An optimal encoding for inlined spans will need to be selected to minimize regressions.
|
||||
/// The side table approach is relatively good, but not perfect due to collisions.
|
||||
/// In particular, collisions happen when token is passed as an argument through several macro
|
||||
/// calls, like in recursive macros.
|
||||
/// The old heuristic below is used to improve spans in case of collisions, but diagnostics are
|
||||
/// still degraded sometimes in those cases.
|
||||
///
|
||||
/// The old heuristic:
|
||||
///
|
||||
/// Usually metavariables `$var` produce interpolated tokens, which have an additional place for
|
||||
/// keeping both the original span and the metavariable span. For `tt` metavariables that's not the
|
||||
/// case however, and there's no place for keeping a second span. So we try to give the single
|
||||
|
|
@ -338,15 +350,12 @@ pub(super) fn transcribe<'a>(
|
|||
/// These are typically used for passing larger amounts of code, and tokens in that code usually
|
||||
/// combine with each other and not with tokens outside of the sequence.
|
||||
/// - The metavariable span comes from a different crate, then we prefer the more local span.
|
||||
///
|
||||
/// FIXME: Find a way to keep both original and metavariable spans for all tokens without
|
||||
/// regressing compilation time too much. Several experiments for adding such spans were made in
|
||||
/// the past (PR #95580, #118517, #118671) and all showed some regressions.
|
||||
fn maybe_use_metavar_location(
|
||||
cx: &ExtCtxt<'_>,
|
||||
stack: &[Frame<'_>],
|
||||
metavar_span: Span,
|
||||
mut metavar_span: Span,
|
||||
orig_tt: &TokenTree,
|
||||
marker: &mut Marker,
|
||||
) -> TokenTree {
|
||||
let undelimited_seq = matches!(
|
||||
stack.last(),
|
||||
|
|
@ -357,18 +366,44 @@ fn maybe_use_metavar_location(
|
|||
..
|
||||
})
|
||||
);
|
||||
if undelimited_seq || cx.source_map().is_imported(metavar_span) {
|
||||
if undelimited_seq {
|
||||
// Do not record metavar spans for tokens from undelimited sequences, for perf reasons.
|
||||
return orig_tt.clone();
|
||||
}
|
||||
|
||||
let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) {
|
||||
Ok(_) => true,
|
||||
Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success
|
||||
};
|
||||
marker.visit_span(&mut metavar_span);
|
||||
let no_collision = match orig_tt {
|
||||
TokenTree::Token(token, ..) => {
|
||||
with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span))
|
||||
}
|
||||
TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| {
|
||||
insert(mspans, dspan.open, metavar_span)
|
||||
&& insert(mspans, dspan.close, metavar_span)
|
||||
&& insert(mspans, dspan.entire(), metavar_span)
|
||||
}),
|
||||
};
|
||||
if no_collision || cx.source_map().is_imported(metavar_span) {
|
||||
return orig_tt.clone();
|
||||
}
|
||||
|
||||
// Setting metavar spans for the heuristic spans gives better opportunities for combining them
|
||||
// with neighboring spans even despite their different syntactic contexts.
|
||||
match orig_tt {
|
||||
TokenTree::Token(Token { kind, span }, spacing) => {
|
||||
let span = metavar_span.with_ctxt(span.ctxt());
|
||||
with_metavar_spans(|mspans| insert(mspans, span, metavar_span));
|
||||
TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
|
||||
}
|
||||
TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
|
||||
let open = metavar_span.shrink_to_lo().with_ctxt(dspan.open.ctxt());
|
||||
let close = metavar_span.shrink_to_hi().with_ctxt(dspan.close.ctxt());
|
||||
let open = metavar_span.with_ctxt(dspan.open.ctxt());
|
||||
let close = metavar_span.with_ctxt(dspan.close.ctxt());
|
||||
with_metavar_spans(|mspans| {
|
||||
insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span)
|
||||
});
|
||||
let dspan = DelimSpan::from_pair(open, close);
|
||||
TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2998,6 +2998,12 @@ impl<'hir> Item<'hir> {
|
|||
ItemId { owner_id: self.owner_id }
|
||||
}
|
||||
|
||||
/// Check if this is an [`ItemKind::Enum`], [`ItemKind::Struct`] or
|
||||
/// [`ItemKind::Union`].
|
||||
pub fn is_adt(&self) -> bool {
|
||||
matches!(self.kind, ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..))
|
||||
}
|
||||
|
||||
expect_methods_self_kind! {
|
||||
expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
|
||||
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ hir_analysis_invalid_union_field =
|
|||
hir_analysis_invalid_union_field_sugg =
|
||||
wrap the field type in `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types
|
||||
|
||||
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
|
||||
.label = const parameter declared here
|
||||
|
||||
|
|
@ -373,19 +375,24 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha
|
|||
hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
|
||||
.label = `#[start]` function is not allowed to be `#[track_caller]`
|
||||
|
||||
hir_analysis_static_mut_ref = reference of mutable static is disallowed
|
||||
.label = reference of mutable static
|
||||
.note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
.suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
|
||||
.suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
|
||||
hir_analysis_static_mut_ref = creating a {$shared} reference to a mutable static
|
||||
.label = {$shared} reference to mutable static
|
||||
.note = {$shared ->
|
||||
[shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
|
||||
*[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
|
||||
}
|
||||
.suggestion = use `addr_of!` instead to create a raw pointer
|
||||
.suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
|
||||
|
||||
hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged
|
||||
.label = shared reference of mutable static
|
||||
.label_mut = mutable reference of mutable static
|
||||
.suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
|
||||
.suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
|
||||
.note = reference of mutable static is a hard error from 2024 edition
|
||||
.why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
hir_analysis_static_mut_refs_lint = creating a {$shared} reference to mutable static is discouraged
|
||||
.label = {$shared} reference to mutable static
|
||||
.suggestion = use `addr_of!` instead to create a raw pointer
|
||||
.suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
|
||||
.note = this will be a hard error in the 2024 edition
|
||||
.why_note = {$shared ->
|
||||
[shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
|
||||
*[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
|
||||
}
|
||||
|
||||
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
|
||||
|
||||
|
|
@ -462,6 +469,7 @@ hir_analysis_unrecognized_atomic_operation =
|
|||
hir_analysis_unrecognized_intrinsic_function =
|
||||
unrecognized intrinsic function: `{$name}`
|
||||
.label = unrecognized intrinsic
|
||||
.help = if you're adding an intrinsic, be sure to update `check_intrinsic_type`
|
||||
|
||||
hir_analysis_unused_associated_type_bounds =
|
||||
unnecessary associated type bound for not object safe associated type
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ use rustc_span::{ErrorGuaranteed, Span};
|
|||
use rustc_trait_selection::traits;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::astconv::{
|
||||
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
|
||||
};
|
||||
use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -238,7 +236,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
&self,
|
||||
hir_ref_id: hir::HirId,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
binding: &ConvertedBinding<'_, 'tcx>,
|
||||
binding: &hir::TypeBinding<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
dup_bindings: &mut FxIndexMap<DefId, Span>,
|
||||
|
|
@ -263,21 +261,20 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
|
||||
let tcx = self.tcx();
|
||||
|
||||
let assoc_kind =
|
||||
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
|
||||
ty::AssocKind::Fn
|
||||
} else if let ConvertedBindingKind::Equality(term) = binding.kind
|
||||
&& let ty::TermKind::Const(_) = term.node.unpack()
|
||||
{
|
||||
ty::AssocKind::Const
|
||||
} else {
|
||||
ty::AssocKind::Type
|
||||
};
|
||||
let assoc_kind = if binding.gen_args.parenthesized
|
||||
== hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
{
|
||||
ty::AssocKind::Fn
|
||||
} else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind {
|
||||
ty::AssocKind::Const
|
||||
} else {
|
||||
ty::AssocKind::Type
|
||||
};
|
||||
|
||||
let candidate = if self.trait_defines_associated_item_named(
|
||||
trait_ref.def_id(),
|
||||
assoc_kind,
|
||||
binding.item_name,
|
||||
binding.ident,
|
||||
) {
|
||||
// Simple case: The assoc item is defined in the current trait.
|
||||
trait_ref
|
||||
|
|
@ -289,14 +286,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
trait_ref.skip_binder().print_only_trait_name(),
|
||||
None,
|
||||
assoc_kind,
|
||||
binding.item_name,
|
||||
binding.ident,
|
||||
path_span,
|
||||
Some(&binding),
|
||||
Some(binding),
|
||||
)?
|
||||
};
|
||||
|
||||
let (assoc_ident, def_scope) =
|
||||
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
|
||||
tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id);
|
||||
|
||||
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
|
||||
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
|
||||
|
|
@ -312,7 +309,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
.dcx()
|
||||
.struct_span_err(
|
||||
binding.span,
|
||||
format!("{} `{}` is private", assoc_item.kind, binding.item_name),
|
||||
format!("{} `{}` is private", assoc_item.kind, binding.ident),
|
||||
)
|
||||
.with_span_label(binding.span, format!("private {}", assoc_item.kind))
|
||||
.emit();
|
||||
|
|
@ -327,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: binding.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: binding.item_name,
|
||||
item_name: binding.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
|
|
@ -390,14 +387,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
{
|
||||
alias_ty
|
||||
} else {
|
||||
return Err(self.tcx().dcx().emit_err(
|
||||
crate::errors::ReturnTypeNotationOnNonRpitit {
|
||||
span: binding.span,
|
||||
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
|
||||
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
|
||||
note: (),
|
||||
},
|
||||
));
|
||||
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
|
||||
span: binding.span,
|
||||
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
|
||||
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
|
||||
note: (),
|
||||
}));
|
||||
};
|
||||
|
||||
// Finally, move the fn return type's bound vars over to account for the early bound
|
||||
|
|
@ -410,9 +405,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
let bound_vars = tcx.late_bound_vars(binding.hir_id);
|
||||
ty::Binder::bind_with_vars(instantiation_output, bound_vars)
|
||||
} else {
|
||||
// Append the generic arguments of the associated type to the `trait_ref`.
|
||||
// Create the generic arguments for the associated type or constant by joining the
|
||||
// parent arguments (the arguments of the trait) and the own arguments (the ones of
|
||||
// the associated item itself) and construct an alias type using them.
|
||||
candidate.map_bound(|trait_ref| {
|
||||
let ident = Ident::new(assoc_item.name, binding.item_name.span);
|
||||
let ident = Ident::new(assoc_item.name, binding.ident.span);
|
||||
let item_segment = hir::PathSegment {
|
||||
ident,
|
||||
hir_id: binding.hir_id,
|
||||
|
|
@ -421,77 +418,82 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
infer_args: false,
|
||||
};
|
||||
|
||||
let args_trait_ref_and_assoc_item = self.create_args_for_associated_item(
|
||||
let alias_args = self.create_args_for_associated_item(
|
||||
path_span,
|
||||
assoc_item.def_id,
|
||||
&item_segment,
|
||||
trait_ref.args,
|
||||
);
|
||||
debug!(?alias_args);
|
||||
|
||||
debug!(?args_trait_ref_and_assoc_item);
|
||||
|
||||
ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item)
|
||||
// Note that we're indeed also using `AliasTy` (alias *type*) for associated
|
||||
// *constants* to represent *const projections*. Alias *term* would be a more
|
||||
// appropriate name but alas.
|
||||
ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
|
||||
})
|
||||
};
|
||||
|
||||
if !speculative {
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref or assoc_item. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
if let ConvertedBindingKind::Equality(ty) = binding.kind {
|
||||
let late_bound_in_trait_ref =
|
||||
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
|
||||
debug!(?late_bound_in_trait_ref);
|
||||
debug!(?late_bound_in_ty);
|
||||
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
self.validate_late_bound_regions(
|
||||
late_bound_in_trait_ref,
|
||||
late_bound_in_ty,
|
||||
|br_name| {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name,
|
||||
br_name
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
|
||||
return Err(self.tcx().dcx().emit_err(
|
||||
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
|
||||
));
|
||||
hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
|
||||
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
|
||||
span: binding.span,
|
||||
}));
|
||||
}
|
||||
ConvertedBindingKind::Equality(term) => {
|
||||
hir::TypeBindingKind::Equality { term } => {
|
||||
let term = match term {
|
||||
hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
|
||||
hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
|
||||
};
|
||||
|
||||
if !speculative {
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref or assoc_item. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
let late_bound_in_projection_ty =
|
||||
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
||||
let late_bound_in_term =
|
||||
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term));
|
||||
debug!(?late_bound_in_projection_ty);
|
||||
debug!(?late_bound_in_term);
|
||||
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
// NOTE(associated_const_equality): This error should be impossible to trigger
|
||||
// with associated const equality bounds.
|
||||
self.validate_late_bound_regions(
|
||||
late_bound_in_projection_ty,
|
||||
late_bound_in_term,
|
||||
|br_name| {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.ident,
|
||||
br_name
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
// the "projection predicate" for:
|
||||
//
|
||||
// `<T as Iterator>::Item = u32`
|
||||
bounds.push_projection_bound(
|
||||
tcx,
|
||||
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
|
||||
projection_ty,
|
||||
term: term.node,
|
||||
}),
|
||||
projection_ty
|
||||
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
|
||||
binding.span,
|
||||
);
|
||||
}
|
||||
ConvertedBindingKind::Constraint(ast_bounds) => {
|
||||
hir::TypeBindingKind::Constraint { bounds: ast_bounds } => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
|
||||
//
|
||||
// `<T as Iterator>::Item: Debug`
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::astconv::{AstConv, ConvertedBindingKind};
|
||||
use crate::astconv::AstConv;
|
||||
use crate::errors::{
|
||||
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
||||
ParenthesizedFnTraitExpansion,
|
||||
|
|
@ -111,7 +111,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
assoc_kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
|
||||
binding: Option<&hir::TypeBinding<'tcx>>,
|
||||
) -> ErrorGuaranteed
|
||||
where
|
||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
|
|
@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
None,
|
||||
) && suggested_name != assoc_name.name
|
||||
{
|
||||
// We suggested constraining a type parameter, but the associated type on it
|
||||
// We suggested constraining a type parameter, but the associated item on it
|
||||
// was also not an exact match, so we also suggest changing it.
|
||||
err.span_suggestion_verbose(
|
||||
assoc_name.span,
|
||||
|
|
@ -258,16 +258,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
|
||||
// If we still couldn't find any associated type, and only one associated type exists,
|
||||
// If we still couldn't find any associated item, and only one associated item exists,
|
||||
// suggests using it.
|
||||
if let [candidate_name] = all_candidate_names.as_slice() {
|
||||
// this should still compile, except on `#![feature(associated_type_defaults)]`
|
||||
// where it could suggests `type A = Self::A`, thus recursing infinitely
|
||||
let applicability = if tcx.features().associated_type_defaults {
|
||||
Applicability::Unspecified
|
||||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
// This should still compile, except on `#![feature(associated_type_defaults)]`
|
||||
// where it could suggests `type A = Self::A`, thus recursing infinitely.
|
||||
let applicability =
|
||||
if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults {
|
||||
Applicability::Unspecified
|
||||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
|
||||
span: assoc_name.span,
|
||||
|
|
@ -289,13 +290,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
assoc_kind: ty::AssocKind,
|
||||
ident: Ident,
|
||||
span: Span,
|
||||
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
|
||||
binding: Option<&hir::TypeBinding<'tcx>>,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
|
||||
&& let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Constraint(_) = binding.kind
|
||||
&& let hir::TypeBindingKind::Constraint { .. } = binding.kind
|
||||
{
|
||||
let lo = if binding.gen_args.span_ext.is_dummy() {
|
||||
ident.span
|
||||
|
|
@ -309,25 +310,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
|
||||
let wrap_in_braces_sugg = if let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Equality(term) = binding.kind
|
||||
&& let ty::TermKind::Ty(ty) = term.node.unpack()
|
||||
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind
|
||||
&& let ty = self.ast_ty_to_ty(hir_ty)
|
||||
&& (ty.is_enum() || ty.references_error())
|
||||
&& tcx.features().associated_const_equality
|
||||
{
|
||||
Some(errors::AssocKindMismatchWrapInBracesSugg {
|
||||
lo: term.span.shrink_to_lo(),
|
||||
hi: term.span.shrink_to_hi(),
|
||||
lo: hir_ty.span.shrink_to_lo(),
|
||||
hi: hir_ty.span.shrink_to_hi(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
|
||||
// one can argue that that's more “untuitive” to the user.
|
||||
// one can argue that that's more “intuitive” to the user.
|
||||
let (span, expected_because_label, expected, got) = if let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Equality(term) = binding.kind
|
||||
&& let hir::TypeBindingKind::Equality { term } = binding.kind
|
||||
{
|
||||
(term.span, Some(ident.span), assoc_item.kind, assoc_kind)
|
||||
let span = match term {
|
||||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(ct) => tcx.def_span(ct.def_id),
|
||||
};
|
||||
(span, Some(ident.span), assoc_item.kind, assoc_kind)
|
||||
} else {
|
||||
(ident.span, None, assoc_kind, assoc_item.kind)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
|
|
@ -151,21 +150,6 @@ pub trait AstConv<'tcx> {
|
|||
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConvertedBinding<'a, 'tcx> {
|
||||
hir_id: hir::HirId,
|
||||
item_name: Ident,
|
||||
kind: ConvertedBindingKind<'a, 'tcx>,
|
||||
gen_args: &'tcx GenericArgs<'tcx>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ConvertedBindingKind<'a, 'tcx> {
|
||||
Equality(Spanned<ty::Term<'tcx>>),
|
||||
Constraint(&'a [hir::GenericBound<'tcx>]),
|
||||
}
|
||||
|
||||
/// New-typed boolean indicating whether explicit late-bound lifetimes
|
||||
/// are present in a set of generic arguments.
|
||||
///
|
||||
|
|
@ -316,7 +300,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
/// Given the type/lifetime/const arguments provided to some path (along with
|
||||
/// an implicit `Self`, if this is a trait reference), returns the complete
|
||||
/// set of generic arguments. This may involve applying defaulted type parameters.
|
||||
/// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`.
|
||||
///
|
||||
/// Constraints on associated types are not converted here but
|
||||
/// separately in `add_predicates_for_ast_type_binding`.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
|
|
@ -329,8 +315,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
/// 2. The path in question is the path to the trait `std::ops::Index`,
|
||||
/// which will have been resolved to a `def_id`
|
||||
/// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
|
||||
/// parameters are returned in the `GenericArgsRef`, the associated type bindings like
|
||||
/// `Output = u32` are returned from `create_assoc_bindings_for_generic_args`.
|
||||
/// parameters are returned in the `GenericArgsRef`
|
||||
/// 4. Associated type bindings like `Output = u32` are contained in `generic_args.bindings`.
|
||||
///
|
||||
/// Note that the type listing given here is *exactly* what the user provided.
|
||||
///
|
||||
|
|
@ -591,52 +577,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
(args, arg_count)
|
||||
}
|
||||
|
||||
fn create_assoc_bindings_for_generic_args<'a>(
|
||||
&self,
|
||||
generic_args: &'a hir::GenericArgs<'tcx>,
|
||||
) -> Vec<ConvertedBinding<'a, 'tcx>> {
|
||||
// Convert associated-type bindings or constraints into a separate vector.
|
||||
// Example: Given this:
|
||||
//
|
||||
// T: Iterator<Item = u32>
|
||||
//
|
||||
// The `T` is passed in as a self-type; the `Item = u32` is
|
||||
// not a "type parameter" of the `Iterator` trait, but rather
|
||||
// a restriction on `<T as Iterator>::Item`, so it is passed
|
||||
// back separately.
|
||||
let assoc_bindings = generic_args
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
let kind = match &binding.kind {
|
||||
hir::TypeBindingKind::Equality { term } => match term {
|
||||
hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan(
|
||||
ty.span,
|
||||
self.ast_ty_to_ty(ty).into(),
|
||||
)),
|
||||
hir::Term::Const(c) => {
|
||||
let span = self.tcx().def_span(c.def_id);
|
||||
let c = Const::from_anon_const(self.tcx(), c.def_id);
|
||||
ConvertedBindingKind::Equality(respan(span, c.into()))
|
||||
}
|
||||
},
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
ConvertedBindingKind::Constraint(bounds)
|
||||
}
|
||||
};
|
||||
ConvertedBinding {
|
||||
hir_id: binding.hir_id,
|
||||
item_name: binding.ident,
|
||||
kind,
|
||||
gen_args: binding.gen_args,
|
||||
span: binding.span,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
assoc_bindings
|
||||
}
|
||||
|
||||
pub fn create_args_for_associated_item(
|
||||
&self,
|
||||
span: Span,
|
||||
|
|
@ -742,18 +682,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
|
||||
debug!(?bound_vars);
|
||||
|
||||
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
|
||||
|
||||
let poly_trait_ref = ty::Binder::bind_with_vars(
|
||||
ty::TraitRef::new(tcx, trait_def_id, generic_args),
|
||||
bound_vars,
|
||||
);
|
||||
|
||||
debug!(?poly_trait_ref, ?assoc_bindings);
|
||||
debug!(?poly_trait_ref);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
|
||||
|
||||
let mut dup_bindings = FxIndexMap::default();
|
||||
for binding in &assoc_bindings {
|
||||
for binding in args.bindings {
|
||||
// Don't register additional associated type bounds for negative bounds,
|
||||
// since we should have emitten an error for them earlier, and they will
|
||||
// not be well-formed!
|
||||
|
|
@ -1029,7 +967,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
assoc_kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
binding: Option<&ConvertedBinding<'_, 'tcx>>,
|
||||
binding: Option<&hir::TypeBinding<'tcx>>,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
|
||||
where
|
||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
|
|
@ -1069,7 +1007,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// Provide a more specific error code index entry for equality bindings.
|
||||
err.code(
|
||||
if let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Equality(_) = binding.kind
|
||||
&& let hir::TypeBindingKind::Equality { .. } = binding.kind
|
||||
{
|
||||
E0222
|
||||
} else {
|
||||
|
|
@ -1094,16 +1032,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
);
|
||||
if let Some(binding) = binding {
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(term) => {
|
||||
hir::TypeBindingKind::Equality { term } => {
|
||||
let term: ty::Term<'_> = match term {
|
||||
hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
ty::Const::from_anon_const(tcx, ct.def_id).into()
|
||||
}
|
||||
};
|
||||
// FIXME(#97583): This isn't syntactically well-formed!
|
||||
where_bounds.push(format!(
|
||||
" T: {trait}::{assoc_name} = {term}",
|
||||
trait = bound.print_only_trait_path(),
|
||||
term = term.node,
|
||||
));
|
||||
}
|
||||
// FIXME: Provide a suggestion.
|
||||
ConvertedBindingKind::Constraint(_bounds) => {}
|
||||
hir::TypeBindingKind::Constraint { bounds: _ } => {}
|
||||
}
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@ use super::compare_impl_item::check_type_bounds;
|
|||
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
|
||||
use super::*;
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::{codes::*, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_errors::{codes::*, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::Node;
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
|
||||
|
|
@ -129,17 +128,20 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
|
|||
for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
|
||||
let field_ty = tcx.type_of(field.did).instantiate_identity();
|
||||
if let Some(adt) = field_ty.ty_adt_def()
|
||||
&& !adt.is_anonymous()
|
||||
&& !adt.repr().c()
|
||||
&& !adt.is_enum()
|
||||
{
|
||||
let field_ty_span = tcx.def_span(adt.did());
|
||||
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
|
||||
span: tcx.def_span(field.did),
|
||||
field_ty_span,
|
||||
field_ty,
|
||||
field_adt_kind: adt.descr(),
|
||||
sugg_span: field_ty_span.shrink_to_lo(),
|
||||
});
|
||||
if !adt.is_anonymous() && !adt.repr().c() {
|
||||
let field_ty_span = tcx.def_span(adt.did());
|
||||
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
|
||||
span: tcx.def_span(field.did),
|
||||
field_ty_span,
|
||||
field_ty,
|
||||
field_adt_kind: adt.descr(),
|
||||
sugg_span: field_ty_span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir_pretty::qpath_to_string;
|
||||
use rustc_lint_defs::builtin::STATIC_MUT_REF;
|
||||
use rustc_lint_defs::builtin::STATIC_MUT_REFS;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::Mutability;
|
||||
|
|
@ -66,32 +66,24 @@ fn handle_static_mut_ref(
|
|||
hir_id: hir::HirId,
|
||||
) {
|
||||
if e2024 {
|
||||
let sugg = if mutable {
|
||||
errors::StaticMutRefSugg::Mut { span, var }
|
||||
let (sugg, shared) = if mutable {
|
||||
(errors::StaticMutRefSugg::Mut { span, var }, "mutable")
|
||||
} else {
|
||||
errors::StaticMutRefSugg::Shared { span, var }
|
||||
(errors::StaticMutRefSugg::Shared { span, var }, "shared")
|
||||
};
|
||||
tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg });
|
||||
tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
|
||||
return;
|
||||
}
|
||||
|
||||
let (label, sugg, shared) = if mutable {
|
||||
(
|
||||
errors::RefOfMutStaticLabel::Mut { span },
|
||||
errors::RefOfMutStaticSugg::Mut { span, var },
|
||||
"mutable ",
|
||||
)
|
||||
let (sugg, shared) = if mutable {
|
||||
(errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
|
||||
} else {
|
||||
(
|
||||
errors::RefOfMutStaticLabel::Shared { span },
|
||||
errors::RefOfMutStaticSugg::Shared { span, var },
|
||||
"shared ",
|
||||
)
|
||||
(errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
|
||||
};
|
||||
tcx.emit_node_span_lint(
|
||||
STATIC_MUT_REF,
|
||||
STATIC_MUT_REFS,
|
||||
hir_id,
|
||||
span,
|
||||
errors::RefOfMutStatic { shared, why_note: (), label, sugg },
|
||||
errors::RefOfMutStatic { span, sugg, shared },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
let id = id.owner_id.def_id;
|
||||
let item_span = self.tcx.def_span(id);
|
||||
let self_ty = self.tcx.type_of(id).instantiate_identity();
|
||||
let self_ty = peel_off_weak_aliases(self.tcx, self_ty);
|
||||
match *self_ty.kind() {
|
||||
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
|
||||
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
|
||||
|
|
@ -166,7 +167,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
| ty::Never
|
||||
| ty::FnPtr(_)
|
||||
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
|
||||
ty::Alias(..) | ty::Param(_) => {
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) | ty::Param(_) => {
|
||||
Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
|
||||
}
|
||||
ty::FnDef(..)
|
||||
|
|
@ -174,6 +175,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Alias(ty::Weak, _)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => {
|
||||
|
|
@ -184,3 +186,30 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Peel off all weak alias types in this type until there are none left.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// This assumes that `ty` gets normalized later and that any overflows occurring
|
||||
/// during said normalization get reported.
|
||||
///
|
||||
/// </div>
|
||||
fn peel_off_weak_aliases<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
|
||||
|
||||
let limit = tcx.recursion_limit();
|
||||
let mut depth = 0;
|
||||
|
||||
while let ty::Alias(ty::Weak, alias) = ty.kind() {
|
||||
if !limit.value_within_limit(depth) {
|
||||
let guar = tcx.dcx().delayed_bug("overflow expanding weak alias type");
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
|
||||
ty = tcx.type_of(alias.def_id).instantiate(tcx, alias.args);
|
||||
depth += 1;
|
||||
}
|
||||
|
||||
ty
|
||||
}
|
||||
|
|
|
|||
|
|
@ -943,7 +943,15 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
|
|||
}
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
|
||||
self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
|
||||
// If this is a direct path to an ADT, we can check it
|
||||
// If this is a type alias or non-ADT, `check_unnamed_fields` should verify it
|
||||
if let Some(def_id) = res.opt_def_id()
|
||||
&& let Some(local) = def_id.as_local()
|
||||
&& let Node::Item(item) = self.tcx.hir_node_by_def_id(local)
|
||||
&& item.is_adt()
|
||||
{
|
||||
self.check_field_in_nested_adt(self.tcx.adt_def(def_id), field.span);
|
||||
}
|
||||
}
|
||||
// Abort due to errors (there must be an error if an unnamed field
|
||||
// has any type kind other than an anonymous adt or a named adt)
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
tcx,
|
||||
&mut predicates,
|
||||
trait_ref,
|
||||
&mut cgp::parameters_for_impl(self_ty, trait_ref),
|
||||
&mut cgp::parameters_for_impl(tcx, self_ty, trait_ref),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -27,12 +28,13 @@ impl From<ty::ParamConst> for Parameter {
|
|||
|
||||
/// Returns the set of parameters constrained by the impl header.
|
||||
pub fn parameters_for_impl<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_self_ty: Ty<'tcx>,
|
||||
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> FxHashSet<Parameter> {
|
||||
let vec = match impl_trait_ref {
|
||||
Some(tr) => parameters_for(&tr, false),
|
||||
None => parameters_for(&impl_self_ty, false),
|
||||
Some(tr) => parameters_for(tcx, &tr, false),
|
||||
None => parameters_for(tcx, &impl_self_ty, false),
|
||||
};
|
||||
vec.into_iter().collect()
|
||||
}
|
||||
|
|
@ -43,26 +45,47 @@ pub fn parameters_for_impl<'tcx>(
|
|||
/// of parameters whose values are needed in order to constrain `ty` - these
|
||||
/// differ, with the latter being a superset, in the presence of projections.
|
||||
pub fn parameters_for<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
t: &impl TypeVisitable<TyCtxt<'tcx>>,
|
||||
include_nonconstraining: bool,
|
||||
) -> Vec<Parameter> {
|
||||
let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
|
||||
let mut collector =
|
||||
ParameterCollector { tcx, parameters: vec![], include_nonconstraining, depth: 0 };
|
||||
t.visit_with(&mut collector);
|
||||
collector.parameters
|
||||
}
|
||||
|
||||
struct ParameterCollector {
|
||||
struct ParameterCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
parameters: Vec<Parameter>,
|
||||
include_nonconstraining: bool,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match *t.kind() {
|
||||
ty::Alias(..) if !self.include_nonconstraining => {
|
||||
// projections are not injective
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _)
|
||||
if !self.include_nonconstraining =>
|
||||
{
|
||||
// Projections are not injective in general.
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
ty::Alias(ty::Weak, alias) if !self.include_nonconstraining => {
|
||||
if !self.tcx.recursion_limit().value_within_limit(self.depth) {
|
||||
// Other constituent types may still constrain some generic params, consider
|
||||
// `<T> (Overflow, T)` for example. Therefore we want to continue instead of
|
||||
// breaking. Only affects diagnostics.
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
self.depth += 1;
|
||||
return ensure_sufficient_stack(|| {
|
||||
self.tcx
|
||||
.type_of(alias.def_id)
|
||||
.instantiate(self.tcx, alias.args)
|
||||
.visit_with(self)
|
||||
});
|
||||
}
|
||||
ty::Param(data) => {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
}
|
||||
|
|
@ -82,7 +105,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
|||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
|
||||
// Constant expressions are not injective
|
||||
// Constant expressions are not injective in general.
|
||||
return c.ty().visit_with(self);
|
||||
}
|
||||
ty::ConstKind::Param(data) => {
|
||||
|
|
@ -201,12 +224,12 @@ pub fn setup_constraining_predicates<'tcx>(
|
|||
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
||||
// Then the projection only applies if `T` is known, but it still
|
||||
// does not determine `U`.
|
||||
let inputs = parameters_for(&projection.projection_ty, true);
|
||||
let inputs = parameters_for(tcx, &projection.projection_ty, true);
|
||||
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
|
||||
if !relies_only_on_inputs {
|
||||
continue;
|
||||
}
|
||||
input_parameters.extend(parameters_for(&projection.term, false));
|
||||
input_parameters.extend(parameters_for(tcx, &projection.term, false));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_unrecognized_intrinsic_function, code = E0093)]
|
||||
#[help]
|
||||
pub struct UnrecognizedIntrinsicFunction {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
|
|
@ -661,6 +662,13 @@ pub(crate) struct InvalidUnionField {
|
|||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_unnamed_field_ty)]
|
||||
pub struct InvalidUnnamedFieldTy {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_on_non_rpitit)]
|
||||
pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
|
||||
|
|
@ -1455,12 +1463,13 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
|
|||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_static_mut_ref, code = E0796)]
|
||||
#[note]
|
||||
pub struct StaticMutRef {
|
||||
pub struct StaticMutRef<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: StaticMutRefSugg,
|
||||
pub shared: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
@ -1491,30 +1500,15 @@ pub enum StaticMutRefSugg {
|
|||
|
||||
// STATIC_MUT_REF lint
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_static_mut_ref_lint)]
|
||||
#[diag(hir_analysis_static_mut_refs_lint)]
|
||||
#[note]
|
||||
#[note(hir_analysis_why_note)]
|
||||
pub struct RefOfMutStatic<'a> {
|
||||
pub shared: &'a str,
|
||||
#[note(hir_analysis_why_note)]
|
||||
pub why_note: (),
|
||||
#[subdiagnostic]
|
||||
pub label: RefOfMutStaticLabel,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: RefOfMutStaticSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum RefOfMutStaticLabel {
|
||||
#[label(hir_analysis_label)]
|
||||
Shared {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(hir_analysis_label_mut)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
pub shared: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ fn enforce_impl_params_are_constrained(
|
|||
let impl_predicates = tcx.predicates_of(impl_def_id);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
|
||||
|
||||
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
|
||||
let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
|
||||
cgp::identify_constrained_generic_params(
|
||||
tcx,
|
||||
impl_predicates,
|
||||
|
|
@ -111,7 +111,7 @@ fn enforce_impl_params_are_constrained(
|
|||
match item.kind {
|
||||
ty::AssocKind::Type => {
|
||||
if item.defaultness(tcx).has_value() {
|
||||
cgp::parameters_for(&tcx.type_of(def_id).instantiate_identity(), true)
|
||||
cgp::parameters_for(tcx, &tcx.type_of(def_id).instantiate_identity(), true)
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,15 +266,15 @@ fn unconstrained_parent_impl_args<'tcx>(
|
|||
continue;
|
||||
}
|
||||
|
||||
unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true));
|
||||
unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
|
||||
|
||||
for param in cgp::parameters_for(&projected_ty, false) {
|
||||
for param in cgp::parameters_for(tcx, &projected_ty, false) {
|
||||
if !unconstrained_parameters.contains(¶m) {
|
||||
constrained_params.insert(param.0);
|
||||
}
|
||||
}
|
||||
|
||||
unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true));
|
||||
unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +312,7 @@ fn check_duplicate_params<'tcx>(
|
|||
parent_args: &Vec<GenericArg<'tcx>>,
|
||||
span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let mut base_params = cgp::parameters_for(parent_args, true);
|
||||
let mut base_params = cgp::parameters_for(tcx, parent_args, true);
|
||||
base_params.sort_by_key(|param| param.0);
|
||||
if let (_, [duplicate, ..]) = base_params.partition_dedup() {
|
||||
let param = impl1_args[duplicate.0 as usize];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{errors, structured_errors::StructuredDiagnostic};
|
||||
use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode};
|
||||
use rustc_errors::{codes::*, DiagnosticBuilder};
|
||||
use rustc_middle::ty::{Ty, TypeVisitableExt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Span;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{errors, structured_errors::StructuredDiagnostic};
|
||||
use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode};
|
||||
use rustc_errors::{codes::*, DiagnosticBuilder};
|
||||
use rustc_middle::ty::{Ty, TypeVisitableExt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Span;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::structured_errors::StructuredDiagnostic;
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ pub enum HelpUseLatestEdition {
|
|||
impl HelpUseLatestEdition {
|
||||
pub fn new() -> Self {
|
||||
let edition = LATEST_STABLE_EDITION;
|
||||
if std::env::var_os("CARGO").is_some() {
|
||||
if rustc_session::utils::was_invoked_from_cargo() {
|
||||
Self::Cargo { edition }
|
||||
} else {
|
||||
Self::Standalone { edition }
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
|||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic,
|
||||
DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey,
|
||||
DiagnosticBuilder, ErrorGuaranteed, StashKey,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use itertools::Itertools;
|
|||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, Applicability, Diagnostic, ErrCode, ErrorGuaranteed, MultiSpan, StashKey,
|
||||
codes::*, pluralize, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ use crate::expectation::Expectation;
|
|||
use crate::fn_ctxt::LoweredTy;
|
||||
use crate::gather_locals::GatherLocalsVisitor;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, ErrCode, ErrorGuaranteed};
|
||||
use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ fn lock_directory(
|
|||
lock_err,
|
||||
session_dir,
|
||||
is_unsupported_lock,
|
||||
is_cargo: std::env::var_os("CARGO").map(|_| ()),
|
||||
is_cargo: rustc_session::utils::was_invoked_from_cargo().then_some(()),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::errors::{
|
|||
use crate::infer::error_reporting::TypeErrCtxt;
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode, IntoDiagnosticArg};
|
||||
use rustc_errors::{codes::*, DiagnosticBuilder, IntoDiagnosticArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ pub(super) fn builtin(
|
|||
Vec::new()
|
||||
};
|
||||
|
||||
let is_from_cargo = std::env::var_os("CARGO").is_some();
|
||||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
let mut is_feature_cfg = name == sym::feature;
|
||||
|
||||
if is_feature_cfg && is_from_cargo {
|
||||
|
|
@ -340,7 +340,7 @@ pub(super) fn builtin(
|
|||
.copied()
|
||||
.flatten()
|
||||
.collect();
|
||||
let is_from_cargo = std::env::var_os("CARGO").is_some();
|
||||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
|
||||
// Show the full list if all possible values for a given name, but don't do it
|
||||
// for names as the possibilities could be very long
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ fn register_builtins(store: &mut LintStore) {
|
|||
store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns");
|
||||
store.register_renamed("non_fmt_panic", "non_fmt_panics");
|
||||
store.register_renamed("unused_tuple_struct_fields", "dead_code");
|
||||
store.register_renamed("static_mut_ref", "static_mut_refs");
|
||||
|
||||
// These were moved to tool lints, but rustc still sees them when compiling normally, before
|
||||
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ declare_lint_pass! {
|
|||
SINGLE_USE_LIFETIMES,
|
||||
SOFT_UNSTABLE,
|
||||
STABLE_FEATURES,
|
||||
STATIC_MUT_REF,
|
||||
STATIC_MUT_REFS,
|
||||
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
||||
TEST_UNSTABLE_LINT,
|
||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
||||
|
|
@ -1769,7 +1769,7 @@ declare_lint! {
|
|||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `static_mut_ref` lint checks for shared or mutable references
|
||||
/// The `static_mut_refs` lint checks for shared or mutable references
|
||||
/// of mutable static inside `unsafe` blocks and `unsafe` functions.
|
||||
///
|
||||
/// ### Example
|
||||
|
|
@ -1807,9 +1807,9 @@ declare_lint! {
|
|||
/// Shared or mutable references of mutable static are almost always a mistake and
|
||||
/// can lead to undefined behavior and various other problems in your code.
|
||||
///
|
||||
/// This lint is "warn" by default on editions up to 2021, from 2024 there is
|
||||
/// This lint is "warn" by default on editions up to 2021, in 2024 there is
|
||||
/// a hard error instead.
|
||||
pub STATIC_MUT_REF,
|
||||
pub STATIC_MUT_REFS,
|
||||
Warn,
|
||||
"shared references or mutable references of mutable static is discouraged",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_data_structures::unhash::UnhashMap;
|
|||
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::{DefPath, DefPathData};
|
||||
use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||
use rustc_index::Idx;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::ty::{Region, UserTypeAnnotationIndex};
|
|||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self, CoroutineKind};
|
||||
use rustc_hir::CoroutineKind;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
|
|
|
|||
|
|
@ -1,161 +0,0 @@
|
|||
//! Propagates constants for early reporting of statically known
|
||||
//! assertion failures
|
||||
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
|
||||
/// Severely regress performance.
|
||||
const MAX_ALLOC_LIMIT: u64 = 1024;
|
||||
|
||||
/// Macro for machine-specific `InterpError` without allocation.
|
||||
/// (These will never be shown to the user, but they help diagnose ICEs.)
|
||||
pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
|
||||
// We make a new local type for it. The type itself does not carry any information,
|
||||
// but its vtable (for the `MachineStopType` trait) does.
|
||||
#[derive(Debug)]
|
||||
struct Zst;
|
||||
// Printing this type shows the desired string.
|
||||
impl std::fmt::Display for Zst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, $($tt)*)
|
||||
}
|
||||
}
|
||||
|
||||
impl rustc_middle::mir::interpret::MachineStopType for Zst {
|
||||
fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
|
||||
self.to_string().into()
|
||||
}
|
||||
|
||||
fn add_args(
|
||||
self: Box<Self>,
|
||||
_: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
|
||||
) {}
|
||||
}
|
||||
throw_machine_stop!(Zst)
|
||||
}}
|
||||
|
||||
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum ConstPropMode {
|
||||
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
|
||||
FullConstProp,
|
||||
/// The `Local` can only be propagated into and from its own block.
|
||||
OnlyInsideOwnBlock,
|
||||
/// The `Local` cannot be part of propagation at all. Any statement
|
||||
/// referencing it either for reading or writing will not get propagated.
|
||||
NoPropagation,
|
||||
}
|
||||
|
||||
pub struct CanConstProp {
|
||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||
// False at the beginning. Once set, no more assignments are allowed to that local.
|
||||
found_assignment: BitSet<Local>,
|
||||
}
|
||||
|
||||
impl CanConstProp {
|
||||
/// Returns true if `local` can be propagated
|
||||
pub fn check<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
) -> IndexVec<Local, ConstPropMode> {
|
||||
let mut cpv = CanConstProp {
|
||||
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
|
||||
found_assignment: BitSet::new_empty(body.local_decls.len()),
|
||||
};
|
||||
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
|
||||
let ty = body.local_decls[local].ty;
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
|
||||
// Either the layout fails to compute, then we can't use this local anyway
|
||||
// or the local is too large, then we don't want to.
|
||||
_ => {
|
||||
*val = ConstPropMode::NoPropagation;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Consider that arguments are assigned on entry.
|
||||
for arg in body.args_iter() {
|
||||
cpv.found_assignment.insert(arg);
|
||||
}
|
||||
cpv.visit_body(body);
|
||||
cpv.can_const_prop
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CanConstProp {
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
|
||||
use rustc_middle::mir::visit::PlaceContext::*;
|
||||
|
||||
// Dereferencing just read the addess of `place.local`.
|
||||
if place.projection.first() == Some(&PlaceElem::Deref) {
|
||||
context = NonMutatingUse(NonMutatingUseContext::Copy);
|
||||
}
|
||||
|
||||
self.visit_local(place.local, context, loc);
|
||||
self.visit_projection(place.as_ref(), context, loc);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
|
||||
use rustc_middle::mir::visit::PlaceContext::*;
|
||||
match context {
|
||||
// These are just stores, where the storing is not propagatable, but there may be later
|
||||
// mutations of the same local via `Store`
|
||||
| MutatingUse(MutatingUseContext::Call)
|
||||
| MutatingUse(MutatingUseContext::AsmOutput)
|
||||
| MutatingUse(MutatingUseContext::Deinit)
|
||||
// Actual store that can possibly even propagate a value
|
||||
| MutatingUse(MutatingUseContext::Store)
|
||||
| MutatingUse(MutatingUseContext::SetDiscriminant) => {
|
||||
if !self.found_assignment.insert(local) {
|
||||
match &mut self.can_const_prop[local] {
|
||||
// If the local can only get propagated in its own block, then we don't have
|
||||
// to worry about multiple assignments, as we'll nuke the const state at the
|
||||
// end of the block anyway, and inside the block we overwrite previous
|
||||
// states as applicable.
|
||||
ConstPropMode::OnlyInsideOwnBlock => {}
|
||||
ConstPropMode::NoPropagation => {}
|
||||
other @ ConstPropMode::FullConstProp => {
|
||||
trace!(
|
||||
"local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
|
||||
local, other,
|
||||
);
|
||||
*other = ConstPropMode::OnlyInsideOwnBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reading constants is allowed an arbitrary number of times
|
||||
NonMutatingUse(NonMutatingUseContext::Copy)
|
||||
| NonMutatingUse(NonMutatingUseContext::Move)
|
||||
| NonMutatingUse(NonMutatingUseContext::Inspect)
|
||||
| NonMutatingUse(NonMutatingUseContext::PlaceMention)
|
||||
| NonUse(_) => {}
|
||||
|
||||
// These could be propagated with a smarter analysis or just some careful thinking about
|
||||
// whether they'd be fine right now.
|
||||
MutatingUse(MutatingUseContext::Yield)
|
||||
| MutatingUse(MutatingUseContext::Drop)
|
||||
| MutatingUse(MutatingUseContext::Retag)
|
||||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
||||
// mutation.
|
||||
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||
| MutatingUse(MutatingUseContext::Borrow)
|
||||
| MutatingUse(MutatingUseContext::AddressOf) => {
|
||||
trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
|
||||
self.can_const_prop[local] = ConstPropMode::NoPropagation;
|
||||
}
|
||||
MutatingUse(MutatingUseContext::Projection)
|
||||
| NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,17 +9,14 @@ use rustc_const_eval::interpret::{
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_index::{bit_set::BitSet, Idx, IndexVec};
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx};
|
||||
|
||||
use crate::const_prop::CanConstProp;
|
||||
use crate::const_prop::ConstPropMode;
|
||||
use crate::dataflow_const_prop::DummyMachine;
|
||||
use crate::errors::{AssertLint, AssertLintKind};
|
||||
use crate::MirLint;
|
||||
|
|
@ -849,3 +846,128 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
|
||||
/// Severely regress performance.
|
||||
const MAX_ALLOC_LIMIT: u64 = 1024;
|
||||
|
||||
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum ConstPropMode {
|
||||
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
|
||||
FullConstProp,
|
||||
/// The `Local` can only be propagated into and from its own block.
|
||||
OnlyInsideOwnBlock,
|
||||
/// The `Local` cannot be part of propagation at all. Any statement
|
||||
/// referencing it either for reading or writing will not get propagated.
|
||||
NoPropagation,
|
||||
}
|
||||
|
||||
pub struct CanConstProp {
|
||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||
// False at the beginning. Once set, no more assignments are allowed to that local.
|
||||
found_assignment: BitSet<Local>,
|
||||
}
|
||||
|
||||
impl CanConstProp {
|
||||
/// Returns true if `local` can be propagated
|
||||
pub fn check<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
) -> IndexVec<Local, ConstPropMode> {
|
||||
let mut cpv = CanConstProp {
|
||||
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
|
||||
found_assignment: BitSet::new_empty(body.local_decls.len()),
|
||||
};
|
||||
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
|
||||
let ty = body.local_decls[local].ty;
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
|
||||
// Either the layout fails to compute, then we can't use this local anyway
|
||||
// or the local is too large, then we don't want to.
|
||||
_ => {
|
||||
*val = ConstPropMode::NoPropagation;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Consider that arguments are assigned on entry.
|
||||
for arg in body.args_iter() {
|
||||
cpv.found_assignment.insert(arg);
|
||||
}
|
||||
cpv.visit_body(body);
|
||||
cpv.can_const_prop
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CanConstProp {
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
|
||||
use rustc_middle::mir::visit::PlaceContext::*;
|
||||
|
||||
// Dereferencing just read the addess of `place.local`.
|
||||
if place.projection.first() == Some(&PlaceElem::Deref) {
|
||||
context = NonMutatingUse(NonMutatingUseContext::Copy);
|
||||
}
|
||||
|
||||
self.visit_local(place.local, context, loc);
|
||||
self.visit_projection(place.as_ref(), context, loc);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
|
||||
use rustc_middle::mir::visit::PlaceContext::*;
|
||||
match context {
|
||||
// These are just stores, where the storing is not propagatable, but there may be later
|
||||
// mutations of the same local via `Store`
|
||||
| MutatingUse(MutatingUseContext::Call)
|
||||
| MutatingUse(MutatingUseContext::AsmOutput)
|
||||
| MutatingUse(MutatingUseContext::Deinit)
|
||||
// Actual store that can possibly even propagate a value
|
||||
| MutatingUse(MutatingUseContext::Store)
|
||||
| MutatingUse(MutatingUseContext::SetDiscriminant) => {
|
||||
if !self.found_assignment.insert(local) {
|
||||
match &mut self.can_const_prop[local] {
|
||||
// If the local can only get propagated in its own block, then we don't have
|
||||
// to worry about multiple assignments, as we'll nuke the const state at the
|
||||
// end of the block anyway, and inside the block we overwrite previous
|
||||
// states as applicable.
|
||||
ConstPropMode::OnlyInsideOwnBlock => {}
|
||||
ConstPropMode::NoPropagation => {}
|
||||
other @ ConstPropMode::FullConstProp => {
|
||||
trace!(
|
||||
"local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
|
||||
local, other,
|
||||
);
|
||||
*other = ConstPropMode::OnlyInsideOwnBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reading constants is allowed an arbitrary number of times
|
||||
NonMutatingUse(NonMutatingUseContext::Copy)
|
||||
| NonMutatingUse(NonMutatingUseContext::Move)
|
||||
| NonMutatingUse(NonMutatingUseContext::Inspect)
|
||||
| NonMutatingUse(NonMutatingUseContext::PlaceMention)
|
||||
| NonUse(_) => {}
|
||||
|
||||
// These could be propagated with a smarter analysis or just some careful thinking about
|
||||
// whether they'd be fine right now.
|
||||
MutatingUse(MutatingUseContext::Yield)
|
||||
| MutatingUse(MutatingUseContext::Drop)
|
||||
| MutatingUse(MutatingUseContext::Retag)
|
||||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
||||
// mutation.
|
||||
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||
| MutatingUse(MutatingUseContext::Borrow)
|
||||
| MutatingUse(MutatingUseContext::AddressOf) => {
|
||||
trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
|
||||
self.can_const_prop[local] = ConstPropMode::NoPropagation;
|
||||
}
|
||||
MutatingUse(MutatingUseContext::Projection)
|
||||
| NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,32 @@ use rustc_span::def_id::DefId;
|
|||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
|
||||
|
||||
use crate::const_prop::throw_machine_stop_str;
|
||||
/// Macro for machine-specific `InterpError` without allocation.
|
||||
/// (These will never be shown to the user, but they help diagnose ICEs.)
|
||||
pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
|
||||
// We make a new local type for it. The type itself does not carry any information,
|
||||
// but its vtable (for the `MachineStopType` trait) does.
|
||||
#[derive(Debug)]
|
||||
struct Zst;
|
||||
// Printing this type shows the desired string.
|
||||
impl std::fmt::Display for Zst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, $($tt)*)
|
||||
}
|
||||
}
|
||||
|
||||
impl rustc_middle::mir::interpret::MachineStopType for Zst {
|
||||
fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
|
||||
self.to_string().into()
|
||||
}
|
||||
|
||||
fn add_args(
|
||||
self: Box<Self>,
|
||||
_: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
|
||||
) {}
|
||||
}
|
||||
throw_machine_stop!(Zst)
|
||||
}}
|
||||
|
||||
// These constants are somewhat random guesses and have not been optimized.
|
||||
// If `tcx.sess.mir_opt_level() >= 4`, we ignore the limits (this can become very expensive).
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ mod remove_place_mention;
|
|||
mod add_subtyping_projections;
|
||||
pub mod cleanup_post_borrowck;
|
||||
mod const_debuginfo;
|
||||
mod const_prop;
|
||||
mod const_prop_lint;
|
||||
mod copy_prop;
|
||||
mod coroutine;
|
||||
|
|
|
|||
|
|
@ -2545,7 +2545,7 @@ pub enum HelpUseLatestEdition {
|
|||
impl HelpUseLatestEdition {
|
||||
pub fn new() -> Self {
|
||||
let edition = LATEST_STABLE_EDITION;
|
||||
if std::env::var_os("CARGO").is_some() {
|
||||
if rustc_session::utils::was_invoked_from_cargo() {
|
||||
Self::Cargo { edition }
|
||||
} else {
|
||||
Self::Standalone { edition }
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
use crate::def_collector::collect_definitions;
|
||||
use crate::imports::{ImportData, ImportKind};
|
||||
use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
|
||||
use crate::Namespace::{self, MacroNS, TypeNS, ValueNS};
|
||||
use crate::Namespace::{MacroNS, TypeNS, ValueNS};
|
||||
use crate::{errors, BindingKey, MacroData, NameBindingData};
|
||||
use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError};
|
||||
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError};
|
||||
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
|
||||
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};
|
||||
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
|
||||
|
|
@ -362,7 +362,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
root_span,
|
||||
root_id,
|
||||
vis: Cell::new(Some(vis)),
|
||||
used: Cell::new(false),
|
||||
used: Default::default(),
|
||||
});
|
||||
|
||||
self.r.indeterminate_imports.push(import);
|
||||
|
|
@ -885,7 +885,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
span: item.span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(Some(vis)),
|
||||
used: Cell::new(used),
|
||||
used: Cell::new(used.then_some(Used::Other)),
|
||||
});
|
||||
self.r.potentially_unused_imports.push(import);
|
||||
let imported_binding = self.r.import(binding, import);
|
||||
|
|
@ -1090,7 +1090,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
|
||||
used: Cell::new(false),
|
||||
used: Default::default(),
|
||||
})
|
||||
};
|
||||
|
||||
|
|
@ -1261,7 +1261,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(Some(vis)),
|
||||
used: Cell::new(true),
|
||||
used: Cell::new(Some(Used::Other)),
|
||||
});
|
||||
let import_binding = self.r.import(binding, import);
|
||||
self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
|
||||
|
|
|
|||
|
|
@ -27,9 +27,10 @@ use crate::imports::ImportKind;
|
|||
use crate::module_to_string;
|
||||
use crate::Resolver;
|
||||
|
||||
use crate::NameBindingKind;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{pluralize, MultiSpan};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -38,14 +39,14 @@ use rustc_session::lint::BuiltinLintDiagnostics;
|
|||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
struct UnusedImport<'a> {
|
||||
use_tree: &'a ast::UseTree,
|
||||
struct UnusedImport {
|
||||
use_tree: ast::UseTree,
|
||||
use_tree_id: ast::NodeId,
|
||||
item_span: Span,
|
||||
unused: UnordSet<ast::NodeId>,
|
||||
}
|
||||
|
||||
impl<'a> UnusedImport<'a> {
|
||||
impl UnusedImport {
|
||||
fn add(&mut self, id: ast::NodeId) {
|
||||
self.unused.insert(id);
|
||||
}
|
||||
|
|
@ -54,7 +55,7 @@ impl<'a> UnusedImport<'a> {
|
|||
struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
||||
r: &'a mut Resolver<'b, 'tcx>,
|
||||
/// All the (so far) unused imports, grouped path list
|
||||
unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
|
||||
unused_imports: FxIndexMap<ast::NodeId, UnusedImport>,
|
||||
extern_crate_items: Vec<ExternCrateToLint>,
|
||||
base_use_tree: Option<&'a ast::UseTree>,
|
||||
base_id: ast::NodeId,
|
||||
|
|
@ -100,9 +101,9 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
|
||||
fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport {
|
||||
let use_tree_id = self.base_id;
|
||||
let use_tree = self.base_use_tree.unwrap();
|
||||
let use_tree = self.base_use_tree.unwrap().clone();
|
||||
let item_span = self.item_span;
|
||||
|
||||
self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
|
||||
|
|
@ -197,7 +198,7 @@ enum UnusedSpanResult {
|
|||
}
|
||||
|
||||
fn calc_unused_spans(
|
||||
unused_import: &UnusedImport<'_>,
|
||||
unused_import: &UnusedImport,
|
||||
use_tree: &ast::UseTree,
|
||||
use_tree_id: ast::NodeId,
|
||||
) -> UnusedSpanResult {
|
||||
|
|
@ -287,7 +288,7 @@ impl Resolver<'_, '_> {
|
|||
|
||||
for import in self.potentially_unused_imports.iter() {
|
||||
match import.kind {
|
||||
_ if import.used.get()
|
||||
_ if import.used.get().is_some()
|
||||
|| import.expect_vis().is_public()
|
||||
|| import.span.is_dummy() =>
|
||||
{
|
||||
|
|
@ -336,7 +337,7 @@ impl Resolver<'_, '_> {
|
|||
|
||||
for unused in visitor.unused_imports.values() {
|
||||
let mut fixes = Vec::new();
|
||||
let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
||||
let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
|
||||
UnusedSpanResult::Used => continue,
|
||||
UnusedSpanResult::FlatUnused(span, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
|
|
@ -483,5 +484,30 @@ impl Resolver<'_, '_> {
|
|||
BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
|
||||
);
|
||||
}
|
||||
|
||||
let unused_imports = visitor.unused_imports;
|
||||
let mut check_redundant_imports = FxIndexSet::default();
|
||||
for module in self.arenas.local_modules().iter() {
|
||||
for (_key, resolution) in self.resolutions(*module).borrow().iter() {
|
||||
let resolution = resolution.borrow();
|
||||
|
||||
if let Some(binding) = resolution.binding
|
||||
&& let NameBindingKind::Import { import, .. } = binding.kind
|
||||
&& let ImportKind::Single { id, .. } = import.kind
|
||||
{
|
||||
if let Some(unused_import) = unused_imports.get(&import.root_id)
|
||||
&& unused_import.unused.contains(&id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
check_redundant_imports.insert(import);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for import in check_redundant_imports {
|
||||
self.check_for_redundant_imports(import);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{ImplTraitContext, Resolver};
|
||||
use rustc_ast::visit::{self, FnKind};
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_ast::*;
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSugge
|
|||
use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
|
||||
use crate::imports::{Import, ImportKind};
|
||||
use crate::late::{PatternSource, Rib};
|
||||
use crate::path_names_to_string;
|
||||
use crate::{errors as errs, BindingKey};
|
||||
use crate::{path_names_to_string, Used};
|
||||
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
|
||||
use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
|
||||
|
|
@ -1503,7 +1503,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
);
|
||||
// Silence the 'unused import' warning we might get,
|
||||
// since this diagnostic already covers that import.
|
||||
self.record_use(ident, binding, false);
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use rustc_span::Span;
|
|||
use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
|
||||
use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
|
||||
use crate::macros::{sub_namespace_match, MacroRulesScope};
|
||||
use crate::BindingKey;
|
||||
use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
|
||||
use crate::{BindingKey, Used};
|
||||
use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
|
||||
use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
|
||||
|
|
@ -339,7 +339,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
|
||||
ignore_binding,
|
||||
);
|
||||
if let Ok(binding) = item {
|
||||
|
|
@ -506,7 +506,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ns,
|
||||
adjusted_parent_scope,
|
||||
!matches!(scope_set, ScopeSet::Late(..)),
|
||||
finalize,
|
||||
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
|
||||
ignore_binding,
|
||||
);
|
||||
match binding {
|
||||
|
|
@ -857,7 +857,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
.into_iter()
|
||||
.find_map(|binding| if binding == ignore_binding { None } else { binding });
|
||||
|
||||
if let Some(Finalize { path_span, report_private, .. }) = finalize {
|
||||
if let Some(Finalize { path_span, report_private, used, .. }) = finalize {
|
||||
let Some(binding) = binding else {
|
||||
return Err((Determined, Weak::No));
|
||||
};
|
||||
|
|
@ -901,7 +901,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.record_use(ident, binding, restricted_shadowing);
|
||||
self.record_use(ident, binding, used);
|
||||
return Ok(binding);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ use crate::errors::{
|
|||
use crate::Determinacy::{self, *};
|
||||
use crate::Namespace::*;
|
||||
use crate::{module_to_string, names_to_string, ImportSuggestion};
|
||||
use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
|
||||
use crate::{AmbiguityKind, BindingKey, ResolutionError, Resolver, Segment};
|
||||
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
|
||||
use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult};
|
||||
use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult, Used};
|
||||
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -173,7 +173,7 @@ pub(crate) struct ImportData<'a> {
|
|||
/// The resolution of `module_path`.
|
||||
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
|
||||
pub vis: Cell<Option<ty::Visibility>>,
|
||||
pub used: Cell<bool>,
|
||||
pub used: Cell<Option<Used>>,
|
||||
}
|
||||
|
||||
/// All imports are unique and allocated on a same arena,
|
||||
|
|
@ -286,7 +286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.arenas.alloc_name_binding(NameBindingData {
|
||||
kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
|
||||
kind: NameBindingKind::Import { binding, import },
|
||||
ambiguity: None,
|
||||
warn_ambiguity: false,
|
||||
span: import.span,
|
||||
|
|
@ -485,9 +485,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
resolution.single_imports.remove(&import);
|
||||
})
|
||||
});
|
||||
self.record_use(target, dummy_binding, false);
|
||||
self.record_use(target, dummy_binding, Used::Other);
|
||||
} else if import.imported_module.get().is_none() {
|
||||
import.used.set(true);
|
||||
import.used.set(Some(Used::Other));
|
||||
if let Some(id) = import.id() {
|
||||
self.used_imports.insert(id);
|
||||
}
|
||||
|
|
@ -1056,11 +1056,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
&& initial_binding.is_extern_crate()
|
||||
&& !initial_binding.is_import()
|
||||
{
|
||||
this.record_use(
|
||||
ident,
|
||||
target_binding,
|
||||
import.module_path.is_empty(),
|
||||
);
|
||||
let used = if import.module_path.is_empty() {
|
||||
Used::Scope
|
||||
} else {
|
||||
Used::Other
|
||||
};
|
||||
this.record_use(ident, target_binding, used);
|
||||
}
|
||||
}
|
||||
initial_binding.res()
|
||||
|
|
@ -1299,22 +1300,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
});
|
||||
|
||||
self.check_for_redundant_imports(ident, import, source_bindings, target_bindings, target);
|
||||
|
||||
debug!("(resolving single import) successfully resolved import");
|
||||
None
|
||||
}
|
||||
|
||||
fn check_for_redundant_imports(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
import: Import<'a>,
|
||||
source_bindings: &PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
|
||||
target_bindings: &PerNS<Cell<Option<NameBinding<'a>>>>,
|
||||
target: Ident,
|
||||
) {
|
||||
pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) {
|
||||
// This function is only called for single imports.
|
||||
let ImportKind::Single { id, .. } = import.kind else { unreachable!() };
|
||||
let ImportKind::Single {
|
||||
source, target, ref source_bindings, ref target_bindings, id, ..
|
||||
} = import.kind
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
// Skip if the import is of the form `use source as target` and source != target.
|
||||
if source != target {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if the import was produced by a macro.
|
||||
if import.parent_scope.expansion != LocalExpnId::ROOT {
|
||||
|
|
@ -1323,16 +1325,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
// Skip if we are inside a named module (in contrast to an anonymous
|
||||
// module defined by a block).
|
||||
if let ModuleKind::Def(..) = import.parent_scope.module.kind {
|
||||
// Skip if the import is public or was used through non scope-based resolution,
|
||||
// e.g. through a module-relative path.
|
||||
if import.used.get() == Some(Used::Other)
|
||||
|| self.effective_visibilities.is_exported(self.local_def_id(id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let mut is_redundant = PerNS { value_ns: None, type_ns: None, macro_ns: None };
|
||||
let mut is_redundant = true;
|
||||
|
||||
let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None };
|
||||
|
||||
self.per_ns(|this, ns| {
|
||||
if let Ok(binding) = source_bindings[ns].get() {
|
||||
if is_redundant && let Ok(binding) = source_bindings[ns].get() {
|
||||
if binding.res() == Res::Err {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1346,18 +1352,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
target_bindings[ns].get(),
|
||||
) {
|
||||
Ok(other_binding) => {
|
||||
is_redundant[ns] = Some(
|
||||
binding.res() == other_binding.res() && !other_binding.is_ambiguity(),
|
||||
);
|
||||
redundant_span[ns] = Some((other_binding.span, other_binding.is_import()));
|
||||
is_redundant =
|
||||
binding.res() == other_binding.res() && !other_binding.is_ambiguity();
|
||||
if is_redundant {
|
||||
redundant_span[ns] =
|
||||
Some((other_binding.span, other_binding.is_import()));
|
||||
}
|
||||
}
|
||||
Err(_) => is_redundant[ns] = Some(false),
|
||||
Err(_) => is_redundant = false,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if !is_redundant.is_empty() && is_redundant.present_items().all(|is_redundant| is_redundant)
|
||||
{
|
||||
if is_redundant && !redundant_span.is_empty() {
|
||||
let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
|
||||
redundant_spans.sort();
|
||||
redundant_spans.dedup();
|
||||
|
|
@ -1365,8 +1372,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
UNUSED_IMPORTS,
|
||||
id,
|
||||
import.span,
|
||||
format!("the item `{ident}` is imported redundantly"),
|
||||
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
|
||||
format!("the item `{source}` is imported redundantly"),
|
||||
BuiltinLintDiagnostics::RedundantImport(redundant_spans, source),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,23 +7,22 @@
|
|||
//! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
|
||||
|
||||
use crate::errors::ImportsCannotReferTo;
|
||||
use crate::BindingKey;
|
||||
use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
|
||||
use crate::{BindingKey, Used};
|
||||
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
|
||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, ErrCode, IntoDiagnosticArg,
|
||||
StashKey,
|
||||
codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, IntoDiagnosticArg, StashKey,
|
||||
};
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
|
||||
use rustc_hir::{PrimTy, TraitCandidate};
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::middle::resolve_bound_vars::Set1;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
|
@ -3623,7 +3622,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
// whether they can be shadowed by fresh bindings or not, so force an error.
|
||||
// issues/33118#issuecomment-233962221 (see below) still applies here,
|
||||
// but we have to ignore it for backward compatibility.
|
||||
self.r.record_use(ident, binding, false);
|
||||
self.r.record_use(ident, binding, Used::Other);
|
||||
return None;
|
||||
}
|
||||
LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
|
||||
|
|
@ -3638,7 +3637,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
) if is_syntactic_ambiguity => {
|
||||
// Disambiguate in favor of a unit struct/variant or constant pattern.
|
||||
if let Some(binding) = binding {
|
||||
self.r.record_use(ident, binding, false);
|
||||
self.r.record_use(ident, binding, Used::Other);
|
||||
}
|
||||
Some(res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,6 +175,23 @@ enum ImplTraitContext {
|
|||
Universal,
|
||||
}
|
||||
|
||||
/// Used for tracking import use types which will be used for redundant import checking.
|
||||
/// ### Used::Scope Example
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(unused_imports)]
|
||||
/// use std::mem::drop;
|
||||
/// fn main() {
|
||||
/// let s = Box::new(32);
|
||||
/// drop(s);
|
||||
/// }
|
||||
/// ```
|
||||
/// Used::Other is for other situations like module-relative uses.
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||
enum Used {
|
||||
Scope,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BindingError {
|
||||
name: Symbol,
|
||||
|
|
@ -695,7 +712,7 @@ impl<'a> ToNameBinding<'a> for NameBinding<'a> {
|
|||
enum NameBindingKind<'a> {
|
||||
Res(Res),
|
||||
Module(Module<'a>),
|
||||
Import { binding: NameBinding<'a>, import: Import<'a>, used: Cell<bool> },
|
||||
Import { binding: NameBinding<'a>, import: Import<'a> },
|
||||
}
|
||||
|
||||
impl<'a> NameBindingKind<'a> {
|
||||
|
|
@ -1784,15 +1801,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) {
|
||||
self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity);
|
||||
fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, used: Used) {
|
||||
self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity);
|
||||
}
|
||||
|
||||
fn record_use_inner(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
used_binding: NameBinding<'a>,
|
||||
is_lexical_scope: bool,
|
||||
used: Used,
|
||||
warn_ambiguity: bool,
|
||||
) {
|
||||
if let Some((b2, kind)) = used_binding.ambiguity {
|
||||
|
|
@ -1810,27 +1827,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
self.ambiguity_errors.push(ambiguity_error);
|
||||
}
|
||||
}
|
||||
if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind {
|
||||
if let NameBindingKind::Import { import, binding } = used_binding.kind {
|
||||
if let ImportKind::MacroUse { warn_private: true } = import.kind {
|
||||
let msg = format!("macro `{ident}` is private");
|
||||
self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg);
|
||||
}
|
||||
// Avoid marking `extern crate` items that refer to a name from extern prelude,
|
||||
// but not introduce it, as used if they are accessed from lexical scope.
|
||||
if is_lexical_scope {
|
||||
if used == Used::Scope {
|
||||
if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
|
||||
if !entry.introduced_by_item && entry.binding == Some(used_binding) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
used.set(true);
|
||||
import.used.set(true);
|
||||
let old_used = import.used.get();
|
||||
let new_used = Some(used);
|
||||
if new_used > old_used {
|
||||
import.used.set(new_used);
|
||||
}
|
||||
if let Some(id) = import.id() {
|
||||
self.used_imports.insert(id);
|
||||
}
|
||||
self.add_to_glob_map(import, ident);
|
||||
self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity);
|
||||
self.record_use_inner(
|
||||
ident,
|
||||
binding,
|
||||
Used::Other,
|
||||
warn_ambiguity || binding.warn_ambiguity,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1985,7 +2010,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
if !entry.is_import() {
|
||||
self.crate_loader(|c| c.process_path_extern(ident.name, ident.span));
|
||||
} else if entry.introduced_by_item {
|
||||
self.record_use(ident, binding, false);
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
}
|
||||
}
|
||||
binding
|
||||
|
|
@ -2115,7 +2140,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let is_import = name_binding.is_import();
|
||||
let span = name_binding.span;
|
||||
if let Res::Def(DefKind::Fn, _) = res {
|
||||
self.record_use(ident, name_binding, false);
|
||||
self.record_use(ident, name_binding, Used::Other);
|
||||
}
|
||||
self.main_def = Some(MainDefinition { res, is_import, span });
|
||||
}
|
||||
|
|
@ -2176,6 +2201,8 @@ struct Finalize {
|
|||
/// Whether to report privacy errors or silently return "no resolution" for them,
|
||||
/// similarly to speculative resolution.
|
||||
report_private: bool,
|
||||
/// Tracks whether an item is used in scope or used relatively to a module.
|
||||
used: Used,
|
||||
}
|
||||
|
||||
impl Finalize {
|
||||
|
|
@ -2184,7 +2211,7 @@ impl Finalize {
|
|||
}
|
||||
|
||||
fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
|
||||
Finalize { node_id, path_span, root_span, report_private: true }
|
||||
Finalize { node_id, path_span, root_span, report_private: true, used: Used::Other }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
|
|||
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
|
||||
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
|
||||
use crate::Namespace::*;
|
||||
use crate::{BuiltinMacroState, Determinacy, MacroData};
|
||||
use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
|
||||
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
|
||||
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
||||
use rustc_ast::expand::StrippedCfgItem;
|
||||
|
|
@ -794,7 +794,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
) {
|
||||
Ok(binding) => {
|
||||
let initial_res = initial_binding.map(|initial_binding| {
|
||||
self.record_use(ident, initial_binding, false);
|
||||
self.record_use(ident, initial_binding, Used::Other);
|
||||
initial_binding.res()
|
||||
});
|
||||
let res = binding.res();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ libc = "0.2"
|
|||
# tidy-alphabetical-end
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_LibraryLoader",
|
||||
|
|
|
|||
|
|
@ -143,7 +143,6 @@ fn current_dll_path() -> Result<PathBuf, String> {
|
|||
&mut module,
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let mut filename = vec![0; 1024];
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType};
|
|||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_errors::registry::Registry;
|
||||
use rustc_errors::{
|
||||
codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrCode,
|
||||
codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage,
|
||||
ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, LazyFallbackBundle, TerminalUrl,
|
||||
};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use crate::session::Session;
|
||||
use rustc_data_structures::profiling::VerboseTimingGuard;
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
impl Session {
|
||||
pub fn timer(&self, what: &'static str) -> VerboseTimingGuard<'_> {
|
||||
|
|
@ -158,3 +161,18 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
|
|||
|
||||
if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
|
||||
}
|
||||
|
||||
/// Returns whenever rustc was launched by Cargo as opposed to another build system.
|
||||
///
|
||||
/// To be used in diagnostics to avoid printing Cargo specific suggestions to other
|
||||
/// build systems (like Bazel, Buck2, Makefile, ...).
|
||||
pub fn was_invoked_from_cargo() -> bool {
|
||||
static FROM_CARGO: OnceLock<bool> = OnceLock::new();
|
||||
|
||||
// To be able to detect Cargo, we use the simplest and least intrusive
|
||||
// way: we check whenever the `CARGO_CRATE_NAME` env is set.
|
||||
//
|
||||
// Note that it is common in Makefiles to define the `CARGO` env even
|
||||
// though we may not have been called by Cargo, so we avoid using it.
|
||||
*FROM_CARGO.get_or_init(|| std::env::var_os("CARGO_CRATE_NAME").is_some())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ pub mod fatal_error;
|
|||
|
||||
pub mod profiling;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
|
||||
|
||||
|
|
@ -98,6 +99,9 @@ mod tests;
|
|||
pub struct SessionGlobals {
|
||||
symbol_interner: symbol::Interner,
|
||||
span_interner: Lock<span_encoding::SpanInterner>,
|
||||
/// Maps a macro argument token into use of the corresponding metavariable in the macro body.
|
||||
/// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
|
||||
metavar_spans: Lock<FxHashMap<Span, Span>>,
|
||||
hygiene_data: Lock<hygiene::HygieneData>,
|
||||
|
||||
/// A reference to the source map in the `Session`. It's an `Option`
|
||||
|
|
@ -115,6 +119,7 @@ impl SessionGlobals {
|
|||
SessionGlobals {
|
||||
symbol_interner: symbol::Interner::fresh(),
|
||||
span_interner: Lock::new(span_encoding::SpanInterner::default()),
|
||||
metavar_spans: Default::default(),
|
||||
hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
|
||||
source_map: Lock::new(None),
|
||||
}
|
||||
|
|
@ -168,6 +173,11 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
|
|||
// deserialization.
|
||||
scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
|
||||
|
||||
#[inline]
|
||||
pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R {
|
||||
with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock()))
|
||||
}
|
||||
|
||||
// FIXME: We should use this enum or something like it to get rid of the
|
||||
// use of magic `/rust/1.x/...` paths across the board.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)]
|
||||
|
|
@ -824,29 +834,64 @@ impl Span {
|
|||
)
|
||||
}
|
||||
|
||||
/// Check if you can select metavar spans for the given spans to get matching contexts.
|
||||
fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
|
||||
let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied();
|
||||
match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) {
|
||||
(None, None) => {}
|
||||
(Some(meta_a), None) => {
|
||||
let meta_a = meta_a.data();
|
||||
if meta_a.ctxt == b.ctxt {
|
||||
return (meta_a, b);
|
||||
}
|
||||
}
|
||||
(None, Some(meta_b)) => {
|
||||
let meta_b = meta_b.data();
|
||||
if a.ctxt == meta_b.ctxt {
|
||||
return (a, meta_b);
|
||||
}
|
||||
}
|
||||
(Some(meta_a), Some(meta_b)) => {
|
||||
let meta_b = meta_b.data();
|
||||
if a.ctxt == meta_b.ctxt {
|
||||
return (a, meta_b);
|
||||
}
|
||||
let meta_a = meta_a.data();
|
||||
if meta_a.ctxt == b.ctxt {
|
||||
return (meta_a, b);
|
||||
} else if meta_a.ctxt == meta_b.ctxt {
|
||||
return (meta_a, meta_b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(a, b)
|
||||
}
|
||||
|
||||
/// Prepare two spans to a combine operation like `to` or `between`.
|
||||
/// FIXME: consider using declarative macro metavariable spans for the given spans if they are
|
||||
/// better suitable for combining (#119412).
|
||||
fn prepare_to_combine(
|
||||
a_orig: Span,
|
||||
b_orig: Span,
|
||||
) -> Result<(SpanData, SpanData, Option<LocalDefId>), Span> {
|
||||
let (a, b) = (a_orig.data(), b_orig.data());
|
||||
|
||||
if a.ctxt != b.ctxt {
|
||||
// Context mismatches usually happen when procedural macros combine spans copied from
|
||||
// the macro input with spans produced by the macro (`Span::*_site`).
|
||||
// In that case we consider the combined span to be produced by the macro and return
|
||||
// the original macro-produced span as the result.
|
||||
// Otherwise we just fall back to returning the first span.
|
||||
// Combining locations typically doesn't make sense in case of context mismatches.
|
||||
// `is_root` here is a fast path optimization.
|
||||
let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt();
|
||||
return Err(if a_is_callsite { b_orig } else { a_orig });
|
||||
if a.ctxt == b.ctxt {
|
||||
return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
|
||||
}
|
||||
|
||||
let parent = if a.parent == b.parent { a.parent } else { None };
|
||||
Ok((a, b, parent))
|
||||
let (a, b) = Span::try_metavars(a, b, a_orig, b_orig);
|
||||
if a.ctxt == b.ctxt {
|
||||
return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
|
||||
}
|
||||
|
||||
// Context mismatches usually happen when procedural macros combine spans copied from
|
||||
// the macro input with spans produced by the macro (`Span::*_site`).
|
||||
// In that case we consider the combined span to be produced by the macro and return
|
||||
// the original macro-produced span as the result.
|
||||
// Otherwise we just fall back to returning the first span.
|
||||
// Combining locations typically doesn't make sense in case of context mismatches.
|
||||
// `is_root` here is a fast path optimization.
|
||||
let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt();
|
||||
Err(if a_is_callsite { b_orig } else { a_orig })
|
||||
}
|
||||
|
||||
/// This span, but in a larger context, may switch to the metavariable span if suitable.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use super::*;
|
||||
|
||||
use rustc_data_structures::sync::FreezeLock;
|
||||
|
||||
fn init_source_map() -> SourceMap {
|
||||
let sm = SourceMap::new(FilePathMapping::empty());
|
||||
sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string());
|
||||
|
|
|
|||
|
|
@ -3689,6 +3689,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
if let Node::Expr(expr) = tcx.hir_node(arg_hir_id)
|
||||
&& let Some(typeck_results) = &self.typeck_results
|
||||
{
|
||||
if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr
|
||||
&& let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
|
||||
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
|
||||
&& let pred = failed_pred.map_bound(|pred| pred.with_self_ty(tcx, ty))
|
||||
&& self.predicate_must_hold_modulo_regions(&Obligation::misc(
|
||||
tcx, expr.span, body_id, param_env, pred,
|
||||
))
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.with_lo(rcvr.span.hi()),
|
||||
format!(
|
||||
"consider removing this method call, as the receiver has type `{ty}` and \
|
||||
`{pred}` trivially holds",
|
||||
),
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
|
||||
let inner_expr = expr.peel_blocks();
|
||||
let ty = typeck_results
|
||||
|
|
@ -3824,7 +3842,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Node::Expr(expr) = tcx.hir_node(call_hir_id) {
|
||||
if let Node::Expr(expr) = call_node {
|
||||
if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
|
||||
| hir::ExprKind::MethodCall(
|
||||
hir::PathSegment { ident: Ident { span, .. }, .. },
|
||||
|
|
|
|||
|
|
@ -829,7 +829,7 @@
|
|||
# target triples containing `-none`, `nvptx`, `switch`, or `-uefi`.
|
||||
#no-std = <platform-specific> (bool)
|
||||
|
||||
# This is an array of the codegen backends that will be compiled a rustc
|
||||
# This is an array of the codegen backends that will be
|
||||
# compiled for this target, overriding the global rust.codegen-backends option.
|
||||
# See that option for more info.
|
||||
#codegen-backends = rust.codegen-backends (array)
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
// and could hypothetically handle differences between stride and size, but this memory
|
||||
// has already been allocated so we know it can't overflow and currently rust does not
|
||||
// support such types. So we can do better by skipping some checks and avoid an unwrap.
|
||||
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
|
||||
const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
|
||||
unsafe {
|
||||
let align = mem::align_of::<T>();
|
||||
let size = mem::size_of::<T>().unchecked_mul(self.cap.0);
|
||||
|
|
@ -465,7 +465,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
|
||||
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
|
||||
// See current_memory() why this assert is here
|
||||
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
|
||||
const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
|
||||
|
||||
// If shrinking to 0, deallocate the buffer. We don't reach this point
|
||||
// for the T::IS_ZST case since current_memory() will have returned
|
||||
|
|
|
|||
|
|
@ -261,8 +261,9 @@ cfg_if::cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
|
||||
#[allow(static_mut_ref)]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
|
||||
#[cfg_attr(bootstrap, allow(static_mut_ref))]
|
||||
#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
|
||||
pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
|
||||
use core::intrinsics::atomic_store_seqcst;
|
||||
|
||||
|
|
@ -324,8 +325,9 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
|
|||
_CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _);
|
||||
}
|
||||
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
|
||||
#[allow(static_mut_ref)]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
|
||||
#[cfg_attr(bootstrap, allow(static_mut_ref))]
|
||||
#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
|
||||
pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
|
||||
// A null payload here means that we got here from the catch (...) of
|
||||
// __rust_try. This happens when a non-Rust foreign exception is caught.
|
||||
|
|
|
|||
|
|
@ -1,169 +0,0 @@
|
|||
//! This module contains the LLVM intrinsics bindings that provide the functionality for this
|
||||
//! crate.
|
||||
//!
|
||||
//! The LLVM assembly language is documented here: <https://llvm.org/docs/LangRef.html>
|
||||
//!
|
||||
//! A quick glossary of jargon that may appear in this module, mostly paraphrasing LLVM's LangRef:
|
||||
//! - poison: "undefined behavior as a value". specifically, it is like uninit memory (such as padding bytes). it is "safe" to create poison, BUT
|
||||
//! poison MUST NOT be observed from safe code, as operations on poison return poison, like NaN. unlike NaN, which has defined comparisons,
|
||||
//! poison is neither true nor false, and LLVM may also convert it to undef (at which point it is both). so, it can't be conditioned on, either.
|
||||
//! - undef: "a value that is every value". functionally like poison, insofar as Rust is concerned. poison may become this. note:
|
||||
//! this means that division by poison or undef is like division by zero, which means it inflicts...
|
||||
//! - "UB": poison and undef cover most of what people call "UB". "UB" means this operation immediately invalidates the program:
|
||||
//! LLVM is allowed to lower it to `ud2` or other opcodes that may cause an illegal instruction exception, and this is the "good end".
|
||||
//! The "bad end" is that LLVM may reverse time to the moment control flow diverged on a path towards undefined behavior,
|
||||
//! and destroy the other branch, potentially deleting safe code and violating Rust's `unsafe` contract.
|
||||
//!
|
||||
//! Note that according to LLVM, vectors are not arrays, but they are equivalent when stored to and loaded from memory.
|
||||
//!
|
||||
//! Unless stated otherwise, all intrinsics for binary operations require SIMD vectors of equal types and lengths.
|
||||
|
||||
// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
|
||||
// mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner.
|
||||
// The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function.
|
||||
extern "platform-intrinsic" {
|
||||
/// add/fadd
|
||||
pub(crate) fn simd_add<T>(x: T, y: T) -> T;
|
||||
|
||||
/// sub/fsub
|
||||
pub(crate) fn simd_sub<T>(lhs: T, rhs: T) -> T;
|
||||
|
||||
/// mul/fmul
|
||||
pub(crate) fn simd_mul<T>(x: T, y: T) -> T;
|
||||
|
||||
/// udiv/sdiv/fdiv
|
||||
/// ints and uints: {s,u}div incur UB if division by zero occurs.
|
||||
/// ints: sdiv is UB for int::MIN / -1.
|
||||
/// floats: fdiv is never UB, but may create NaNs or infinities.
|
||||
pub(crate) fn simd_div<T>(lhs: T, rhs: T) -> T;
|
||||
|
||||
/// urem/srem/frem
|
||||
/// ints and uints: {s,u}rem incur UB if division by zero occurs.
|
||||
/// ints: srem is UB for int::MIN / -1.
|
||||
/// floats: frem is equivalent to libm::fmod in the "default" floating point environment, sans errno.
|
||||
pub(crate) fn simd_rem<T>(lhs: T, rhs: T) -> T;
|
||||
|
||||
/// shl
|
||||
/// for (u)ints. poison if rhs >= lhs::BITS
|
||||
pub(crate) fn simd_shl<T>(lhs: T, rhs: T) -> T;
|
||||
|
||||
/// ints: ashr
|
||||
/// uints: lshr
|
||||
/// poison if rhs >= lhs::BITS
|
||||
pub(crate) fn simd_shr<T>(lhs: T, rhs: T) -> T;
|
||||
|
||||
/// and
|
||||
pub(crate) fn simd_and<T>(x: T, y: T) -> T;
|
||||
|
||||
/// or
|
||||
pub(crate) fn simd_or<T>(x: T, y: T) -> T;
|
||||
|
||||
/// xor
|
||||
pub(crate) fn simd_xor<T>(x: T, y: T) -> T;
|
||||
|
||||
/// fptoui/fptosi/uitofp/sitofp
|
||||
/// casting floats to integers is truncating, so it is safe to convert values like e.g. 1.5
|
||||
/// but the truncated value must fit in the target type or the result is poison.
|
||||
/// use `simd_as` instead for a cast that performs a saturating conversion.
|
||||
pub(crate) fn simd_cast<T, U>(x: T) -> U;
|
||||
/// follows Rust's `T as U` semantics, including saturating float casts
|
||||
/// which amounts to the same as `simd_cast` for many cases
|
||||
pub(crate) fn simd_as<T, U>(x: T) -> U;
|
||||
|
||||
/// neg/fneg
|
||||
/// ints: ultimately becomes a call to cg_ssa's BuilderMethods::neg. cg_llvm equates this to `simd_sub(Simd::splat(0), x)`.
|
||||
/// floats: LLVM's fneg, which changes the floating point sign bit. Some arches have instructions for it.
|
||||
/// Rust panics for Neg::neg(int::MIN) due to overflow, but it is not UB in LLVM without `nsw`.
|
||||
pub(crate) fn simd_neg<T>(x: T) -> T;
|
||||
|
||||
/// fabs
|
||||
pub(crate) fn simd_fabs<T>(x: T) -> T;
|
||||
|
||||
// minnum/maxnum
|
||||
pub(crate) fn simd_fmin<T>(x: T, y: T) -> T;
|
||||
pub(crate) fn simd_fmax<T>(x: T, y: T) -> T;
|
||||
|
||||
// these return Simd<int, N> with the same BITS size as the inputs
|
||||
pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
|
||||
pub(crate) fn simd_ne<T, U>(x: T, y: T) -> U;
|
||||
pub(crate) fn simd_lt<T, U>(x: T, y: T) -> U;
|
||||
pub(crate) fn simd_le<T, U>(x: T, y: T) -> U;
|
||||
pub(crate) fn simd_gt<T, U>(x: T, y: T) -> U;
|
||||
pub(crate) fn simd_ge<T, U>(x: T, y: T) -> U;
|
||||
|
||||
// shufflevector
|
||||
// idx: LLVM calls it a "shuffle mask vector constant", a vector of i32s
|
||||
pub(crate) fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
|
||||
|
||||
/// llvm.masked.gather
|
||||
/// like a loop of pointer reads
|
||||
/// val: vector of values to select if a lane is masked
|
||||
/// ptr: vector of pointers to read from
|
||||
/// mask: a "wide" mask of integers, selects as if simd_select(mask, read(ptr), val)
|
||||
/// note, the LLVM intrinsic accepts a mask vector of `<N x i1>`
|
||||
/// FIXME: review this if/when we fix up our mask story in general?
|
||||
pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
|
||||
/// llvm.masked.scatter
|
||||
/// like gather, but more spicy, as it writes instead of reads
|
||||
pub(crate) fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
|
||||
|
||||
// {s,u}add.sat
|
||||
pub(crate) fn simd_saturating_add<T>(x: T, y: T) -> T;
|
||||
|
||||
// {s,u}sub.sat
|
||||
pub(crate) fn simd_saturating_sub<T>(lhs: T, rhs: T) -> T;
|
||||
|
||||
// reductions
|
||||
// llvm.vector.reduce.{add,fadd}
|
||||
pub(crate) fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U;
|
||||
// llvm.vector.reduce.{mul,fmul}
|
||||
pub(crate) fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U;
|
||||
#[allow(unused)]
|
||||
pub(crate) fn simd_reduce_all<T>(x: T) -> bool;
|
||||
#[allow(unused)]
|
||||
pub(crate) fn simd_reduce_any<T>(x: T) -> bool;
|
||||
pub(crate) fn simd_reduce_max<T, U>(x: T) -> U;
|
||||
pub(crate) fn simd_reduce_min<T, U>(x: T) -> U;
|
||||
pub(crate) fn simd_reduce_and<T, U>(x: T) -> U;
|
||||
pub(crate) fn simd_reduce_or<T, U>(x: T) -> U;
|
||||
pub(crate) fn simd_reduce_xor<T, U>(x: T) -> U;
|
||||
|
||||
// truncate integer vector to bitmask
|
||||
// `fn simd_bitmask(vector) -> unsigned integer` takes a vector of integers and
|
||||
// returns either an unsigned integer or array of `u8`.
|
||||
// Every element in the vector becomes a single bit in the returned bitmask.
|
||||
// If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
|
||||
// The bit order of the result depends on the byte endianness. LSB-first for little
|
||||
// endian and MSB-first for big endian.
|
||||
//
|
||||
// UB if called on a vector with values other than 0 and -1.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn simd_bitmask<T, U>(x: T) -> U;
|
||||
|
||||
// select
|
||||
// first argument is a vector of integers, -1 (all bits 1) is "true"
|
||||
// logically equivalent to (yes & m) | (no & (m^-1),
|
||||
// but you can use it on floats.
|
||||
pub(crate) fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
|
||||
#[allow(unused)]
|
||||
pub(crate) fn simd_select_bitmask<M, T>(m: M, yes: T, no: T) -> T;
|
||||
|
||||
/// getelementptr (without inbounds)
|
||||
/// equivalent to wrapping_offset
|
||||
pub(crate) fn simd_arith_offset<T, U>(ptr: T, offset: U) -> T;
|
||||
|
||||
/// equivalent to `T as U` semantics, specifically for pointers
|
||||
pub(crate) fn simd_cast_ptr<T, U>(ptr: T) -> U;
|
||||
|
||||
/// expose a pointer as an address
|
||||
pub(crate) fn simd_expose_addr<T, U>(ptr: T) -> U;
|
||||
|
||||
/// convert an exposed address back to a pointer
|
||||
pub(crate) fn simd_from_exposed_addr<T, U>(addr: T) -> U;
|
||||
|
||||
// Integer operations
|
||||
pub(crate) fn simd_bswap<T>(x: T) -> T;
|
||||
pub(crate) fn simd_bitreverse<T>(x: T) -> T;
|
||||
pub(crate) fn simd_ctlz<T>(x: T) -> T;
|
||||
pub(crate) fn simd_cttz<T>(x: T) -> T;
|
||||
}
|
||||
|
|
@ -1,20 +1,38 @@
|
|||
#![no_std]
|
||||
#![feature(
|
||||
const_intrinsic_copy,
|
||||
const_refs_to_cell,
|
||||
const_maybe_uninit_as_mut_ptr,
|
||||
const_mut_refs,
|
||||
convert_float_to_int,
|
||||
core_intrinsics,
|
||||
decl_macro,
|
||||
inline_const,
|
||||
intra_doc_pointers,
|
||||
platform_intrinsics,
|
||||
repr_simd,
|
||||
simd_ffi,
|
||||
staged_api,
|
||||
stdsimd,
|
||||
strict_provenance,
|
||||
ptr_metadata
|
||||
)]
|
||||
#![cfg_attr(
|
||||
all(
|
||||
any(target_arch = "aarch64", target_arch = "arm",),
|
||||
any(
|
||||
all(target_feature = "v6", not(target_feature = "mclass")),
|
||||
all(target_feature = "mclass", target_feature = "dsp"),
|
||||
)
|
||||
),
|
||||
feature(stdarch_arm_dsp)
|
||||
)]
|
||||
#![cfg_attr(
|
||||
all(target_arch = "arm", target_feature = "v7"),
|
||||
feature(stdarch_arm_neon_intrinsics)
|
||||
)]
|
||||
#![cfg_attr(
|
||||
any(target_arch = "powerpc", target_arch = "powerpc64"),
|
||||
feature(stdarch_powerpc)
|
||||
)]
|
||||
#![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
|
||||
#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
|
||||
#![allow(internal_features)]
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@
|
|||
)]
|
||||
mod mask_impl;
|
||||
|
||||
use crate::simd::{
|
||||
cmp::SimdPartialEq, intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount,
|
||||
};
|
||||
use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
|
||||
use core::cmp::Ordering;
|
||||
use core::{fmt, mem};
|
||||
|
||||
|
|
@ -35,7 +33,7 @@ mod sealed {
|
|||
|
||||
fn eq(self, other: Self) -> bool;
|
||||
|
||||
fn as_usize(self) -> usize;
|
||||
fn to_usize(self) -> usize;
|
||||
|
||||
type Unsigned: SimdElement;
|
||||
|
||||
|
|
@ -60,14 +58,23 @@ macro_rules! impl_element {
|
|||
where
|
||||
LaneCount<N>: SupportedLaneCount,
|
||||
{
|
||||
(value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all()
|
||||
// We can't use `Simd` directly, because `Simd`'s functions call this function and
|
||||
// we will end up with an infinite loop.
|
||||
// Safety: `value` is an integer vector
|
||||
unsafe {
|
||||
use core::intrinsics::simd;
|
||||
let falses: Simd<Self, N> = simd::simd_eq(value, Simd::splat(0 as _));
|
||||
let trues: Simd<Self, N> = simd::simd_eq(value, Simd::splat(-1 as _));
|
||||
let valid: Simd<Self, N> = simd::simd_or(falses, trues);
|
||||
simd::simd_reduce_all(valid)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn eq(self, other: Self) -> bool { self == other }
|
||||
|
||||
#[inline]
|
||||
fn as_usize(self) -> usize {
|
||||
fn to_usize(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
|
|
@ -141,8 +148,9 @@ where
|
|||
// but these are "dependently-sized" types, so copy elision it is!
|
||||
unsafe {
|
||||
let bytes: [u8; N] = mem::transmute_copy(&array);
|
||||
let bools: Simd<i8, N> = intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8));
|
||||
Mask::from_int_unchecked(intrinsics::simd_cast(bools))
|
||||
let bools: Simd<i8, N> =
|
||||
core::intrinsics::simd::simd_ne(Simd::from_array(bytes), Simd::splat(0u8));
|
||||
Mask::from_int_unchecked(core::intrinsics::simd::simd_cast(bools))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +168,7 @@ where
|
|||
// This would be hypothetically valid as an "in-place" transmute,
|
||||
// but these are "dependently-sized" types, so copy elision it is!
|
||||
unsafe {
|
||||
let mut bytes: Simd<i8, N> = intrinsics::simd_cast(self.to_int());
|
||||
let mut bytes: Simd<i8, N> = core::intrinsics::simd::simd_cast(self.to_int());
|
||||
bytes &= Simd::splat(1i8);
|
||||
mem::transmute_copy(&bytes)
|
||||
}
|
||||
|
|
@ -175,7 +183,10 @@ where
|
|||
#[must_use = "method returns a new mask and does not mutate the original value"]
|
||||
pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self {
|
||||
// Safety: the caller must confirm this invariant
|
||||
unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
|
||||
unsafe {
|
||||
core::intrinsics::assume(<T as Sealed>::valid(value));
|
||||
Self(mask_impl::Mask::from_int_unchecked(value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a vector of integers to a mask, where 0 represents `false` and -1
|
||||
|
|
@ -374,15 +385,17 @@ where
|
|||
);
|
||||
|
||||
// Safety: the input and output are integer vectors
|
||||
let index: Simd<T, N> = unsafe { intrinsics::simd_cast(index) };
|
||||
let index: Simd<T, N> = unsafe { core::intrinsics::simd::simd_cast(index) };
|
||||
|
||||
let masked_index = self.select(index, Self::splat(true).to_int());
|
||||
|
||||
// Safety: the input and output are integer vectors
|
||||
let masked_index: Simd<T::Unsigned, N> = unsafe { intrinsics::simd_cast(masked_index) };
|
||||
let masked_index: Simd<T::Unsigned, N> =
|
||||
unsafe { core::intrinsics::simd::simd_cast(masked_index) };
|
||||
|
||||
// Safety: the input is an integer vector
|
||||
let min_index: T::Unsigned = unsafe { intrinsics::simd_reduce_min(masked_index) };
|
||||
let min_index: T::Unsigned =
|
||||
unsafe { core::intrinsics::simd::simd_reduce_min(masked_index) };
|
||||
|
||||
// Safety: the return value is the unsigned version of T
|
||||
let min_index: T = unsafe { core::mem::transmute_copy(&min_index) };
|
||||
|
|
@ -390,7 +403,7 @@ where
|
|||
if min_index.eq(T::TRUE) {
|
||||
None
|
||||
} else {
|
||||
Some(min_index.as_usize())
|
||||
Some(min_index.to_usize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#![allow(unused_imports)]
|
||||
use super::MaskElement;
|
||||
use crate::simd::intrinsics;
|
||||
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
|
|
@ -109,14 +108,18 @@ where
|
|||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
pub fn to_int(self) -> Simd<T, N> {
|
||||
unsafe {
|
||||
intrinsics::simd_select_bitmask(self.0, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
|
||||
core::intrinsics::simd::simd_select_bitmask(
|
||||
self.0,
|
||||
Simd::splat(T::TRUE),
|
||||
Simd::splat(T::FALSE),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use = "method returns a new mask and does not mutate the original value"]
|
||||
pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self {
|
||||
unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) }
|
||||
unsafe { Self(core::intrinsics::simd::simd_bitmask(value), PhantomData) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Masks that take up full SIMD vector registers.
|
||||
|
||||
use crate::simd::intrinsics;
|
||||
use crate::simd::{LaneCount, MaskElement, Simd, SupportedLaneCount};
|
||||
|
||||
#[repr(transparent)]
|
||||
|
|
@ -138,7 +137,7 @@ where
|
|||
U: MaskElement,
|
||||
{
|
||||
// Safety: masks are simply integer vectors of 0 and -1, and we can cast the element type.
|
||||
unsafe { Mask(intrinsics::simd_cast(self.0)) }
|
||||
unsafe { Mask(core::intrinsics::simd::simd_cast(self.0)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -150,13 +149,16 @@ where
|
|||
unsafe {
|
||||
// Compute the bitmask
|
||||
let mut bytes: <LaneCount<N> as SupportedLaneCount>::BitMask =
|
||||
intrinsics::simd_bitmask(self.0);
|
||||
core::intrinsics::simd::simd_bitmask(self.0);
|
||||
|
||||
// LLVM assumes bit order should match endianness
|
||||
if cfg!(target_endian = "big") {
|
||||
for x in bytes.as_mut() {
|
||||
*x = x.reverse_bits()
|
||||
}
|
||||
if N % 8 > 0 {
|
||||
bytes.as_mut()[N / 8] >>= 8 - N % 8;
|
||||
}
|
||||
}
|
||||
|
||||
bitmask.as_mut_array()[..bytes.as_ref().len()].copy_from_slice(bytes.as_ref());
|
||||
|
|
@ -180,10 +182,13 @@ where
|
|||
for x in bytes.as_mut() {
|
||||
*x = x.reverse_bits();
|
||||
}
|
||||
if N % 8 > 0 {
|
||||
bytes.as_mut()[N / 8] >>= 8 - N % 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the regular mask
|
||||
Self::from_int_unchecked(intrinsics::simd_select_bitmask(
|
||||
Self::from_int_unchecked(core::intrinsics::simd::simd_select_bitmask(
|
||||
bytes,
|
||||
Self::splat(true).to_int(),
|
||||
Self::splat(false).to_int(),
|
||||
|
|
@ -199,7 +204,7 @@ where
|
|||
let resized = self.to_int().resize::<M>(T::FALSE);
|
||||
|
||||
// Safety: `resized` is an integer vector with length M, which must match T
|
||||
let bitmask: U = unsafe { intrinsics::simd_bitmask(resized) };
|
||||
let bitmask: U = unsafe { core::intrinsics::simd::simd_bitmask(resized) };
|
||||
|
||||
// LLVM assumes bit order should match endianness
|
||||
if cfg!(target_endian = "big") {
|
||||
|
|
@ -223,7 +228,7 @@ where
|
|||
|
||||
// SAFETY: `mask` is the correct bitmask type for a u64 bitmask
|
||||
let mask: Simd<T, M> = unsafe {
|
||||
intrinsics::simd_select_bitmask(
|
||||
core::intrinsics::simd::simd_select_bitmask(
|
||||
bitmask,
|
||||
Simd::<T, M>::splat(T::TRUE),
|
||||
Simd::<T, M>::splat(T::FALSE),
|
||||
|
|
@ -274,14 +279,14 @@ where
|
|||
#[must_use = "method returns a new bool and does not mutate the original value"]
|
||||
pub fn any(self) -> bool {
|
||||
// Safety: use `self` as an integer vector
|
||||
unsafe { intrinsics::simd_reduce_any(self.to_int()) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_any(self.to_int()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
pub fn all(self) -> bool {
|
||||
// Safety: use `self` as an integer vector
|
||||
unsafe { intrinsics::simd_reduce_all(self.to_int()) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_all(self.to_int()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +311,7 @@ where
|
|||
#[must_use = "method returns a new mask and does not mutate the original value"]
|
||||
fn bitand(self, rhs: Self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
|
||||
unsafe { Self(core::intrinsics::simd::simd_and(self.0, rhs.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +325,7 @@ where
|
|||
#[must_use = "method returns a new mask and does not mutate the original value"]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
|
||||
unsafe { Self(core::intrinsics::simd::simd_or(self.0, rhs.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +339,7 @@ where
|
|||
#[must_use = "method returns a new mask and does not mutate the original value"]
|
||||
fn bitxor(self, rhs: Self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
|
||||
unsafe { Self(core::intrinsics::simd::simd_xor(self.0, rhs.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
#[macro_use]
|
||||
mod swizzle;
|
||||
|
||||
pub(crate) mod intrinsics;
|
||||
|
||||
mod alias;
|
||||
mod cast;
|
||||
mod fmt;
|
||||
|
|
@ -27,8 +25,6 @@ pub mod simd {
|
|||
|
||||
pub mod cmp;
|
||||
|
||||
pub(crate) use crate::core_simd::intrinsics;
|
||||
|
||||
pub use crate::core_simd::alias::*;
|
||||
pub use crate::core_simd::cast::*;
|
||||
pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ where
|
|||
macro_rules! unsafe_base {
|
||||
($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
|
||||
// Safety: $lhs and $rhs are vectors
|
||||
unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) }
|
||||
unsafe { core::intrinsics::simd::$simd_call($lhs, $rhs) }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ macro_rules! wrap_bitshift {
|
|||
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||
// Safety: $lhs and the bitand result are vectors
|
||||
unsafe {
|
||||
$crate::simd::intrinsics::$simd_call(
|
||||
core::intrinsics::simd::$simd_call(
|
||||
$lhs,
|
||||
$rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)),
|
||||
)
|
||||
|
|
@ -97,7 +97,7 @@ macro_rules! int_divrem_guard {
|
|||
$rhs
|
||||
};
|
||||
// Safety: $lhs and rhs are vectors
|
||||
unsafe { $crate::simd::intrinsics::$simd_call($lhs, rhs) }
|
||||
unsafe { core::intrinsics::simd::$simd_call($lhs, rhs) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::simd::intrinsics;
|
||||
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
|
||||
use core::ops::{Neg, Not}; // unary ops
|
||||
|
||||
|
|
@ -15,7 +14,7 @@ macro_rules! neg {
|
|||
#[must_use = "operator returns a new vector without mutating the input"]
|
||||
fn neg(self) -> Self::Output {
|
||||
// Safety: `self` is a signed vector
|
||||
unsafe { intrinsics::simd_neg(self) }
|
||||
unsafe { core::intrinsics::simd::simd_neg(self) }
|
||||
}
|
||||
})*
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::simd::intrinsics;
|
||||
use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
|
||||
|
||||
impl<T, const N: usize> Mask<T, N>
|
||||
|
|
@ -29,7 +28,7 @@ where
|
|||
{
|
||||
// Safety: The mask has been cast to a vector of integers,
|
||||
// and the operands to select between are vectors of the same type and length.
|
||||
unsafe { intrinsics::simd_select(self.to_int(), true_values, false_values) }
|
||||
unsafe { core::intrinsics::simd::simd_select(self.to_int(), true_values, false_values) }
|
||||
}
|
||||
|
||||
/// Choose elements from two masks.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::simd::{
|
||||
intrinsics,
|
||||
ptr::{SimdConstPtr, SimdMutPtr},
|
||||
LaneCount, Mask, Simd, SimdElement, SupportedLaneCount,
|
||||
};
|
||||
|
|
@ -31,14 +30,14 @@ macro_rules! impl_number {
|
|||
fn simd_eq(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_eq(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ne(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ne(self, other)) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
@ -60,14 +59,14 @@ macro_rules! impl_mask {
|
|||
fn simd_eq(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Self::from_int_unchecked(intrinsics::simd_eq(self.to_int(), other.to_int())) }
|
||||
unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_eq(self.to_int(), other.to_int())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ne(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Self::from_int_unchecked(intrinsics::simd_ne(self.to_int(), other.to_int())) }
|
||||
unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_ne(self.to_int(), other.to_int())) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use crate::simd::{
|
||||
cmp::SimdPartialEq,
|
||||
intrinsics,
|
||||
ptr::{SimdConstPtr, SimdMutPtr},
|
||||
LaneCount, Mask, Simd, SupportedLaneCount,
|
||||
};
|
||||
|
|
@ -57,28 +56,28 @@ macro_rules! impl_integer {
|
|||
fn simd_lt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_lt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_le(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_le(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_gt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_gt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ge(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ge(self, other)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,28 +122,28 @@ macro_rules! impl_float {
|
|||
fn simd_lt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_lt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_le(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_le(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_gt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_gt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ge(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
|
||||
unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ge(self, other)) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
@ -164,28 +163,28 @@ macro_rules! impl_mask {
|
|||
fn simd_lt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Self::from_int_unchecked(intrinsics::simd_lt(self.to_int(), other.to_int())) }
|
||||
unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_lt(self.to_int(), other.to_int())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_le(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Self::from_int_unchecked(intrinsics::simd_le(self.to_int(), other.to_int())) }
|
||||
unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_le(self.to_int(), other.to_int())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_gt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Self::from_int_unchecked(intrinsics::simd_gt(self.to_int(), other.to_int())) }
|
||||
unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_gt(self.to_int(), other.to_int())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ge(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Self::from_int_unchecked(intrinsics::simd_ge(self.to_int(), other.to_int())) }
|
||||
unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_ge(self.to_int(), other.to_int())) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{
|
||||
cmp::{SimdPartialEq, SimdPartialOrd},
|
||||
intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount,
|
||||
LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount,
|
||||
};
|
||||
|
||||
/// Operations on SIMD vectors of floats.
|
||||
|
|
@ -259,7 +259,7 @@ macro_rules! impl_trait {
|
|||
fn cast<T: SimdCast>(self) -> Self::Cast<T>
|
||||
{
|
||||
// Safety: supported types are guaranteed by SimdCast
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
unsafe { core::intrinsics::simd::simd_as(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -269,7 +269,7 @@ macro_rules! impl_trait {
|
|||
Self::Scalar: core::convert::FloatToInt<I>,
|
||||
{
|
||||
// Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants
|
||||
unsafe { intrinsics::simd_cast(self) }
|
||||
unsafe { core::intrinsics::simd::simd_cast(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -289,7 +289,7 @@ macro_rules! impl_trait {
|
|||
#[inline]
|
||||
fn abs(self) -> Self {
|
||||
// Safety: `self` is a float vector
|
||||
unsafe { intrinsics::simd_fabs(self) }
|
||||
unsafe { core::intrinsics::simd::simd_fabs(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -363,13 +363,13 @@ macro_rules! impl_trait {
|
|||
#[inline]
|
||||
fn simd_min(self, other: Self) -> Self {
|
||||
// Safety: `self` and `other` are float vectors
|
||||
unsafe { intrinsics::simd_fmin(self, other) }
|
||||
unsafe { core::intrinsics::simd::simd_fmin(self, other) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_max(self, other: Self) -> Self {
|
||||
// Safety: `self` and `other` are floating point vectors
|
||||
unsafe { intrinsics::simd_fmax(self, other) }
|
||||
unsafe { core::intrinsics::simd::simd_fmax(self, other) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -391,7 +391,7 @@ macro_rules! impl_trait {
|
|||
self.as_array().iter().sum()
|
||||
} else {
|
||||
// Safety: `self` is a float vector
|
||||
unsafe { intrinsics::simd_reduce_add_ordered(self, 0.) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0.) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -402,20 +402,20 @@ macro_rules! impl_trait {
|
|||
self.as_array().iter().product()
|
||||
} else {
|
||||
// Safety: `self` is a float vector
|
||||
unsafe { intrinsics::simd_reduce_mul_ordered(self, 1.) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1.) }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_max(self) -> Self::Scalar {
|
||||
// Safety: `self` is a float vector
|
||||
unsafe { intrinsics::simd_reduce_max(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_max(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_min(self) -> Self::Scalar {
|
||||
// Safety: `self` is a float vector
|
||||
unsafe { intrinsics::simd_reduce_min(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_min(self) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{
|
||||
cmp::SimdPartialOrd, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
|
||||
cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
|
||||
SupportedLaneCount,
|
||||
};
|
||||
|
||||
|
|
@ -237,19 +237,19 @@ macro_rules! impl_trait {
|
|||
#[inline]
|
||||
fn cast<T: SimdCast>(self) -> Self::Cast<T> {
|
||||
// Safety: supported types are guaranteed by SimdCast
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
unsafe { core::intrinsics::simd::simd_as(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn saturating_add(self, second: Self) -> Self {
|
||||
// Safety: `self` is a vector
|
||||
unsafe { intrinsics::simd_saturating_add(self, second) }
|
||||
unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn saturating_sub(self, second: Self) -> Self {
|
||||
// Safety: `self` is a vector
|
||||
unsafe { intrinsics::simd_saturating_sub(self, second) }
|
||||
unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -293,55 +293,55 @@ macro_rules! impl_trait {
|
|||
#[inline]
|
||||
fn reduce_sum(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_product(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_max(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_max(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_max(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_min(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_min(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_min(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_and(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_and(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_and(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_or(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_or(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_or(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_xor(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_xor(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn swap_bytes(self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_bswap(self) }
|
||||
unsafe { core::intrinsics::simd::simd_bswap(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reverse_bits(self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_bitreverse(self) }
|
||||
unsafe { core::intrinsics::simd::simd_bitreverse(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
|
||||
use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
|
||||
|
||||
/// Operations on SIMD vectors of unsigned integers.
|
||||
pub trait SimdUint: Copy + Sealed {
|
||||
|
|
@ -117,7 +117,7 @@ macro_rules! impl_trait {
|
|||
#[inline]
|
||||
fn cast<T: SimdCast>(self) -> Self::Cast<T> {
|
||||
// Safety: supported types are guaranteed by SimdCast
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
unsafe { core::intrinsics::simd::simd_as(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -129,79 +129,79 @@ macro_rules! impl_trait {
|
|||
#[inline]
|
||||
fn saturating_add(self, second: Self) -> Self {
|
||||
// Safety: `self` is a vector
|
||||
unsafe { intrinsics::simd_saturating_add(self, second) }
|
||||
unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn saturating_sub(self, second: Self) -> Self {
|
||||
// Safety: `self` is a vector
|
||||
unsafe { intrinsics::simd_saturating_sub(self, second) }
|
||||
unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_sum(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_product(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_max(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_max(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_max(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_min(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_min(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_min(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_and(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_and(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_and(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_or(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_or(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_or(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_xor(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_reduce_xor(self) }
|
||||
unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn swap_bytes(self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_bswap(self) }
|
||||
unsafe { core::intrinsics::simd::simd_bswap(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reverse_bits(self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_bitreverse(self) }
|
||||
unsafe { core::intrinsics::simd::simd_bitreverse(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn leading_zeros(self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_ctlz(self) }
|
||||
unsafe { core::intrinsics::simd::simd_ctlz(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn trailing_zeros(self) -> Self {
|
||||
// Safety: `self` is an integer vector
|
||||
unsafe { intrinsics::simd_cttz(self) }
|
||||
unsafe { core::intrinsics::simd::simd_cttz(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{
|
||||
cmp::SimdPartialEq, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount,
|
||||
};
|
||||
use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount};
|
||||
|
||||
/// Operations on SIMD vectors of constant pointers.
|
||||
pub trait SimdConstPtr: Copy + Sealed {
|
||||
|
|
@ -103,13 +101,13 @@ where
|
|||
assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
|
||||
|
||||
// Safety: pointers can be cast
|
||||
unsafe { intrinsics::simd_cast_ptr(self) }
|
||||
unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cast_mut(self) -> Self::MutPtr {
|
||||
// Safety: pointers can be cast
|
||||
unsafe { intrinsics::simd_cast_ptr(self) }
|
||||
unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -135,19 +133,19 @@ where
|
|||
#[inline]
|
||||
fn expose_addr(self) -> Self::Usize {
|
||||
// Safety: `self` is a pointer vector
|
||||
unsafe { intrinsics::simd_expose_addr(self) }
|
||||
unsafe { core::intrinsics::simd::simd_expose_addr(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_exposed_addr(addr: Self::Usize) -> Self {
|
||||
// Safety: `self` is a pointer vector
|
||||
unsafe { intrinsics::simd_from_exposed_addr(addr) }
|
||||
unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn wrapping_offset(self, count: Self::Isize) -> Self {
|
||||
// Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
|
||||
unsafe { intrinsics::simd_arith_offset(self, count) }
|
||||
unsafe { core::intrinsics::simd::simd_arith_offset(self, count) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{
|
||||
cmp::SimdPartialEq, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount,
|
||||
};
|
||||
use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount};
|
||||
|
||||
/// Operations on SIMD vectors of mutable pointers.
|
||||
pub trait SimdMutPtr: Copy + Sealed {
|
||||
|
|
@ -100,13 +98,13 @@ where
|
|||
assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
|
||||
|
||||
// Safety: pointers can be cast
|
||||
unsafe { intrinsics::simd_cast_ptr(self) }
|
||||
unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cast_const(self) -> Self::ConstPtr {
|
||||
// Safety: pointers can be cast
|
||||
unsafe { intrinsics::simd_cast_ptr(self) }
|
||||
unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -132,19 +130,19 @@ where
|
|||
#[inline]
|
||||
fn expose_addr(self) -> Self::Usize {
|
||||
// Safety: `self` is a pointer vector
|
||||
unsafe { intrinsics::simd_expose_addr(self) }
|
||||
unsafe { core::intrinsics::simd::simd_expose_addr(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_exposed_addr(addr: Self::Usize) -> Self {
|
||||
// Safety: `self` is a pointer vector
|
||||
unsafe { intrinsics::simd_from_exposed_addr(addr) }
|
||||
unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn wrapping_offset(self, count: Self::Isize) -> Self {
|
||||
// Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
|
||||
unsafe { intrinsics::simd_arith_offset(self, count) }
|
||||
unsafe { core::intrinsics::simd::simd_arith_offset(self, count) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::simd::intrinsics;
|
||||
use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
|
||||
|
||||
/// Constructs a new SIMD vector by copying elements from selected elements in other vectors.
|
||||
|
|
@ -88,7 +87,7 @@ pub trait Swizzle<const N: usize> {
|
|||
{
|
||||
// Safety: `vector` is a vector, and the index is a const array of u32.
|
||||
unsafe {
|
||||
intrinsics::simd_shuffle(
|
||||
core::intrinsics::simd::simd_shuffle(
|
||||
vector,
|
||||
vector,
|
||||
const {
|
||||
|
|
@ -124,7 +123,7 @@ pub trait Swizzle<const N: usize> {
|
|||
{
|
||||
// Safety: `first` and `second` are vectors, and the index is a const array of u32.
|
||||
unsafe {
|
||||
intrinsics::simd_shuffle(
|
||||
core::intrinsics::simd::simd_shuffle(
|
||||
first,
|
||||
second,
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ where
|
|||
))]
|
||||
8 => transize(vtbl1_u8, self, idxs),
|
||||
#[cfg(target_feature = "ssse3")]
|
||||
16 => transize(x86::_mm_shuffle_epi8, self, idxs),
|
||||
16 => transize(x86::_mm_shuffle_epi8, self, zeroing_idxs(idxs)),
|
||||
#[cfg(target_feature = "simd128")]
|
||||
16 => transize(wasm::i8x16_swizzle, self, idxs),
|
||||
#[cfg(all(
|
||||
|
|
@ -54,9 +54,9 @@ where
|
|||
))]
|
||||
16 => transize(vqtbl1q_u8, self, idxs),
|
||||
#[cfg(all(target_feature = "avx2", not(target_feature = "avx512vbmi")))]
|
||||
32 => transize_raw(avx2_pshufb, self, idxs),
|
||||
32 => transize(avx2_pshufb, self, idxs),
|
||||
#[cfg(all(target_feature = "avx512vl", target_feature = "avx512vbmi"))]
|
||||
32 => transize(x86::_mm256_permutexvar_epi8, self, idxs),
|
||||
32 => transize(x86::_mm256_permutexvar_epi8, zeroing_idxs(idxs), self),
|
||||
// Notable absence: avx512bw shuffle
|
||||
// If avx512bw is available, odds of avx512vbmi are good
|
||||
// FIXME: initial AVX512VBMI variant didn't actually pass muster
|
||||
|
|
@ -129,45 +129,25 @@ unsafe fn avx2_pshufb(bytes: Simd<u8, 32>, idxs: Simd<u8, 32>) -> Simd<u8, 32> {
|
|||
#[inline(always)]
|
||||
unsafe fn transize<T, const N: usize>(
|
||||
f: unsafe fn(T, T) -> T,
|
||||
bytes: Simd<u8, N>,
|
||||
idxs: Simd<u8, N>,
|
||||
a: Simd<u8, N>,
|
||||
b: Simd<u8, N>,
|
||||
) -> Simd<u8, N>
|
||||
where
|
||||
LaneCount<N>: SupportedLaneCount,
|
||||
{
|
||||
let idxs = zeroing_idxs(idxs);
|
||||
// SAFETY: Same obligation to use this function as to use mem::transmute_copy.
|
||||
unsafe { mem::transmute_copy(&f(mem::transmute_copy(&bytes), mem::transmute_copy(&idxs))) }
|
||||
unsafe { mem::transmute_copy(&f(mem::transmute_copy(&a), mem::transmute_copy(&b))) }
|
||||
}
|
||||
|
||||
/// Make indices that yield 0 for this architecture
|
||||
/// Make indices that yield 0 for x86
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[allow(unused)]
|
||||
#[inline(always)]
|
||||
fn zeroing_idxs<const N: usize>(idxs: Simd<u8, N>) -> Simd<u8, N>
|
||||
where
|
||||
LaneCount<N>: SupportedLaneCount,
|
||||
{
|
||||
// On x86, make sure the top bit is set.
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
let idxs = {
|
||||
use crate::simd::cmp::SimdPartialOrd;
|
||||
idxs.simd_lt(Simd::splat(N as u8))
|
||||
.select(idxs, Simd::splat(u8::MAX))
|
||||
};
|
||||
// Simply do nothing on most architectures.
|
||||
idxs
|
||||
}
|
||||
|
||||
/// As transize but no implicit call to `zeroing_idxs`.
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
unsafe fn transize_raw<T, const N: usize>(
|
||||
f: unsafe fn(T, T) -> T,
|
||||
bytes: Simd<u8, N>,
|
||||
idxs: Simd<u8, N>,
|
||||
) -> Simd<u8, N>
|
||||
where
|
||||
LaneCount<N>: SupportedLaneCount,
|
||||
{
|
||||
// SAFETY: Same obligation to use this function as to use mem::transmute_copy.
|
||||
unsafe { mem::transmute_copy(&f(mem::transmute_copy(&bytes), mem::transmute_copy(&idxs))) }
|
||||
use crate::simd::cmp::SimdPartialOrd;
|
||||
idxs.simd_lt(Simd::splat(N as u8))
|
||||
.select(idxs, Simd::splat(u8::MAX))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use crate::simd::{
|
||||
cmp::SimdPartialOrd,
|
||||
intrinsics,
|
||||
ptr::{SimdConstPtr, SimdMutPtr},
|
||||
LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle,
|
||||
};
|
||||
|
|
@ -194,7 +193,7 @@ where
|
|||
/// With padding, `read_unaligned` will read past the end of an array of N elements.
|
||||
///
|
||||
/// # Safety
|
||||
/// Reading `ptr` must be safe, as if by `<*const [T; N]>::read_unaligned`.
|
||||
/// Reading `ptr` must be safe, as if by `<*const [T; N]>::read`.
|
||||
#[inline]
|
||||
const unsafe fn load(ptr: *const [T; N]) -> Self {
|
||||
// There are potentially simpler ways to write this function, but this should result in
|
||||
|
|
@ -215,7 +214,7 @@ where
|
|||
/// See `load` as to why this function is necessary.
|
||||
///
|
||||
/// # Safety
|
||||
/// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write_unaligned`.
|
||||
/// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write`.
|
||||
#[inline]
|
||||
const unsafe fn store(self, ptr: *mut [T; N]) {
|
||||
// There are potentially simpler ways to write this function, but this should result in
|
||||
|
|
@ -491,7 +490,7 @@ where
|
|||
or: Self,
|
||||
) -> Self {
|
||||
// Safety: The caller is responsible for upholding all invariants
|
||||
unsafe { intrinsics::simd_gather(or, source, enable.to_int()) }
|
||||
unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_int()) }
|
||||
}
|
||||
|
||||
/// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
|
||||
|
|
@ -650,7 +649,7 @@ where
|
|||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub unsafe fn scatter_select_ptr(self, dest: Simd<*mut T, N>, enable: Mask<isize, N>) {
|
||||
// Safety: The caller is responsible for upholding all invariants
|
||||
unsafe { intrinsics::simd_scatter(self, dest, enable.to_int()) }
|
||||
unsafe { core::intrinsics::simd::simd_scatter(self, dest, enable.to_int()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -692,7 +691,8 @@ where
|
|||
fn eq(&self, other: &Self) -> bool {
|
||||
// Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
|
||||
let mask = unsafe {
|
||||
let tfvec: Simd<<T as SimdElement>::Mask, N> = intrinsics::simd_eq(*self, *other);
|
||||
let tfvec: Simd<<T as SimdElement>::Mask, N> =
|
||||
core::intrinsics::simd::simd_eq(*self, *other);
|
||||
Mask::from_int_unchecked(tfvec)
|
||||
};
|
||||
|
||||
|
|
@ -705,7 +705,8 @@ where
|
|||
fn ne(&self, other: &Self) -> bool {
|
||||
// Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
|
||||
let mask = unsafe {
|
||||
let tfvec: Simd<<T as SimdElement>::Mask, N> = intrinsics::simd_ne(*self, *other);
|
||||
let tfvec: Simd<<T as SimdElement>::Mask, N> =
|
||||
core::intrinsics::simd::simd_ne(*self, *other);
|
||||
Mask::from_int_unchecked(tfvec)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,19 @@ macro_rules! test_mask_api {
|
|||
assert_eq!(Mask::<$type, 2>::from_bitmask(bitmask), mask);
|
||||
}
|
||||
|
||||
#[cfg(feature = "all_lane_counts")]
|
||||
#[test]
|
||||
fn roundtrip_bitmask_conversion_odd() {
|
||||
let values = [
|
||||
true, false, true, false, true, true, false, false, false, true, true,
|
||||
];
|
||||
let mask = Mask::<$type, 11>::from_array(values);
|
||||
let bitmask = mask.to_bitmask();
|
||||
assert_eq!(bitmask, 0b11000110101);
|
||||
assert_eq!(Mask::<$type, 11>::from_bitmask(bitmask), mask);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn cast() {
|
||||
fn cast_impl<T: core_simd::simd::MaskElement>()
|
||||
|
|
@ -134,6 +147,35 @@ macro_rules! test_mask_api {
|
|||
assert_eq!(bitmask.resize::<2>(0).to_ne_bytes()[..2], [0b01001001, 0b10000011]);
|
||||
assert_eq!(Mask::<$type, 16>::from_bitmask_vector(bitmask), mask);
|
||||
}
|
||||
|
||||
// rust-lang/portable-simd#379
|
||||
#[test]
|
||||
fn roundtrip_bitmask_vector_conversion_small() {
|
||||
use core_simd::simd::ToBytes;
|
||||
let values = [
|
||||
true, false, true, true
|
||||
];
|
||||
let mask = Mask::<$type, 4>::from_array(values);
|
||||
let bitmask = mask.to_bitmask_vector();
|
||||
assert_eq!(bitmask.resize::<1>(0).to_ne_bytes()[0], 0b00001101);
|
||||
assert_eq!(Mask::<$type, 4>::from_bitmask_vector(bitmask), mask);
|
||||
}
|
||||
|
||||
/* FIXME doesn't work with non-powers-of-two, yet
|
||||
// rust-lang/portable-simd#379
|
||||
#[cfg(feature = "all_lane_counts")]
|
||||
#[test]
|
||||
fn roundtrip_bitmask_vector_conversion_odd() {
|
||||
use core_simd::simd::ToBytes;
|
||||
let values = [
|
||||
true, false, true, false, true, true, false, false, false, true, true,
|
||||
];
|
||||
let mask = Mask::<$type, 11>::from_array(values);
|
||||
let bitmask = mask.to_bitmask_vector();
|
||||
assert_eq!(bitmask.resize::<2>(0).to_ne_bytes()[..2], [0b00110101, 0b00000110]);
|
||||
assert_eq!(Mask::<$type, 11>::from_bitmask_vector(bitmask), mask);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg_attr(feature = "as_crate", no_std)] // We are std!
|
||||
#![cfg_attr(
|
||||
feature = "as_crate",
|
||||
feature(platform_intrinsics),
|
||||
feature(core_intrinsics),
|
||||
feature(portable_simd),
|
||||
allow(internal_features)
|
||||
)]
|
||||
|
|
@ -10,6 +10,8 @@ use core::simd;
|
|||
#[cfg(feature = "as_crate")]
|
||||
use core_simd::simd;
|
||||
|
||||
use core::intrinsics::simd as intrinsics;
|
||||
|
||||
use simd::{LaneCount, Simd, SupportedLaneCount};
|
||||
|
||||
#[cfg(feature = "as_crate")]
|
||||
|
|
@ -22,28 +24,6 @@ use experimental as sealed;
|
|||
|
||||
use crate::sealed::Sealed;
|
||||
|
||||
// "platform intrinsics" are essentially "codegen intrinsics"
|
||||
// each of these may be scalarized and lowered to a libm call
|
||||
extern "platform-intrinsic" {
|
||||
// ceil
|
||||
fn simd_ceil<T>(x: T) -> T;
|
||||
|
||||
// floor
|
||||
fn simd_floor<T>(x: T) -> T;
|
||||
|
||||
// round
|
||||
fn simd_round<T>(x: T) -> T;
|
||||
|
||||
// trunc
|
||||
fn simd_trunc<T>(x: T) -> T;
|
||||
|
||||
// fsqrt
|
||||
fn simd_fsqrt<T>(x: T) -> T;
|
||||
|
||||
// fma
|
||||
fn simd_fma<T>(x: T, y: T, z: T) -> T;
|
||||
}
|
||||
|
||||
/// This trait provides a possibly-temporary implementation of float functions
|
||||
/// that may, in the absence of hardware support, canonicalize to calling an
|
||||
/// operating system's `math.h` dynamically-loaded library (also known as a
|
||||
|
|
@ -74,7 +54,7 @@ pub trait StdFloat: Sealed + Sized {
|
|||
#[inline]
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self {
|
||||
unsafe { simd_fma(self, a, b) }
|
||||
unsafe { intrinsics::simd_fma(self, a, b) }
|
||||
}
|
||||
|
||||
/// Produces a vector where every lane has the square root value
|
||||
|
|
@ -82,35 +62,35 @@ pub trait StdFloat: Sealed + Sized {
|
|||
#[inline]
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
fn sqrt(self) -> Self {
|
||||
unsafe { simd_fsqrt(self) }
|
||||
unsafe { intrinsics::simd_fsqrt(self) }
|
||||
}
|
||||
|
||||
/// Returns the smallest integer greater than or equal to each lane.
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
#[inline]
|
||||
fn ceil(self) -> Self {
|
||||
unsafe { simd_ceil(self) }
|
||||
unsafe { intrinsics::simd_ceil(self) }
|
||||
}
|
||||
|
||||
/// Returns the largest integer value less than or equal to each lane.
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
#[inline]
|
||||
fn floor(self) -> Self {
|
||||
unsafe { simd_floor(self) }
|
||||
unsafe { intrinsics::simd_floor(self) }
|
||||
}
|
||||
|
||||
/// Rounds to the nearest integer value. Ties round toward zero.
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
#[inline]
|
||||
fn round(self) -> Self {
|
||||
unsafe { simd_round(self) }
|
||||
unsafe { intrinsics::simd_round(self) }
|
||||
}
|
||||
|
||||
/// Returns the floating point's integer value, with its fractional part removed.
|
||||
#[must_use = "method returns a new vector and does not mutate the original value"]
|
||||
#[inline]
|
||||
fn trunc(self) -> Self {
|
||||
unsafe { simd_trunc(self) }
|
||||
unsafe { intrinsics::simd_trunc(self) }
|
||||
}
|
||||
|
||||
/// Returns the floating point's fractional value, with its integer part removed.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
#![feature(stdsimd, powerpc_target_feature)]
|
||||
#![feature(powerpc_target_feature)]
|
||||
#![cfg_attr(
|
||||
any(target_arch = "powerpc", target_arch = "powerpc64"),
|
||||
feature(stdarch_powerpc)
|
||||
)]
|
||||
|
||||
pub mod array;
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ pub fn current_dir() -> io::Result<PathBuf> {
|
|||
/// assert!(env::set_current_dir(&root).is_ok());
|
||||
/// println!("Successfully changed working directory to {}!", root.display());
|
||||
/// ```
|
||||
#[doc(alias = "chdir")]
|
||||
#[doc(alias = "chdir", alias = "SetCurrentDirectory", alias = "SetCurrentDirectoryW")]
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
os_imp::chdir(path.as_ref())
|
||||
|
|
@ -655,6 +655,7 @@ pub fn home_dir() -> Option<PathBuf> {
|
|||
/// }
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[doc(alias = "GetTempPath", alias = "GetTempPath2")]
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
os_imp::temp_dir()
|
||||
|
|
|
|||
|
|
@ -127,6 +127,11 @@
|
|||
//! trait, which provides a [`from_wide`] method to convert a native Windows
|
||||
//! string (without the terminating nul character) to an [`OsString`].
|
||||
//!
|
||||
//! ## Other platforms
|
||||
//!
|
||||
//! Many other platforms provide their own extension traits in a
|
||||
//! `std::os::*::ffi` module.
|
||||
//!
|
||||
//! ## On all platforms
|
||||
//!
|
||||
//! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of
|
||||
|
|
@ -135,6 +140,8 @@
|
|||
//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_encoded_bytes`] and
|
||||
//! [`OsStr::from_encoded_bytes_unchecked`].
|
||||
//!
|
||||
//! For basic string processing, see [`OsStr::slice_encoded_bytes`].
|
||||
//!
|
||||
//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
|
||||
//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
|
||||
//! [`env::set_var()`]: crate::env::set_var "env::set_var"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::hash::{Hash, Hasher};
|
|||
use crate::ops::{self, Range};
|
||||
use crate::rc::Rc;
|
||||
use crate::slice;
|
||||
use crate::str::{from_utf8 as str_from_utf8, FromStr};
|
||||
use crate::str::FromStr;
|
||||
use crate::sync::Arc;
|
||||
|
||||
use crate::sys::os_str::{Buf, Slice};
|
||||
|
|
@ -997,42 +997,15 @@ impl OsStr {
|
|||
/// ```
|
||||
#[unstable(feature = "os_str_slice", issue = "118485")]
|
||||
pub fn slice_encoded_bytes<R: ops::RangeBounds<usize>>(&self, range: R) -> &Self {
|
||||
#[track_caller]
|
||||
fn check_valid_boundary(bytes: &[u8], index: usize) {
|
||||
if index == 0 || index == bytes.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fast path
|
||||
if bytes[index - 1].is_ascii() || bytes[index].is_ascii() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (before, after) = bytes.split_at(index);
|
||||
|
||||
// UTF-8 takes at most 4 bytes per codepoint, so we don't
|
||||
// need to check more than that.
|
||||
let after = after.get(..4).unwrap_or(after);
|
||||
match str_from_utf8(after) {
|
||||
Ok(_) => return,
|
||||
Err(err) if err.valid_up_to() != 0 => return,
|
||||
Err(_) => (),
|
||||
}
|
||||
|
||||
for len in 2..=4.min(index) {
|
||||
let before = &before[index - len..];
|
||||
if str_from_utf8(before).is_ok() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
panic!("byte index {index} is not an OsStr boundary");
|
||||
}
|
||||
|
||||
let encoded_bytes = self.as_encoded_bytes();
|
||||
let Range { start, end } = slice::range(range, ..encoded_bytes.len());
|
||||
check_valid_boundary(encoded_bytes, start);
|
||||
check_valid_boundary(encoded_bytes, end);
|
||||
|
||||
// `check_public_boundary` should panic if the index does not lie on an
|
||||
// `OsStr` boundary as described above. It's possible to do this in an
|
||||
// encoding-agnostic way, but details of the internal encoding might
|
||||
// permit a more efficient implementation.
|
||||
self.inner.check_public_boundary(start);
|
||||
self.inner.check_public_boundary(end);
|
||||
|
||||
// SAFETY: `slice::range` ensures that `start` and `end` are valid
|
||||
let slice = unsafe { encoded_bytes.get_unchecked(start..end) };
|
||||
|
|
|
|||
|
|
@ -194,15 +194,65 @@ fn slice_encoded_bytes() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "byte index 2 is not an OsStr boundary")]
|
||||
#[should_panic]
|
||||
fn slice_out_of_bounds() {
|
||||
let crab = OsStr::new("🦀");
|
||||
let _ = crab.slice_encoded_bytes(..5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn slice_mid_char() {
|
||||
let crab = OsStr::new("🦀");
|
||||
let _ = crab.slice_encoded_bytes(..2);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[should_panic(expected = "byte index 1 is not an OsStr boundary")]
|
||||
fn slice_invalid_data() {
|
||||
use crate::os::unix::ffi::OsStrExt;
|
||||
|
||||
let os_string = OsStr::from_bytes(b"\xFF\xFF");
|
||||
let _ = os_string.slice_encoded_bytes(1..);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[should_panic(expected = "byte index 1 is not an OsStr boundary")]
|
||||
fn slice_partial_utf8() {
|
||||
use crate::os::unix::ffi::{OsStrExt, OsStringExt};
|
||||
|
||||
let part_crab = OsStr::from_bytes(&"🦀".as_bytes()[..3]);
|
||||
let mut os_string = OsString::from_vec(vec![0xFF]);
|
||||
os_string.push(part_crab);
|
||||
let _ = os_string.slice_encoded_bytes(1..);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn slice_invalid_edge() {
|
||||
use crate::os::unix::ffi::{OsStrExt, OsStringExt};
|
||||
|
||||
let os_string = OsStr::from_bytes(b"a\xFFa");
|
||||
assert_eq!(os_string.slice_encoded_bytes(..1), "a");
|
||||
assert_eq!(os_string.slice_encoded_bytes(1..), OsStr::from_bytes(b"\xFFa"));
|
||||
assert_eq!(os_string.slice_encoded_bytes(..2), OsStr::from_bytes(b"a\xFF"));
|
||||
assert_eq!(os_string.slice_encoded_bytes(2..), "a");
|
||||
|
||||
let os_string = OsStr::from_bytes(&"abc🦀".as_bytes()[..6]);
|
||||
assert_eq!(os_string.slice_encoded_bytes(..3), "abc");
|
||||
assert_eq!(os_string.slice_encoded_bytes(3..), OsStr::from_bytes(b"\xF0\x9F\xA6"));
|
||||
|
||||
let mut os_string = OsString::from_vec(vec![0xFF]);
|
||||
os_string.push("🦀");
|
||||
assert_eq!(os_string.slice_encoded_bytes(..1), OsStr::from_bytes(b"\xFF"));
|
||||
assert_eq!(os_string.slice_encoded_bytes(1..), "🦀");
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
#[should_panic(expected = "byte index 3 is not an OsStr boundary")]
|
||||
#[should_panic(expected = "byte index 3 lies between surrogate codepoints")]
|
||||
fn slice_between_surrogates() {
|
||||
use crate::os::windows::ffi::OsStringExt;
|
||||
|
||||
|
|
@ -216,10 +266,14 @@ fn slice_between_surrogates() {
|
|||
fn slice_surrogate_edge() {
|
||||
use crate::os::windows::ffi::OsStringExt;
|
||||
|
||||
let os_string = OsString::from_wide(&[0xD800]);
|
||||
let mut with_crab = os_string.clone();
|
||||
with_crab.push("🦀");
|
||||
let surrogate = OsString::from_wide(&[0xD800]);
|
||||
let mut pre_crab = surrogate.clone();
|
||||
pre_crab.push("🦀");
|
||||
assert_eq!(pre_crab.slice_encoded_bytes(..3), surrogate);
|
||||
assert_eq!(pre_crab.slice_encoded_bytes(3..), "🦀");
|
||||
|
||||
assert_eq!(with_crab.slice_encoded_bytes(..3), os_string);
|
||||
assert_eq!(with_crab.slice_encoded_bytes(3..), "🦀");
|
||||
let mut post_crab = OsString::from("🦀");
|
||||
post_crab.push(&surrogate);
|
||||
assert_eq!(post_crab.slice_encoded_bytes(..4), "🦀");
|
||||
assert_eq!(post_crab.slice_encoded_bytes(4..), surrogate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -656,6 +656,7 @@ impl File {
|
|||
///
|
||||
/// Note that this method alters the permissions of the underlying file,
|
||||
/// even though it takes `&self` rather than `&mut self`.
|
||||
#[doc(alias = "fchmod", alias = "SetFileInformationByHandle")]
|
||||
#[stable(feature = "set_permissions_atomic", since = "1.16.0")]
|
||||
pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
|
||||
self.inner.set_permissions(perm.0)
|
||||
|
|
@ -1314,6 +1315,7 @@ impl Metadata {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "mtime", alias = "ftLastWriteTime")]
|
||||
#[stable(feature = "fs_time", since = "1.10.0")]
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
self.0.modified().map(FromInner::from_inner)
|
||||
|
|
@ -1349,6 +1351,7 @@ impl Metadata {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "atime", alias = "ftLastAccessTime")]
|
||||
#[stable(feature = "fs_time", since = "1.10.0")]
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
self.0.accessed().map(FromInner::from_inner)
|
||||
|
|
@ -1381,6 +1384,7 @@ impl Metadata {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "btime", alias = "birthtime", alias = "ftCreationTime")]
|
||||
#[stable(feature = "fs_time", since = "1.10.0")]
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
self.0.created().map(FromInner::from_inner)
|
||||
|
|
@ -1879,6 +1883,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
fs_imp::unlink(path.as_ref())
|
||||
|
|
@ -1917,6 +1922,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "stat")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
||||
fs_imp::stat(path.as_ref()).map(Metadata)
|
||||
|
|
@ -1951,6 +1957,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "lstat")]
|
||||
#[stable(feature = "symlink_metadata", since = "1.1.0")]
|
||||
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
||||
fs_imp::lstat(path.as_ref()).map(Metadata)
|
||||
|
|
@ -1994,6 +2001,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "mv", alias = "MoveFile", alias = "MoveFileEx")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
|
||||
fs_imp::rename(from.as_ref(), to.as_ref())
|
||||
|
|
@ -2052,6 +2060,9 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "cp")]
|
||||
#[doc(alias = "CopyFile", alias = "CopyFileEx")]
|
||||
#[doc(alias = "fclonefileat", alias = "fcopyfile")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
|
||||
fs_imp::copy(from.as_ref(), to.as_ref())
|
||||
|
|
@ -2096,6 +2107,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "CreateHardLink", alias = "linkat")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
|
||||
fs_imp::link(original.as_ref(), link.as_ref())
|
||||
|
|
@ -2245,7 +2257,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "mkdir")]
|
||||
#[doc(alias = "mkdir", alias = "CreateDirectory")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "fs_create_dir")]
|
||||
pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
|
|
@ -2326,7 +2338,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "rmdir")]
|
||||
#[doc(alias = "rmdir", alias = "RemoveDirectory")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
fs_imp::rmdir(path.as_ref())
|
||||
|
|
@ -2449,6 +2461,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
|
||||
fs_imp::readdir(path.as_ref()).map(ReadDir)
|
||||
|
|
@ -2484,6 +2497,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "chmod", alias = "SetFileAttributes")]
|
||||
#[stable(feature = "set_permissions", since = "1.1.0")]
|
||||
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
|
||||
fs_imp::set_perm(path.as_ref(), perm.0)
|
||||
|
|
|
|||
|
|
@ -397,7 +397,6 @@ pub trait OpenOptionsExt {
|
|||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(rustc_private)]
|
||||
/// use libc;
|
||||
/// use std::fs::OpenOptions;
|
||||
/// use std::os::unix::fs::OpenOptionsExt;
|
||||
///
|
||||
|
|
|
|||
|
|
@ -173,51 +173,61 @@ pub trait FileExt {
|
|||
///
|
||||
/// This corresponds to the `fd_tell` syscall and is similar to
|
||||
/// `seek` where you offset 0 bytes from the current position.
|
||||
#[doc(alias = "fd_tell")]
|
||||
fn tell(&self) -> io::Result<u64>;
|
||||
|
||||
/// Adjust the flags associated with this file.
|
||||
///
|
||||
/// This corresponds to the `fd_fdstat_set_flags` syscall.
|
||||
#[doc(alias = "fd_fdstat_set_flags")]
|
||||
fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
|
||||
|
||||
/// Adjust the rights associated with this file.
|
||||
///
|
||||
/// This corresponds to the `fd_fdstat_set_rights` syscall.
|
||||
#[doc(alias = "fd_fdstat_set_rights")]
|
||||
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
|
||||
|
||||
/// Provide file advisory information on a file descriptor.
|
||||
///
|
||||
/// This corresponds to the `fd_advise` syscall.
|
||||
#[doc(alias = "fd_advise")]
|
||||
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
|
||||
|
||||
/// Force the allocation of space in a file.
|
||||
///
|
||||
/// This corresponds to the `fd_allocate` syscall.
|
||||
#[doc(alias = "fd_allocate")]
|
||||
fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
|
||||
|
||||
/// Create a directory.
|
||||
///
|
||||
/// This corresponds to the `path_create_directory` syscall.
|
||||
#[doc(alias = "path_create_directory")]
|
||||
fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
|
||||
|
||||
/// Read the contents of a symbolic link.
|
||||
///
|
||||
/// This corresponds to the `path_readlink` syscall.
|
||||
#[doc(alias = "path_readlink")]
|
||||
fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
|
||||
|
||||
/// Return the attributes of a file or directory.
|
||||
///
|
||||
/// This corresponds to the `path_filestat_get` syscall.
|
||||
#[doc(alias = "path_filestat_get")]
|
||||
fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
|
||||
|
||||
/// Unlink a file.
|
||||
///
|
||||
/// This corresponds to the `path_unlink_file` syscall.
|
||||
#[doc(alias = "path_unlink_file")]
|
||||
fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
|
||||
|
||||
/// Remove a directory.
|
||||
///
|
||||
/// This corresponds to the `path_remove_directory` syscall.
|
||||
#[doc(alias = "path_remove_directory")]
|
||||
fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
|
||||
}
|
||||
|
||||
|
|
@ -359,6 +369,7 @@ pub trait OpenOptionsExt {
|
|||
/// Open a file or directory.
|
||||
///
|
||||
/// This corresponds to the `path_open` syscall.
|
||||
#[doc(alias = "path_open")]
|
||||
fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
|
||||
}
|
||||
|
||||
|
|
@ -500,6 +511,7 @@ impl DirEntryExt for fs::DirEntry {
|
|||
/// Create a hard link.
|
||||
///
|
||||
/// This corresponds to the `path_link` syscall.
|
||||
#[doc(alias = "path_link")]
|
||||
pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
|
||||
old_fd: &File,
|
||||
old_flags: u32,
|
||||
|
|
@ -518,6 +530,7 @@ pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
|
|||
/// Rename a file or directory.
|
||||
///
|
||||
/// This corresponds to the `path_rename` syscall.
|
||||
#[doc(alias = "path_rename")]
|
||||
pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
|
||||
old_fd: &File,
|
||||
old_path: P,
|
||||
|
|
@ -534,6 +547,7 @@ pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
|
|||
/// Create a symbolic link.
|
||||
///
|
||||
/// This corresponds to the `path_symlink` syscall.
|
||||
#[doc(alias = "path_symlink")]
|
||||
pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
|
||||
old_path: P,
|
||||
fd: &File,
|
||||
|
|
|
|||
|
|
@ -337,8 +337,9 @@ pub mod panic_count {
|
|||
#[doc(hidden)]
|
||||
#[cfg(not(feature = "panic_immediate_abort"))]
|
||||
#[unstable(feature = "update_panic_count", issue = "none")]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
|
||||
#[allow(static_mut_ref)]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
|
||||
#[cfg_attr(bootstrap, allow(static_mut_ref))]
|
||||
#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
|
||||
pub mod panic_count {
|
||||
use crate::cell::Cell;
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue