Merge ref '873d4682c7' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: rust-lang/rust@873d4682c7
Filtered ref: rust-lang/miri@57f1e8b76f
Upstream diff: 5a07626f4b...873d4682c7
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
58f38eb01d
104 changed files with 1680 additions and 967 deletions
|
|
@ -62,9 +62,9 @@ Stabilized APIs
|
|||
- [`<uN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shl)
|
||||
- [`<uN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shr)
|
||||
- [`<[T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_array)
|
||||
- [`<[T]>::as_array_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
|
||||
- [`<[T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
|
||||
- [`<*const [T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_array)
|
||||
- [`<*mut [T]>::as_array_mut`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
|
||||
- [`<*mut [T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
|
||||
- [`VecDeque::pop_front_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_front_if)
|
||||
- [`VecDeque::pop_back_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_back_if)
|
||||
- [`Duration::from_nanos_u128`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos_u128)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub enum CanonAbi {
|
|||
C,
|
||||
Rust,
|
||||
RustCold,
|
||||
RustPreserveNone,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
|
@ -54,7 +55,7 @@ pub enum CanonAbi {
|
|||
impl CanonAbi {
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
match self {
|
||||
CanonAbi::Rust | CanonAbi::RustCold => true,
|
||||
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
|
||||
CanonAbi::C
|
||||
| CanonAbi::Custom
|
||||
| CanonAbi::Arm(_)
|
||||
|
|
@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
|
|
|
|||
|
|
@ -42,6 +42,13 @@ pub enum ExternAbi {
|
|||
/// in a platform-agnostic way.
|
||||
RustInvalid,
|
||||
|
||||
/// Preserves no registers.
|
||||
///
|
||||
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
|
||||
/// and may fall-back to a more conservative calling convention if the backend does not support
|
||||
/// forcing callers to save all registers.
|
||||
RustPreserveNone,
|
||||
|
||||
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
|
@ -163,6 +170,7 @@ abi_impls! {
|
|||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustInvalid =><= "rust-invalid",
|
||||
RustPreserveNone =><= "rust-preserve-none",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
|
|
@ -243,7 +251,7 @@ impl ExternAbi {
|
|||
/// - are subject to change between compiler versions
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
use ExternAbi::*;
|
||||
matches!(self, Rust | RustCall | RustCold)
|
||||
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
|
||||
}
|
||||
|
||||
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
||||
|
|
@ -315,7 +323,8 @@ impl ExternAbi {
|
|||
| Self::Thiscall { .. }
|
||||
| Self::Vectorcall { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::Win64 { .. } => true,
|
||||
| Self::Win64 { .. }
|
||||
| Self::RustPreserveNone => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
ExternAbi::RustCold => {
|
||||
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
||||
}
|
||||
ExternAbi::RustPreserveNone => Err(UnstableAbi {
|
||||
abi,
|
||||
feature: sym::rust_preserve_none_cc,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::RustInvalid => {
|
||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ impl<'a> AstValidator<'a> {
|
|||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::RustPreserveNone
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv(
|
|||
CanonAbi::Rust | CanonAbi::C => default_call_conv,
|
||||
CanonAbi::RustCold => CallConv::Cold,
|
||||
|
||||
// Cranelift doesn't currently have anything for this.
|
||||
CanonAbi::RustPreserveNone => default_call_conv,
|
||||
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
|
|
|
|||
|
|
@ -243,6 +243,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option<FnAttribute<'gcc>> {
|
||||
let attribute = match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => return None,
|
||||
// gcc/gccjit does not have anything for this.
|
||||
CanonAbi::RustPreserveNone => return None,
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
|
|
|
|||
|
|
@ -694,6 +694,10 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm:
|
|||
match abi {
|
||||
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
|
||||
CanonAbi::RustCold => llvm::PreserveMost,
|
||||
CanonAbi::RustPreserveNone => match &sess.target.arch {
|
||||
Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone,
|
||||
_ => llvm::CCallConv,
|
||||
},
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
|
|||
llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
|
||||
}
|
||||
|
||||
/// Helper for `FnAbi::apply_attrs_llfn`:
|
||||
/// Helper for `FnAbiLlvmExt::apply_attrs_llfn`:
|
||||
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
|
||||
/// attributes.
|
||||
pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
||||
|
|
@ -516,7 +516,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
|||
to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
|
||||
// applies to argument place instead of function place
|
||||
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
|
||||
let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) {
|
||||
// "Does not capture provenance" means "if the function call stashes the pointer somewhere,
|
||||
// accessing that pointer after the function returns is UB". That is definitely the case here since
|
||||
// freeing will destroy the provenance.
|
||||
let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
|
||||
&[allocated_pointer, captures_addr]
|
||||
} else {
|
||||
&[allocated_pointer]
|
||||
};
|
||||
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
|
||||
}
|
||||
if let Some(align) = codegen_fn_attrs.alignment {
|
||||
llvm::set_alignment(llfn, align);
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ pub(crate) enum CallConv {
|
|||
PreserveMost = 14,
|
||||
PreserveAll = 15,
|
||||
Tail = 18,
|
||||
PreserveNone = 21,
|
||||
X86StdcallCallConv = 64,
|
||||
X86FastcallCallConv = 65,
|
||||
ArmAapcsCallConv = 67,
|
||||
|
|
|
|||
|
|
@ -431,8 +431,6 @@ impl ToInternal<rustc_errors::Level> for Level {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct FreeFunctions;
|
||||
|
||||
pub(crate) struct Rustc<'a, 'b> {
|
||||
ecx: &'a mut ExtCtxt<'b>,
|
||||
def_site: Span,
|
||||
|
|
@ -461,13 +459,28 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
|||
}
|
||||
|
||||
impl server::Types for Rustc<'_, '_> {
|
||||
type FreeFunctions = FreeFunctions;
|
||||
type TokenStream = TokenStream;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::FreeFunctions for Rustc<'_, '_> {
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
call_site: self.call_site,
|
||||
mixed_site: self.mixed_site,
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_symbol(string: &str) -> Self::Symbol {
|
||||
Symbol::intern(string)
|
||||
}
|
||||
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
|
||||
fn injected_env_var(&mut self, var: &str) -> Option<String> {
|
||||
self.ecx.sess.opts.logical_env.get(var).cloned()
|
||||
}
|
||||
|
|
@ -552,14 +565,20 @@ impl server::FreeFunctions for Rustc<'_, '_> {
|
|||
}
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
|
||||
impl server::TokenStream for Rustc<'_, '_> {
|
||||
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
fn ts_drop(&mut self, stream: Self::TokenStream) {
|
||||
drop(stream);
|
||||
}
|
||||
|
||||
fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream {
|
||||
stream.clone()
|
||||
}
|
||||
|
||||
fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
stream.is_empty()
|
||||
}
|
||||
|
||||
fn from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
fn ts_from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
unwrap_or_emit_fatal(source_str_to_stream(
|
||||
self.psess(),
|
||||
FileName::proc_macro_source_code(src),
|
||||
|
|
@ -568,11 +587,11 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
))
|
||||
}
|
||||
|
||||
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
pprust::tts_to_string(stream)
|
||||
}
|
||||
|
||||
fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
fn ts_expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
// Parse the expression from our tokenstream.
|
||||
let expr: PResult<'_, _> = try {
|
||||
let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr"));
|
||||
|
|
@ -633,14 +652,14 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_token_tree(
|
||||
fn ts_from_token_tree(
|
||||
&mut self,
|
||||
tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
|
||||
) -> Self::TokenStream {
|
||||
Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
fn concat_trees(
|
||||
fn ts_concat_trees(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
|
||||
|
|
@ -654,7 +673,7 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
stream
|
||||
}
|
||||
|
||||
fn concat_streams(
|
||||
fn ts_concat_streams(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
streams: Vec<Self::TokenStream>,
|
||||
|
|
@ -666,16 +685,14 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
stream
|
||||
}
|
||||
|
||||
fn into_trees(
|
||||
fn ts_into_trees(
|
||||
&mut self,
|
||||
stream: Self::TokenStream,
|
||||
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
|
||||
FromInternal::from_internal((stream, self))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Span for Rustc<'_, '_> {
|
||||
fn debug(&mut self, span: Self::Span) -> String {
|
||||
fn span_debug(&mut self, span: Self::Span) -> String {
|
||||
if self.ecx.ecfg.span_debug {
|
||||
format!("{span:?}")
|
||||
} else {
|
||||
|
|
@ -683,7 +700,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn file(&mut self, span: Self::Span) -> String {
|
||||
fn span_file(&mut self, span: Self::Span) -> String {
|
||||
self.psess()
|
||||
.source_map()
|
||||
.lookup_char_pos(span.lo())
|
||||
|
|
@ -693,7 +710,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
.to_string()
|
||||
}
|
||||
|
||||
fn local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
fn span_local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.psess()
|
||||
.source_map()
|
||||
.lookup_char_pos(span.lo())
|
||||
|
|
@ -708,15 +725,15 @@ impl server::Span for Rustc<'_, '_> {
|
|||
})
|
||||
}
|
||||
|
||||
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||
fn span_parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||
span.parent_callsite()
|
||||
}
|
||||
|
||||
fn source(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_source(&mut self, span: Self::Span) -> Self::Span {
|
||||
span.source_callsite()
|
||||
}
|
||||
|
||||
fn byte_range(&mut self, span: Self::Span) -> Range<usize> {
|
||||
fn span_byte_range(&mut self, span: Self::Span) -> Range<usize> {
|
||||
let source_map = self.psess().source_map();
|
||||
|
||||
let relative_start_pos = source_map.lookup_byte_offset(span.lo()).pos;
|
||||
|
|
@ -724,25 +741,25 @@ impl server::Span for Rustc<'_, '_> {
|
|||
|
||||
Range { start: relative_start_pos.0 as usize, end: relative_end_pos.0 as usize }
|
||||
}
|
||||
fn start(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_start(&mut self, span: Self::Span) -> Self::Span {
|
||||
span.shrink_to_lo()
|
||||
}
|
||||
|
||||
fn end(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_end(&mut self, span: Self::Span) -> Self::Span {
|
||||
span.shrink_to_hi()
|
||||
}
|
||||
|
||||
fn line(&mut self, span: Self::Span) -> usize {
|
||||
fn span_line(&mut self, span: Self::Span) -> usize {
|
||||
let loc = self.psess().source_map().lookup_char_pos(span.lo());
|
||||
loc.line
|
||||
}
|
||||
|
||||
fn column(&mut self, span: Self::Span) -> usize {
|
||||
fn span_column(&mut self, span: Self::Span) -> usize {
|
||||
let loc = self.psess().source_map().lookup_char_pos(span.lo());
|
||||
loc.col.to_usize() + 1
|
||||
}
|
||||
|
||||
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
|
||||
fn span_join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
|
||||
let self_loc = self.psess().source_map().lookup_char_pos(first.lo());
|
||||
let other_loc = self.psess().source_map().lookup_char_pos(second.lo());
|
||||
|
||||
|
|
@ -753,7 +770,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
Some(first.to(second))
|
||||
}
|
||||
|
||||
fn subspan(
|
||||
fn span_subspan(
|
||||
&mut self,
|
||||
span: Self::Span,
|
||||
start: Bound<usize>,
|
||||
|
|
@ -789,11 +806,11 @@ impl server::Span for Rustc<'_, '_> {
|
|||
Some(span.with_lo(new_lo).with_hi(new_hi))
|
||||
}
|
||||
|
||||
fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||
fn span_resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||
span.with_ctxt(at.ctxt())
|
||||
}
|
||||
|
||||
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
fn span_source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.psess().source_map().span_to_snippet(span).ok()
|
||||
}
|
||||
|
||||
|
|
@ -821,11 +838,11 @@ impl server::Span for Rustc<'_, '_> {
|
|||
/// span from the metadata of `my_proc_macro` (which we have access to,
|
||||
/// since we've loaded `my_proc_macro` from disk in order to execute it).
|
||||
/// In this way, we have obtained a span pointing into `my_proc_macro`
|
||||
fn save_span(&mut self, span: Self::Span) -> usize {
|
||||
fn span_save_span(&mut self, span: Self::Span) -> usize {
|
||||
self.psess().save_proc_macro_span(span)
|
||||
}
|
||||
|
||||
fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
|
||||
fn span_recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
|
||||
let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
|
||||
*self.rebased_spans.entry(id).or_insert_with(|| {
|
||||
// FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
|
||||
|
|
@ -833,29 +850,9 @@ impl server::Span for Rustc<'_, '_> {
|
|||
resolver.get_proc_macro_quoted_span(krate, id).with_ctxt(def_site.ctxt())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Symbol for Rustc<'_, '_> {
|
||||
fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
let sym = nfc_normalize(string);
|
||||
if rustc_lexer::is_ident(sym.as_str()) { Ok(sym) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
call_site: self.call_site,
|
||||
mixed_site: self.mixed_site,
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_symbol(string: &str) -> Self::Symbol {
|
||||
Symbol::intern(string)
|
||||
}
|
||||
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -634,6 +634,8 @@ declare_features! (
|
|||
(unstable, rtm_target_feature, "1.35.0", Some(150258)),
|
||||
/// Allows `extern "rust-cold"`.
|
||||
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
|
||||
/// Allows `extern "rust-preserve-none"`.
|
||||
(unstable, rust_preserve_none_cc, "CURRENT_RUSTC_VERSION", Some(151401)),
|
||||
/// Target features on s390x.
|
||||
(unstable, s390x_target_feature, "1.82.0", Some(150259)),
|
||||
/// Allows the use of the `sanitize` attribute.
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::RustPreserveNone
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::X86(_) => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1365,6 +1365,7 @@ pub fn can_coerce<'tcx>(
|
|||
/// - WARNING: I don't believe this final type is guaranteed to be
|
||||
/// related to your initial `expected_ty` in any particular way,
|
||||
/// although it will typically be a subtype, so you should check it.
|
||||
/// Check the note below for more details.
|
||||
/// - Invoking `complete()` may cause us to go and adjust the "adjustments" on
|
||||
/// previously coerced expressions.
|
||||
///
|
||||
|
|
@ -1378,6 +1379,28 @@ pub fn can_coerce<'tcx>(
|
|||
/// }
|
||||
/// let final_ty = coerce.complete(fcx);
|
||||
/// ```
|
||||
///
|
||||
/// NOTE: Why does the `expected_ty` participate in the LUB?
|
||||
/// When coercing, each branch should use the following expectations for type inference:
|
||||
/// - The branch can be coerced to the expected type of the match/if/whatever.
|
||||
/// - The branch can be coercion lub'd with the types of the previous branches.
|
||||
/// Ideally we'd have some sort of `Expectation::ParticipatesInCoerceLub(ongoing_lub_ty, final_ty)`,
|
||||
/// but adding and using this feels very challenging.
|
||||
/// What we instead do is to use the expected type of the match/if/whatever as
|
||||
/// the initial coercion lub. This allows us to use the lub of "expected type of match" with
|
||||
/// "types from previous branches" as the coercion target, which can contains both expectations.
|
||||
///
|
||||
/// Two concerns with this approach:
|
||||
/// - We may have incompatible `final_ty` if that lub is different from the expected
|
||||
/// type of the match. However, in this case coercing the final type of the
|
||||
/// `CoerceMany` to its expected type would have error'd anyways, so we don't care.
|
||||
/// - We may constrain the `expected_ty` too early. For some branches with
|
||||
/// type `a` and `b`, we end up with `(a lub expected_ty) lub b` instead of
|
||||
/// `(a lub b) lub expected_ty`. They should be the same type. However,
|
||||
/// `a lub expected_ty` may constrain inference variables in `expected_ty`.
|
||||
/// In this case the difference does matter and we get actually incorrect results.
|
||||
/// FIXME: Ideally we'd compute the final type without unnecessarily constraining
|
||||
/// the expected type of the match when computing the types of its branches.
|
||||
pub(crate) struct CoerceMany<'tcx> {
|
||||
expected_ty: Ty<'tcx>,
|
||||
final_ty: Option<Ty<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -1670,11 +1670,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let coerce_to = expected
|
||||
.to_option(self)
|
||||
.and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index())
|
||||
.and_then(|uty| {
|
||||
self.try_structurally_resolve_type(expr.span, uty)
|
||||
.builtin_index()
|
||||
// Avoid using the original type variable as the coerce_to type, as it may resolve
|
||||
// during the first coercion instead of being the LUB type.
|
||||
.filter(|t| !self.try_structurally_resolve_type(expr.span, *t).is_ty_var())
|
||||
})
|
||||
.unwrap_or_else(|| self.next_ty_var(expr.span));
|
||||
let mut coerce = CoerceMany::with_capacity(coerce_to, args.len());
|
||||
|
||||
for e in args {
|
||||
// FIXME: the element expectation should use
|
||||
// `try_structurally_resolve_and_adjust_for_branches` just like in `if` and `match`.
|
||||
// While that fixes nested coercion, it will break [some
|
||||
// code like this](https://github.com/rust-lang/rust/pull/140283#issuecomment-2958776528).
|
||||
// If we find a way to support recursive tuple coercion, this break can be avoided.
|
||||
let e_ty = self.check_expr_with_hint(e, coerce_to);
|
||||
let cause = self.misc(e.span);
|
||||
coerce.coerce(self, &cause, e, e_ty);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
|
|||
pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
write!(f, "{}", tcx.dep_kind_info(kind).name)
|
||||
write!(f, "{}", tcx.dep_kind_vtable(kind).name)
|
||||
} else {
|
||||
default_dep_kind_debug(kind, f)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -992,7 +992,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
|||
hir_arena,
|
||||
untracked,
|
||||
dep_graph,
|
||||
rustc_query_impl::query_callbacks(arena),
|
||||
rustc_query_impl::make_dep_kind_vtables(arena),
|
||||
rustc_query_impl::query_system(
|
||||
providers.queries,
|
||||
providers.extern_queries,
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ macro_rules! arena_types {
|
|||
[decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::ItemLocalId>,
|
||||
[decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
|
||||
|
||||
[] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
|
||||
[] dep_kind_vtable: rustc_middle::dep_graph::DepKindVTable<'tcx>,
|
||||
|
||||
[decode] trait_impl_trait_tys:
|
||||
rustc_data_structures::unord::UnordMap<
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub use rustc_query_system::dep_graph::{
|
|||
|
||||
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>;
|
||||
|
||||
pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
|
||||
pub type DepKindVTable<'tcx> = rustc_query_system::dep_graph::DepKindVTable<TyCtxt<'tcx>>;
|
||||
|
||||
pub struct DepsType;
|
||||
|
||||
|
|
@ -79,8 +79,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> {
|
||||
&self.query_kinds[dk.as_usize()]
|
||||
fn dep_kind_vtable(&self, dk: DepKind) -> &DepKindVTable<'tcx> {
|
||||
&self.dep_kind_vtables[dk.as_usize()]
|
||||
}
|
||||
|
||||
fn with_reduced_queries<T>(self, f: impl FnOnce() -> T) -> T {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ use rustc_type_ir::{
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::arena::Arena;
|
||||
use crate::dep_graph::{DepGraph, DepKindStruct};
|
||||
use crate::dep_graph::{DepGraph, DepKindVTable};
|
||||
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, CanonicalVarKinds};
|
||||
use crate::lint::lint_level;
|
||||
use crate::metadata::ModChild;
|
||||
|
|
@ -1580,7 +1580,7 @@ pub struct GlobalCtxt<'tcx> {
|
|||
untracked: Untracked,
|
||||
|
||||
pub query_system: QuerySystem<'tcx>,
|
||||
pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>],
|
||||
pub(crate) dep_kind_vtables: &'tcx [DepKindVTable<'tcx>],
|
||||
|
||||
// Internal caches for metadata decoding. No need to track deps on this.
|
||||
pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
|
||||
|
|
@ -1801,7 +1801,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
|
||||
untracked: Untracked,
|
||||
dep_graph: DepGraph,
|
||||
query_kinds: &'tcx [DepKindStruct<'tcx>],
|
||||
dep_kind_vtables: &'tcx [DepKindVTable<'tcx>],
|
||||
query_system: QuerySystem<'tcx>,
|
||||
hooks: crate::hooks::Providers,
|
||||
current_gcx: CurrentGcx,
|
||||
|
|
@ -1831,7 +1831,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
consts: common_consts,
|
||||
untracked,
|
||||
query_system,
|
||||
query_kinds,
|
||||
dep_kind_vtables,
|
||||
ty_rcache: Default::default(),
|
||||
selection_cache: Default::default(),
|
||||
evaluation_cache: Default::default(),
|
||||
|
|
|
|||
|
|
@ -1288,7 +1288,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
|
|||
| RiscvInterruptS
|
||||
| RustInvalid
|
||||
| Unadjusted => false,
|
||||
Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(),
|
||||
Rust | RustCall | RustCold | RustPreserveNone => tcx.sess.panic_strategy().unwinds(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -986,7 +986,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
|
|||
// warn twice, for the unused local and for the unused assignment. Therefore, we remove
|
||||
// from the list of assignments the ones that happen at the definition site.
|
||||
statements.retain(|source_info, _| {
|
||||
source_info.span.find_ancestor_inside(binding.pat_span).is_none()
|
||||
!binding.introductions.iter().any(|intro| intro.span == source_info.span)
|
||||
});
|
||||
|
||||
// Extra assignments that we recognize thanks to the initialization span. We need to
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ pub enum CallConvention {
|
|||
Cold,
|
||||
PreserveMost,
|
||||
PreserveAll,
|
||||
PreserveNone,
|
||||
|
||||
Custom,
|
||||
|
||||
|
|
|
|||
|
|
@ -1139,6 +1139,7 @@ pub enum Abi {
|
|||
RustCold,
|
||||
RiscvInterruptM,
|
||||
RiscvInterruptS,
|
||||
RustPreserveNone,
|
||||
RustInvalid,
|
||||
Custom,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -615,6 +615,7 @@ impl RustcInternal for Abi {
|
|||
Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid,
|
||||
Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM,
|
||||
Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS,
|
||||
Abi::RustPreserveNone => rustc_abi::ExternAbi::RustPreserveNone,
|
||||
Abi::Custom => rustc_abi::ExternAbi::Custom,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi {
|
|||
CanonAbi::C => CallConvention::C,
|
||||
CanonAbi::Rust => CallConvention::Rust,
|
||||
CanonAbi::RustCold => CallConvention::Cold,
|
||||
CanonAbi::RustPreserveNone => CallConvention::PreserveNone,
|
||||
CanonAbi::Custom => CallConvention::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => CallConvention::ArmAapcs,
|
||||
|
|
|
|||
|
|
@ -1020,6 +1020,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
|
|||
ExternAbi::RustCall => Abi::RustCall,
|
||||
ExternAbi::Unadjusted => Abi::Unadjusted,
|
||||
ExternAbi::RustCold => Abi::RustCold,
|
||||
ExternAbi::RustPreserveNone => Abi::RustPreserveNone,
|
||||
ExternAbi::RustInvalid => Abi::RustInvalid,
|
||||
ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM,
|
||||
ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
use rustc_data_structures::stable_hasher::HashStable;
|
||||
use rustc_data_structures::sync::AtomicU64;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::{self, DepKind, DepKindStruct, DepNodeIndex};
|
||||
use rustc_middle::dep_graph::{self, DepKind, DepKindVTable, DepNodeIndex};
|
||||
use rustc_middle::query::erase::{Erase, erase, restore};
|
||||
use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
|
||||
use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_hir::limit::Limit;
|
|||
use rustc_index::Idx;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::{
|
||||
self, DepContext, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
|
||||
self, DepContext, DepKind, DepKindVTable, DepNode, DepNodeIndex, SerializedDepNodeIndex,
|
||||
dep_kinds,
|
||||
};
|
||||
use rustc_middle::query::Key;
|
||||
|
|
@ -489,14 +489,17 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx>
|
||||
pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>(
|
||||
is_anon: bool,
|
||||
is_eval_always: bool,
|
||||
) -> DepKindVTable<'tcx>
|
||||
where
|
||||
Q: QueryConfigRestored<'tcx>,
|
||||
{
|
||||
let fingerprint_style = <Q::Config as QueryConfig<QueryCtxt<'tcx>>>::Key::fingerprint_style();
|
||||
|
||||
if is_anon || !fingerprint_style.reconstructible() {
|
||||
return DepKindStruct {
|
||||
return DepKindVTable {
|
||||
is_anon,
|
||||
is_eval_always,
|
||||
fingerprint_style,
|
||||
|
|
@ -506,7 +509,7 @@ where
|
|||
};
|
||||
}
|
||||
|
||||
DepKindStruct {
|
||||
DepKindVTable {
|
||||
is_anon,
|
||||
is_eval_always,
|
||||
fingerprint_style,
|
||||
|
|
@ -811,15 +814,19 @@ macro_rules! define_queries {
|
|||
for<'tcx> fn(TyCtxt<'tcx>)
|
||||
] = &[$(query_impl::$name::query_key_hash_verify),*];
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
mod query_callbacks {
|
||||
/// Module containing a named function for each dep kind (including queries)
|
||||
/// that creates a `DepKindVTable`.
|
||||
///
|
||||
/// Consumed via `make_dep_kind_array!` to create a list of vtables.
|
||||
#[expect(non_snake_case)]
|
||||
mod _dep_kind_vtable_ctors {
|
||||
use super::*;
|
||||
use rustc_middle::bug;
|
||||
use rustc_query_system::dep_graph::FingerprintStyle;
|
||||
|
||||
// We use this for most things when incr. comp. is turned off.
|
||||
pub(crate) fn Null<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn Null<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: false,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Unit,
|
||||
|
|
@ -830,8 +837,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
|
||||
// We use this for the forever-red node.
|
||||
pub(crate) fn Red<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn Red<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: false,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Unit,
|
||||
|
|
@ -841,8 +848,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn SideEffect<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn SideEffect<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: false,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Unit,
|
||||
|
|
@ -855,8 +862,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn AnonZeroDeps<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn AnonZeroDeps<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: true,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Opaque,
|
||||
|
|
@ -866,8 +873,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn TraitSelect<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: true,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Unit,
|
||||
|
|
@ -877,8 +884,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn CompileCodegenUnit<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: false,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Opaque,
|
||||
|
|
@ -888,8 +895,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn CompileMonoItem<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: false,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Opaque,
|
||||
|
|
@ -899,8 +906,8 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn Metadata<'tcx>() -> DepKindStruct<'tcx> {
|
||||
DepKindStruct {
|
||||
pub(crate) fn Metadata<'tcx>() -> DepKindVTable<'tcx> {
|
||||
DepKindVTable {
|
||||
is_anon: false,
|
||||
is_eval_always: false,
|
||||
fingerprint_style: FingerprintStyle::Unit,
|
||||
|
|
@ -910,16 +917,17 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
$(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
|
||||
$crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>(
|
||||
$(pub(crate) fn $name<'tcx>() -> DepKindVTable<'tcx> {
|
||||
use $crate::query_impl::$name::QueryType;
|
||||
$crate::plumbing::make_dep_kind_vtable_for_query::<QueryType<'tcx>>(
|
||||
is_anon!([$($modifiers)*]),
|
||||
is_eval_always!([$($modifiers)*]),
|
||||
)
|
||||
})*
|
||||
}
|
||||
|
||||
pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
|
||||
arena.alloc_from_iter(rustc_middle::make_dep_kind_array!(query_callbacks))
|
||||
pub fn make_dep_kind_vtables<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindVTable<'tcx>] {
|
||||
arena.alloc_from_iter(rustc_middle::make_dep_kind_array!(_dep_kind_vtable_ctors))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,12 +221,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// This struct stores metadata about each DepKind.
|
||||
/// This struct stores function pointers and other metadata for a particular DepKind.
|
||||
///
|
||||
/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
|
||||
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
|
||||
/// jump table instead of large matches.
|
||||
pub struct DepKindStruct<Tcx: DepContext> {
|
||||
pub struct DepKindVTable<Tcx: DepContext> {
|
||||
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
|
||||
/// When their result is needed, it is recomputed. They are useful for fine-grained
|
||||
/// dependency tracking, and caching within one compiler invocation.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ mod serialized;
|
|||
|
||||
use std::panic;
|
||||
|
||||
pub use dep_node::{DepKind, DepKindStruct, DepNode, DepNodeParams, WorkProductId};
|
||||
pub use dep_node::{DepKind, DepKindVTable, DepNode, DepNodeParams, WorkProductId};
|
||||
pub(crate) use graph::DepGraphData;
|
||||
pub use graph::{DepGraph, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap, hash_result};
|
||||
pub use query::DepGraphQuery;
|
||||
|
|
@ -35,21 +35,21 @@ pub trait DepContext: Copy {
|
|||
/// Access the compiler session.
|
||||
fn sess(&self) -> &Session;
|
||||
|
||||
fn dep_kind_info(&self, dep_node: DepKind) -> &DepKindStruct<Self>;
|
||||
fn dep_kind_vtable(&self, dep_node: DepKind) -> &DepKindVTable<Self>;
|
||||
|
||||
#[inline(always)]
|
||||
fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle {
|
||||
let data = self.dep_kind_info(kind);
|
||||
if data.is_anon {
|
||||
let vtable = self.dep_kind_vtable(kind);
|
||||
if vtable.is_anon {
|
||||
return FingerprintStyle::Opaque;
|
||||
}
|
||||
data.fingerprint_style
|
||||
vtable.fingerprint_style
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
/// Return whether this kind always require evaluation.
|
||||
fn is_eval_always(self, kind: DepKind) -> bool {
|
||||
self.dep_kind_info(kind).is_eval_always
|
||||
self.dep_kind_vtable(kind).is_eval_always
|
||||
}
|
||||
|
||||
/// Try to force a dep node to execute and see if it's green.
|
||||
|
|
@ -65,9 +65,10 @@ pub trait DepContext: Copy {
|
|||
prev_index: SerializedDepNodeIndex,
|
||||
frame: &MarkFrame<'_>,
|
||||
) -> bool {
|
||||
let cb = self.dep_kind_info(dep_node.kind);
|
||||
if let Some(f) = cb.force_from_dep_node {
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| f(self, dep_node, prev_index))) {
|
||||
if let Some(force_fn) = self.dep_kind_vtable(dep_node.kind).force_from_dep_node {
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
force_fn(self, dep_node, prev_index)
|
||||
})) {
|
||||
Err(value) => {
|
||||
if !value.is::<rustc_errors::FatalErrorMarker>() {
|
||||
print_markframe_trace(self.dep_graph(), frame);
|
||||
|
|
@ -83,9 +84,8 @@ pub trait DepContext: Copy {
|
|||
|
||||
/// Load data from the on-disk cache.
|
||||
fn try_load_from_on_disk_cache(self, dep_node: DepNode) {
|
||||
let cb = self.dep_kind_info(dep_node.kind);
|
||||
if let Some(f) = cb.try_load_from_on_disk_cache {
|
||||
f(self, dep_node)
|
||||
if let Some(try_load_fn) = self.dep_kind_vtable(dep_node.kind).try_load_from_on_disk_cache {
|
||||
try_load_fn(self, dep_node)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -626,7 +626,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
|||
file,
|
||||
"#{} [{}] {}",
|
||||
count_total,
|
||||
qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name,
|
||||
qcx.dep_context().dep_kind_vtable(query_info.query.dep_kind).name,
|
||||
query_info.query.description
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1918,6 +1918,7 @@ symbols! {
|
|||
rust_future,
|
||||
rust_logo,
|
||||
rust_out,
|
||||
rust_preserve_none_cc,
|
||||
rustc,
|
||||
rustc_abi,
|
||||
// FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ impl AbiMap {
|
|||
|
||||
(ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
|
||||
(ExternAbi::RustCold, _) => CanonAbi::RustCold,
|
||||
(ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone,
|
||||
|
||||
(ExternAbi::Custom, _) => CanonAbi::Custom,
|
||||
|
||||
|
|
|
|||
|
|
@ -466,9 +466,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
|||
("sha512", Stable, &["avx2"]),
|
||||
("sm3", Stable, &["avx"]),
|
||||
("sm4", Stable, &["avx2"]),
|
||||
// This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to
|
||||
// stabilize. It must be in this list for the ABI check to be able to use it.
|
||||
("soft-float", Stability::Unstable(sym::x87_target_feature), &[]),
|
||||
("soft-float", Stability::Forbidden { reason: "use a soft-float target instead" }, &[]),
|
||||
("sse", Stable, &[]),
|
||||
("sse2", Stable, &["sse"]),
|
||||
("sse3", Stable, &["sse2"]),
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ use core::intrinsics::abort;
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::iter;
|
||||
use core::marker::{PhantomData, Unsize};
|
||||
use core::mem::{self, ManuallyDrop, align_of_val_raw};
|
||||
use core::mem::{self, ManuallyDrop};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
|
|
@ -3845,15 +3845,15 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
|
|||
// Because RcInner is repr(C), it will always be the last field in memory.
|
||||
// SAFETY: since the only unsized types possible are slices, trait objects,
|
||||
// and extern types, the input safety requirement is currently enough to
|
||||
// satisfy the requirements of align_of_val_raw; this is an implementation
|
||||
// satisfy the requirements of Alignment::of_val_raw; this is an implementation
|
||||
// detail of the language that must not be relied upon outside of std.
|
||||
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
|
||||
unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn data_offset_align(align: Alignment) -> usize {
|
||||
fn data_offset_alignment(alignment: Alignment) -> usize {
|
||||
let layout = Layout::new::<RcInner<()>>();
|
||||
layout.size() + layout.padding_needed_for(align)
|
||||
layout.size() + layout.padding_needed_for(alignment)
|
||||
}
|
||||
|
||||
/// A uniquely owned [`Rc`].
|
||||
|
|
@ -4478,7 +4478,7 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
|
|||
|
||||
/// Returns the pointer to be written into to initialize the [`Rc`].
|
||||
fn data_ptr(&mut self) -> *mut T {
|
||||
let offset = data_offset_align(self.layout_for_value.alignment());
|
||||
let offset = data_offset_alignment(self.layout_for_value.alignment());
|
||||
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -444,13 +444,16 @@ impl<T> [T] {
|
|||
impl<T: TrivialClone> ConvertVec for T {
|
||||
#[inline]
|
||||
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
|
||||
let mut v = Vec::with_capacity_in(s.len(), alloc);
|
||||
let len = s.len();
|
||||
let mut v = Vec::with_capacity_in(len, alloc);
|
||||
// SAFETY:
|
||||
// allocated above with the capacity of `s`, and initialize to `s.len()` in
|
||||
// ptr::copy_to_non_overlapping below.
|
||||
unsafe {
|
||||
s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
|
||||
v.set_len(s.len());
|
||||
if len > 0 {
|
||||
unsafe {
|
||||
s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), len);
|
||||
v.set_len(len);
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use core::intrinsics::abort;
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::iter;
|
||||
use core::marker::{PhantomData, Unsize};
|
||||
use core::mem::{self, ManuallyDrop, align_of_val_raw};
|
||||
use core::mem::{self, ManuallyDrop};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
|
|
@ -4206,15 +4206,15 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
|
|||
// Because ArcInner is repr(C), it will always be the last field in memory.
|
||||
// SAFETY: since the only unsized types possible are slices, trait objects,
|
||||
// and extern types, the input safety requirement is currently enough to
|
||||
// satisfy the requirements of align_of_val_raw; this is an implementation
|
||||
// satisfy the requirements of Alignment::of_val_raw; this is an implementation
|
||||
// detail of the language that must not be relied upon outside of std.
|
||||
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
|
||||
unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn data_offset_align(align: Alignment) -> usize {
|
||||
fn data_offset_alignment(alignment: Alignment) -> usize {
|
||||
let layout = Layout::new::<ArcInner<()>>();
|
||||
layout.size() + layout.padding_needed_for(align)
|
||||
layout.size() + layout.padding_needed_for(alignment)
|
||||
}
|
||||
|
||||
/// A unique owning pointer to an [`ArcInner`] **that does not imply the contents are initialized,**
|
||||
|
|
@ -4258,7 +4258,7 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
|
|||
|
||||
/// Returns the pointer to be written into to initialize the [`Arc`].
|
||||
fn data_ptr(&mut self) -> *mut T {
|
||||
let offset = data_offset_align(self.layout_for_value.alignment());
|
||||
let offset = data_offset_alignment(self.layout_for_value.alignment());
|
||||
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2818,7 +2818,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
let count = other.len();
|
||||
self.reserve(count);
|
||||
let len = self.len();
|
||||
unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
|
||||
if count > 0 {
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count)
|
||||
};
|
||||
}
|
||||
self.len += count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,15 +67,16 @@ impl Layout {
|
|||
|
||||
#[inline]
|
||||
const fn is_size_align_valid(size: usize, align: usize) -> bool {
|
||||
let Some(align) = Alignment::new(align) else { return false };
|
||||
if size > Self::max_size_for_align(align) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
let Some(alignment) = Alignment::new(align) else { return false };
|
||||
Self::is_size_alignment_valid(size, alignment)
|
||||
}
|
||||
|
||||
const fn is_size_alignment_valid(size: usize, alignment: Alignment) -> bool {
|
||||
size <= Self::max_size_for_alignment(alignment)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn max_size_for_align(align: Alignment) -> usize {
|
||||
const fn max_size_for_alignment(alignment: Alignment) -> usize {
|
||||
// (power-of-two implies align != 0.)
|
||||
|
||||
// Rounded up size is:
|
||||
|
|
@ -93,18 +94,28 @@ impl Layout {
|
|||
|
||||
// SAFETY: the maximum possible alignment is `isize::MAX + 1`,
|
||||
// so the subtraction cannot overflow.
|
||||
unsafe { unchecked_sub(isize::MAX as usize + 1, align.as_usize()) }
|
||||
unsafe { unchecked_sub(isize::MAX as usize + 1, alignment.as_usize()) }
|
||||
}
|
||||
|
||||
/// Internal helper constructor to skip revalidating alignment validity.
|
||||
/// Constructs a `Layout` from a given `size` and `alignment`,
|
||||
/// or returns `LayoutError` if any of the following conditions
|
||||
/// are not met:
|
||||
///
|
||||
/// * `size`, when rounded up to the nearest multiple of `alignment`,
|
||||
/// must not overflow `isize` (i.e., the rounded value must be
|
||||
/// less than or equal to `isize::MAX`).
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
#[inline]
|
||||
const fn from_size_alignment(size: usize, align: Alignment) -> Result<Self, LayoutError> {
|
||||
if size > Self::max_size_for_align(align) {
|
||||
return Err(LayoutError);
|
||||
pub const fn from_size_alignment(
|
||||
size: usize,
|
||||
alignment: Alignment,
|
||||
) -> Result<Self, LayoutError> {
|
||||
if Layout::is_size_alignment_valid(size, alignment) {
|
||||
// SAFETY: Layout::size invariants checked above.
|
||||
Ok(Layout { size, align: alignment })
|
||||
} else {
|
||||
Err(LayoutError)
|
||||
}
|
||||
|
||||
// SAFETY: Layout::size invariants checked above.
|
||||
Ok(Layout { size, align })
|
||||
}
|
||||
|
||||
/// Creates a layout, bypassing all checks.
|
||||
|
|
@ -132,6 +143,30 @@ impl Layout {
|
|||
unsafe { Layout { size, align: mem::transmute(align) } }
|
||||
}
|
||||
|
||||
/// Creates a layout, bypassing all checks.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe as it does not verify the preconditions from
|
||||
/// [`Layout::from_size_alignment`].
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub const unsafe fn from_size_alignment_unchecked(size: usize, alignment: Alignment) -> Self {
|
||||
assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
"Layout::from_size_alignment_unchecked requires \
|
||||
that the rounded-up allocation size does not exceed isize::MAX",
|
||||
(
|
||||
size: usize = size,
|
||||
alignment: Alignment = alignment,
|
||||
) => Layout::is_size_alignment_valid(size, alignment)
|
||||
);
|
||||
// SAFETY: the caller is required to uphold the preconditions.
|
||||
Layout { size, align: alignment }
|
||||
}
|
||||
|
||||
/// The minimum size in bytes for a memory block of this layout.
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
|
||||
|
|
@ -153,6 +188,16 @@ impl Layout {
|
|||
self.align.as_usize()
|
||||
}
|
||||
|
||||
/// The minimum byte alignment for a memory block of this layout.
|
||||
///
|
||||
/// The returned alignment is guaranteed to be a power of two.
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
#[must_use = "this returns the minimum alignment, without modifying the layout"]
|
||||
#[inline]
|
||||
pub const fn alignment(&self) -> Alignment {
|
||||
self.align
|
||||
}
|
||||
|
||||
/// Constructs a `Layout` suitable for holding a value of type `T`.
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
|
||||
|
|
@ -170,9 +215,9 @@ impl Layout {
|
|||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
|
||||
let (size, align) = (size_of_val(t), align_of_val(t));
|
||||
let (size, alignment) = (size_of_val(t), Alignment::of_val(t));
|
||||
// SAFETY: see rationale in `new` for why this is using the unsafe variant
|
||||
unsafe { Layout::from_size_align_unchecked(size, align) }
|
||||
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
|
||||
}
|
||||
|
||||
/// Produces layout describing a record that could be used to
|
||||
|
|
@ -204,11 +249,12 @@ impl Layout {
|
|||
/// [extern type]: ../../unstable-book/language-features/extern-types.html
|
||||
#[unstable(feature = "layout_for_ptr", issue = "69835")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
|
||||
// SAFETY: we pass along the prerequisites of these functions to the caller
|
||||
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
|
||||
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
|
||||
// SAFETY: see rationale in `new` for why this is using the unsafe variant
|
||||
unsafe { Layout::from_size_align_unchecked(size, align) }
|
||||
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
|
||||
}
|
||||
|
||||
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
|
||||
|
|
@ -243,13 +289,33 @@ impl Layout {
|
|||
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
|
||||
#[inline]
|
||||
pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
|
||||
if let Some(align) = Alignment::new(align) {
|
||||
Layout::from_size_alignment(self.size, Alignment::max(self.align, align))
|
||||
if let Some(alignment) = Alignment::new(align) {
|
||||
self.adjust_alignment_to(alignment)
|
||||
} else {
|
||||
Err(LayoutError)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a layout describing the record that can hold a value
|
||||
/// of the same layout as `self`, but that also is aligned to
|
||||
/// alignment `alignment`.
|
||||
///
|
||||
/// If `self` already meets the prescribed alignment, then returns
|
||||
/// `self`.
|
||||
///
|
||||
/// Note that this method does not add any padding to the overall
|
||||
/// size, regardless of whether the returned layout has a different
|
||||
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
|
||||
/// will *still* have size 16.
|
||||
///
|
||||
/// Returns an error if the combination of `self.size()` and the given
|
||||
/// `alignment` violates the conditions listed in [`Layout::from_size_alignment`].
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
#[inline]
|
||||
pub const fn adjust_alignment_to(&self, alignment: Alignment) -> Result<Self, LayoutError> {
|
||||
Layout::from_size_alignment(self.size, Alignment::max(self.align, alignment))
|
||||
}
|
||||
|
||||
/// Returns the amount of padding we must insert after `self`
|
||||
/// to ensure that the following address will satisfy `alignment`.
|
||||
///
|
||||
|
|
@ -267,7 +333,7 @@ impl Layout {
|
|||
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
|
||||
#[inline]
|
||||
pub const fn padding_needed_for(&self, alignment: Alignment) -> usize {
|
||||
let len_rounded_up = self.size_rounded_up_to_custom_align(alignment);
|
||||
let len_rounded_up = self.size_rounded_up_to_custom_alignment(alignment);
|
||||
// SAFETY: Cannot overflow because the rounded-up value is never less
|
||||
unsafe { unchecked_sub(len_rounded_up, self.size) }
|
||||
}
|
||||
|
|
@ -277,7 +343,7 @@ impl Layout {
|
|||
/// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`)
|
||||
/// because the original size is at most `isize::MAX`.
|
||||
#[inline]
|
||||
const fn size_rounded_up_to_custom_align(&self, align: Alignment) -> usize {
|
||||
const fn size_rounded_up_to_custom_alignment(&self, alignment: Alignment) -> usize {
|
||||
// SAFETY:
|
||||
// Rounded up value is:
|
||||
// size_rounded_up = (size + align - 1) & !(align - 1);
|
||||
|
|
@ -297,7 +363,7 @@ impl Layout {
|
|||
// (Size 0 Align MAX is already aligned, so stays the same, but things like
|
||||
// Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.)
|
||||
unsafe {
|
||||
let align_m1 = unchecked_sub(align.as_usize(), 1);
|
||||
let align_m1 = unchecked_sub(alignment.as_usize(), 1);
|
||||
unchecked_add(self.size, align_m1) & !align_m1
|
||||
}
|
||||
}
|
||||
|
|
@ -317,10 +383,10 @@ impl Layout {
|
|||
// > `size`, when rounded up to the nearest multiple of `align`,
|
||||
// > must not overflow isize (i.e., the rounded value must be
|
||||
// > less than or equal to `isize::MAX`)
|
||||
let new_size = self.size_rounded_up_to_custom_align(self.align);
|
||||
let new_size = self.size_rounded_up_to_custom_alignment(self.align);
|
||||
|
||||
// SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
|
||||
unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
|
||||
unsafe { Layout::from_size_alignment_unchecked(new_size, self.alignment()) }
|
||||
}
|
||||
|
||||
/// Creates a layout describing the record for `n` instances of
|
||||
|
|
@ -426,8 +492,8 @@ impl Layout {
|
|||
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
|
||||
#[inline]
|
||||
pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
|
||||
let new_align = Alignment::max(self.align, next.align);
|
||||
let offset = self.size_rounded_up_to_custom_align(next.align);
|
||||
let new_alignment = Alignment::max(self.align, next.align);
|
||||
let offset = self.size_rounded_up_to_custom_alignment(next.align);
|
||||
|
||||
// SAFETY: `offset` is at most `isize::MAX + 1` (such as from aligning
|
||||
// to `Alignment::MAX`) and `next.size` is at most `isize::MAX` (from the
|
||||
|
|
@ -435,7 +501,7 @@ impl Layout {
|
|||
// `isize::MAX + 1 + isize::MAX`, which is `usize::MAX`, and cannot overflow.
|
||||
let new_size = unsafe { unchecked_add(offset, next.size) };
|
||||
|
||||
if let Ok(layout) = Layout::from_size_alignment(new_size, new_align) {
|
||||
if let Ok(layout) = Layout::from_size_alignment(new_size, new_alignment) {
|
||||
Ok((layout, offset))
|
||||
} else {
|
||||
Err(LayoutError)
|
||||
|
|
@ -496,7 +562,7 @@ impl Layout {
|
|||
|
||||
#[inline]
|
||||
const fn inner(element_layout: Layout, n: usize) -> Result<Layout, LayoutError> {
|
||||
let Layout { size: element_size, align } = element_layout;
|
||||
let Layout { size: element_size, align: alignment } = element_layout;
|
||||
|
||||
// We need to check two things about the size:
|
||||
// - That the total size won't overflow a `usize`, and
|
||||
|
|
@ -504,7 +570,7 @@ impl Layout {
|
|||
// By using division we can check them both with a single threshold.
|
||||
// That'd usually be a bad idea, but thankfully here the element size
|
||||
// and alignment are constants, so the compiler will fold all of it.
|
||||
if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
|
||||
if element_size != 0 && n > Layout::max_size_for_alignment(alignment) / element_size {
|
||||
return Err(LayoutError);
|
||||
}
|
||||
|
||||
|
|
@ -517,17 +583,9 @@ impl Layout {
|
|||
// SAFETY: We just checked above that the `array_size` will not
|
||||
// exceed `isize::MAX` even when rounded up to the alignment.
|
||||
// And `Alignment` guarantees it's a power of two.
|
||||
unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
|
||||
unsafe { Ok(Layout::from_size_alignment_unchecked(array_size, alignment)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Perma-unstable access to `align` as `Alignment` type.
|
||||
#[unstable(issue = "none", feature = "std_internals")]
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub const fn alignment(&self) -> Alignment {
|
||||
self.align
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl<T, const N: usize> IntoIterator for [T; N] {
|
|||
// FIXME: If normal `transmute` ever gets smart enough to allow this
|
||||
// directly, use it instead of `transmute_unchecked`.
|
||||
let data: [MaybeUninit<T>; N] = unsafe { transmute_unchecked(self) };
|
||||
// SAFETY: The original array was entirely initialized and the the alive
|
||||
// SAFETY: The original array was entirely initialized and the alive
|
||||
// range we're passing here represents that fact.
|
||||
let inner = unsafe { InnerSized::new_unchecked(IndexRange::zero_to(N), data) };
|
||||
IntoIter { inner: ManuallyDrop::new(inner) }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use crate::alloc::Layout;
|
|||
use crate::clone::TrivialClone;
|
||||
use crate::marker::{Destruct, DiscriminantKind};
|
||||
use crate::panic::const_assert;
|
||||
use crate::ptr::Alignment;
|
||||
use crate::{clone, cmp, fmt, hash, intrinsics, ptr};
|
||||
|
||||
mod manually_drop;
|
||||
|
|
@ -1257,6 +1258,10 @@ pub trait SizedTypeProperties: Sized {
|
|||
#[lang = "mem_align_const"]
|
||||
const ALIGN: usize = intrinsics::align_of::<Self>();
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
const ALIGNMENT: Alignment = Alignment::of::<Self>();
|
||||
|
||||
/// `true` if this type requires no storage.
|
||||
/// `false` if its [size](size_of) is greater than zero.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(clippy::enum_clike_unportable_variant)]
|
||||
|
||||
use crate::marker::MetaSized;
|
||||
use crate::num::NonZero;
|
||||
use crate::ub_checks::assert_unsafe_precondition;
|
||||
use crate::{cmp, fmt, hash, mem, num};
|
||||
|
|
@ -50,6 +51,79 @@ impl Alignment {
|
|||
const { Alignment::new(align_of::<T>()).unwrap() }
|
||||
}
|
||||
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
|
||||
///
|
||||
/// Every reference to a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_alignment_type)]
|
||||
/// use std::ptr::Alignment;
|
||||
///
|
||||
/// assert_eq!(Alignment::of_val(&5i32).as_usize(), 4);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
pub const fn of_val<T: MetaSized>(val: &T) -> Self {
|
||||
let align = mem::align_of_val(val);
|
||||
// SAFETY: `align_of_val` returns valid alignment
|
||||
unsafe { Alignment::new_unchecked(align) }
|
||||
}
|
||||
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
|
||||
///
|
||||
/// Every reference to a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is only safe to call if the following conditions hold:
|
||||
///
|
||||
/// - If `T` is `Sized`, this function is always safe to call.
|
||||
/// - If the unsized tail of `T` is:
|
||||
/// - a [slice], then the length of the slice tail must be an initialized
|
||||
/// integer, and the size of the *entire value*
|
||||
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
|
||||
/// For the special case where the dynamic tail length is 0, this function
|
||||
/// is safe to call.
|
||||
/// - a [trait object], then the vtable part of the pointer must point
|
||||
/// to a valid vtable acquired by an unsizing coercion, and the size
|
||||
/// of the *entire value* (dynamic tail length + statically sized prefix)
|
||||
/// must fit in `isize`.
|
||||
/// - an (unstable) [extern type], then this function is always safe to
|
||||
/// call, but may panic or otherwise return the wrong value, as the
|
||||
/// extern type's layout is not known. This is the same behavior as
|
||||
/// [`Alignment::of_val`] on a reference to a type with an extern type tail.
|
||||
/// - otherwise, it is conservatively not allowed to call this function.
|
||||
///
|
||||
/// [trait object]: ../../book/ch17-02-trait-objects.html
|
||||
/// [extern type]: ../../unstable-book/language-features/extern-types.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_alignment_type)]
|
||||
/// #![feature(layout_for_ptr)]
|
||||
/// use std::ptr::Alignment;
|
||||
///
|
||||
/// assert_eq!(unsafe { Alignment::of_val_raw(&5i32) }.as_usize(), 4);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
|
||||
// #[unstable(feature = "layout_for_ptr", issue = "69835")]
|
||||
pub const unsafe fn of_val_raw<T: MetaSized>(val: *const T) -> Self {
|
||||
// SAFETY: precondition propagated to the caller
|
||||
let align = unsafe { mem::align_of_val_raw(val) };
|
||||
// SAFETY: `align_of_val_raw` returns valid alignment
|
||||
unsafe { Alignment::new_unchecked(align) }
|
||||
}
|
||||
|
||||
/// Creates an `Alignment` from a `usize`, or returns `None` if it's
|
||||
/// not a power of two.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -6,93 +6,66 @@ use std::sync::atomic::AtomicU32;
|
|||
|
||||
use super::*;
|
||||
|
||||
macro_rules! define_client_handles {
|
||||
(
|
||||
'owned: $($oty:ident,)*
|
||||
'interned: $($ity:ident,)*
|
||||
) => {
|
||||
#[repr(C)]
|
||||
#[allow(non_snake_case)]
|
||||
pub(super) struct HandleCounters {
|
||||
$(pub(super) $oty: AtomicU32,)*
|
||||
$(pub(super) $ity: AtomicU32,)*
|
||||
}
|
||||
#[repr(C)]
|
||||
pub(super) struct HandleCounters {
|
||||
pub(super) token_stream: AtomicU32,
|
||||
pub(super) span: AtomicU32,
|
||||
}
|
||||
|
||||
static COUNTERS: HandleCounters = HandleCounters {
|
||||
$($oty: AtomicU32::new(1),)*
|
||||
$($ity: AtomicU32::new(1),)*
|
||||
};
|
||||
static COUNTERS: HandleCounters =
|
||||
HandleCounters { token_stream: AtomicU32::new(1), span: AtomicU32::new(1) };
|
||||
|
||||
$(
|
||||
pub(crate) struct $oty {
|
||||
handle: handle::Handle,
|
||||
}
|
||||
pub(crate) struct TokenStream {
|
||||
handle: handle::Handle,
|
||||
}
|
||||
|
||||
impl !Send for $oty {}
|
||||
impl !Sync for $oty {}
|
||||
impl !Send for TokenStream {}
|
||||
impl !Sync for TokenStream {}
|
||||
|
||||
// Forward `Drop::drop` to the inherent `drop` method.
|
||||
impl Drop for $oty {
|
||||
fn drop(&mut self) {
|
||||
$oty {
|
||||
handle: self.handle,
|
||||
}.drop();
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for $oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
mem::ManuallyDrop::new(self).handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &$oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &mut $oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for $oty {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
$oty {
|
||||
handle: handle::Handle::decode(r, s),
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
$(
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct $ity {
|
||||
handle: handle::Handle,
|
||||
}
|
||||
|
||||
impl !Send for $ity {}
|
||||
impl !Sync for $ity {}
|
||||
|
||||
impl<S> Encode<S> for $ity {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for $ity {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
$ity {
|
||||
handle: handle::Handle::decode(r, s),
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
// Forward `Drop::drop` to the inherent `drop` method.
|
||||
impl Drop for TokenStream {
|
||||
fn drop(&mut self) {
|
||||
Methods::ts_drop(TokenStream { handle: self.handle });
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for TokenStream {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
mem::ManuallyDrop::new(self).handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &TokenStream {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for TokenStream {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
TokenStream { handle: handle::Handle::decode(r, s) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct Span {
|
||||
handle: handle::Handle,
|
||||
}
|
||||
|
||||
impl !Send for Span {}
|
||||
impl !Sync for Span {}
|
||||
|
||||
impl<S> Encode<S> for Span {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for Span {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
Span { handle: handle::Handle::decode(r, s) }
|
||||
}
|
||||
}
|
||||
with_api_handle_types!(define_client_handles);
|
||||
|
||||
// FIXME(eddyb) generate these impls by pattern-matching on the
|
||||
// names of methods - also could use the presence of `fn drop`
|
||||
|
|
@ -102,7 +75,7 @@ with_api_handle_types!(define_client_handles);
|
|||
|
||||
impl Clone for TokenStream {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone()
|
||||
Methods::ts_clone(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,23 +95,27 @@ impl Span {
|
|||
|
||||
impl fmt::Debug for Span {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.debug())
|
||||
f.write_str(&Methods::span_debug(*self))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use super::Methods;
|
||||
pub(crate) use super::symbol::Symbol;
|
||||
|
||||
macro_rules! define_client_side {
|
||||
($($name:ident {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
|
||||
}),* $(,)?) => {
|
||||
$(impl $name {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
impl Methods {
|
||||
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
|
||||
Bridge::with(|bridge| {
|
||||
let mut buf = bridge.cached_buffer.take();
|
||||
|
||||
buf.clear();
|
||||
api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ());
|
||||
api_tags::Method::$method.encode(&mut buf, &mut ());
|
||||
$($arg.encode(&mut buf, &mut ());)*
|
||||
|
||||
buf = bridge.dispatch.call(buf);
|
||||
|
|
@ -150,7 +127,7 @@ macro_rules! define_client_side {
|
|||
r.unwrap_or_else(|e| panic::resume_unwind(e.into()))
|
||||
})
|
||||
})*
|
||||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
with_api!(self, self, define_client_side);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::hash::Hash;
|
||||
use std::num::NonZero;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ops::Index;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use super::fxhash::FxHashMap;
|
||||
|
|
@ -47,12 +47,6 @@ impl<T> Index<Handle> for OwnedStore<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> IndexMut<Handle> for OwnedStore<T> {
|
||||
fn index_mut(&mut self, h: Handle) -> &mut T {
|
||||
self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle")
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `OwnedStore`, but avoids storing any value more than once.
|
||||
pub(super) struct InternedStore<T: 'static> {
|
||||
owned: OwnedStore<T>,
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ use crate::{Delimiter, Level, Spacing};
|
|||
/// `with_api!(MySelf, my_self, my_macro)` expands to:
|
||||
/// ```rust,ignore (pseudo-code)
|
||||
/// my_macro! {
|
||||
/// // ...
|
||||
/// Literal {
|
||||
/// Methods {
|
||||
/// // ...
|
||||
/// fn character(ch: char) -> MySelf::Literal;
|
||||
/// fn lit_character(ch: char) -> MySelf::Literal;
|
||||
/// // ...
|
||||
/// fn span(my_self: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// fn lit_span(my_self: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn lit_set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// },
|
||||
/// Literal,
|
||||
/// Span,
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
|
|
@ -48,77 +49,62 @@ use crate::{Delimiter, Level, Spacing};
|
|||
macro_rules! with_api {
|
||||
($S:ident, $self:ident, $m:ident) => {
|
||||
$m! {
|
||||
FreeFunctions {
|
||||
fn drop($self: $S::FreeFunctions);
|
||||
Methods {
|
||||
fn injected_env_var(var: &str) -> Option<String>;
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
|
||||
},
|
||||
TokenStream {
|
||||
fn drop($self: $S::TokenStream);
|
||||
fn clone($self: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn is_empty($self: &$S::TokenStream) -> bool;
|
||||
fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn from_str(src: &str) -> $S::TokenStream;
|
||||
fn to_string($self: &$S::TokenStream) -> String;
|
||||
fn from_token_tree(
|
||||
|
||||
fn ts_drop(stream: $S::TokenStream);
|
||||
fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn ts_is_empty(stream: &$S::TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $S::TokenStream;
|
||||
fn ts_to_string(stream: &$S::TokenStream) -> String;
|
||||
fn ts_from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
fn concat_trees(
|
||||
fn ts_concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
fn concat_streams(
|
||||
fn ts_concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
streams: Vec<$S::TokenStream>,
|
||||
) -> $S::TokenStream;
|
||||
fn into_trees(
|
||||
$self: $S::TokenStream
|
||||
fn ts_into_trees(
|
||||
stream: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
},
|
||||
Span {
|
||||
fn debug($self: $S::Span) -> String;
|
||||
fn parent($self: $S::Span) -> Option<$S::Span>;
|
||||
fn source($self: $S::Span) -> $S::Span;
|
||||
fn byte_range($self: $S::Span) -> Range<usize>;
|
||||
fn start($self: $S::Span) -> $S::Span;
|
||||
fn end($self: $S::Span) -> $S::Span;
|
||||
fn line($self: $S::Span) -> usize;
|
||||
fn column($self: $S::Span) -> usize;
|
||||
fn file($self: $S::Span) -> String;
|
||||
fn local_file($self: $S::Span) -> Option<String>;
|
||||
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn subspan($self: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn source_text($self: $S::Span) -> Option<String>;
|
||||
fn save_span($self: $S::Span) -> usize;
|
||||
fn recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
},
|
||||
Symbol {
|
||||
fn normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Similar to `with_api`, but only lists the types requiring handles, and they
|
||||
// are divided into the two storage categories.
|
||||
macro_rules! with_api_handle_types {
|
||||
($m:ident) => {
|
||||
$m! {
|
||||
'owned:
|
||||
FreeFunctions,
|
||||
fn span_debug(span: $S::Span) -> String;
|
||||
fn span_parent(span: $S::Span) -> Option<$S::Span>;
|
||||
fn span_source(span: $S::Span) -> $S::Span;
|
||||
fn span_byte_range(span: $S::Span) -> Range<usize>;
|
||||
fn span_start(span: $S::Span) -> $S::Span;
|
||||
fn span_end(span: $S::Span) -> $S::Span;
|
||||
fn span_line(span: $S::Span) -> usize;
|
||||
fn span_column(span: $S::Span) -> usize;
|
||||
fn span_file(span: $S::Span) -> String;
|
||||
fn span_local_file(span: $S::Span) -> Option<String>;
|
||||
fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn span_source_text(span: $S::Span) -> Option<String>;
|
||||
fn span_save_span(span: $S::Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
},
|
||||
TokenStream,
|
||||
|
||||
'interned:
|
||||
Span,
|
||||
// Symbol is handled manually
|
||||
Symbol,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct Methods;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
mod arena;
|
||||
#[allow(unsafe_code)]
|
||||
|
|
@ -171,20 +157,16 @@ mod api_tags {
|
|||
use super::rpc::{Decode, Encode, Reader, Writer};
|
||||
|
||||
macro_rules! declare_tags {
|
||||
($($name:ident {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
}),* $(,)?) => {
|
||||
$(
|
||||
pub(super) enum $name {
|
||||
$($method),*
|
||||
}
|
||||
rpc_encode_decode!(enum $name { $($method),* });
|
||||
)*
|
||||
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
pub(super) enum Method {
|
||||
$($name($name)),*
|
||||
$($method),*
|
||||
}
|
||||
rpc_encode_decode!(enum Method { $($name(m)),* });
|
||||
rpc_encode_decode!(enum Method { $($method),* });
|
||||
}
|
||||
}
|
||||
with_api!(self, self, declare_tags);
|
||||
|
|
|
|||
|
|
@ -5,108 +5,66 @@ use std::marker::PhantomData;
|
|||
|
||||
use super::*;
|
||||
|
||||
macro_rules! define_server_handles {
|
||||
(
|
||||
'owned: $($oty:ident,)*
|
||||
'interned: $($ity:ident,)*
|
||||
) => {
|
||||
#[allow(non_snake_case)]
|
||||
pub(super) struct HandleStore<S: Types> {
|
||||
$($oty: handle::OwnedStore<S::$oty>,)*
|
||||
$($ity: handle::InternedStore<S::$ity>,)*
|
||||
pub(super) struct HandleStore<S: Types> {
|
||||
token_stream: handle::OwnedStore<Marked<S::TokenStream, client::TokenStream>>,
|
||||
span: handle::InternedStore<Marked<S::Span, client::Span>>,
|
||||
}
|
||||
|
||||
impl<S: Types> HandleStore<S> {
|
||||
fn new(handle_counters: &'static client::HandleCounters) -> Self {
|
||||
HandleStore {
|
||||
token_stream: handle::OwnedStore::new(&handle_counters.token_stream),
|
||||
span: handle::InternedStore::new(&handle_counters.span),
|
||||
}
|
||||
|
||||
impl<S: Types> HandleStore<S> {
|
||||
fn new(handle_counters: &'static client::HandleCounters) -> Self {
|
||||
HandleStore {
|
||||
$($oty: handle::OwnedStore::new(&handle_counters.$oty),)*
|
||||
$($ity: handle::InternedStore::new(&handle_counters.$ity),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl<S: Types> Encode<HandleStore<MarkedTypes<S>>> for Marked<S::$oty, client::$oty> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<MarkedTypes<S>>) {
|
||||
s.$oty.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<MarkedTypes<S>>>
|
||||
for Marked<S::$oty, client::$oty>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<MarkedTypes<S>>) -> Self {
|
||||
s.$oty.take(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: Types> Decode<'_, 's, HandleStore<MarkedTypes<S>>>
|
||||
for &'s Marked<S::$oty, client::$oty>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore<MarkedTypes<S>>) -> Self {
|
||||
&s.$oty[handle::Handle::decode(r, &mut ())]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: Types> Decode<'_, 's, HandleStore<MarkedTypes<S>>>
|
||||
for &'s mut Marked<S::$oty, client::$oty>
|
||||
{
|
||||
fn decode(
|
||||
r: &mut Reader<'_>,
|
||||
s: &'s mut HandleStore<MarkedTypes<S>>
|
||||
) -> Self {
|
||||
&mut s.$oty[handle::Handle::decode(r, &mut ())]
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
$(
|
||||
impl<S: Types> Encode<HandleStore<MarkedTypes<S>>> for Marked<S::$ity, client::$ity> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<MarkedTypes<S>>) {
|
||||
s.$ity.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<MarkedTypes<S>>>
|
||||
for Marked<S::$ity, client::$ity>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<MarkedTypes<S>>) -> Self {
|
||||
s.$ity.copy(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
with_api_handle_types!(define_server_handles);
|
||||
|
||||
impl<S: Types> Encode<HandleStore<S>> for Marked<S::TokenStream, client::TokenStream> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<S>) {
|
||||
s.token_stream.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<S>> for Marked<S::TokenStream, client::TokenStream> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<S>) -> Self {
|
||||
s.token_stream.take(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: Types> Decode<'_, 's, HandleStore<S>>
|
||||
for &'s Marked<S::TokenStream, client::TokenStream>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore<S>) -> Self {
|
||||
&s.token_stream[handle::Handle::decode(r, &mut ())]
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Encode<HandleStore<S>> for Marked<S::Span, client::Span> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<S>) {
|
||||
s.span.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<S>> for Marked<S::Span, client::Span> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<S>) -> Self {
|
||||
s.span.copy(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Types {
|
||||
type FreeFunctions: 'static;
|
||||
type TokenStream: 'static + Clone;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
}
|
||||
|
||||
/// Declare an associated fn of one of the traits below, adding necessary
|
||||
/// default bodies.
|
||||
macro_rules! associated_fn {
|
||||
(fn drop(&mut self, $arg:ident: $arg_ty:ty)) =>
|
||||
(fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) });
|
||||
|
||||
(fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) =>
|
||||
(fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() });
|
||||
|
||||
($($item:tt)*) => ($($item)*;)
|
||||
}
|
||||
|
||||
macro_rules! declare_server_traits {
|
||||
($($name:ident {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
|
||||
}),* $(,)?) => {
|
||||
$(pub trait $name: Types {
|
||||
$(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)*
|
||||
})*
|
||||
|
||||
pub trait Server: Types $(+ $name)* {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
pub trait Server: Types {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span>;
|
||||
|
||||
/// Intern a symbol received from RPC
|
||||
|
|
@ -114,51 +72,25 @@ macro_rules! declare_server_traits {
|
|||
|
||||
/// Recover the string value of a symbol, and invoke a callback with it.
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str));
|
||||
|
||||
$(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)*
|
||||
}
|
||||
}
|
||||
}
|
||||
with_api!(Self, self_, declare_server_traits);
|
||||
|
||||
pub(super) struct MarkedTypes<S: Types>(S);
|
||||
|
||||
impl<S: Server> Server for MarkedTypes<S> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
<_>::mark(Server::globals(&mut self.0))
|
||||
}
|
||||
fn intern_symbol(ident: &str) -> Self::Symbol {
|
||||
<_>::mark(S::intern_symbol(ident))
|
||||
}
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
S::with_symbol_string(symbol.unmark(), f)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_mark_types_impls {
|
||||
($($name:ident {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
|
||||
}),* $(,)?) => {
|
||||
impl<S: Types> Types for MarkedTypes<S> {
|
||||
$(type $name = Marked<S::$name, client::$name>;)*
|
||||
}
|
||||
|
||||
$(impl<S: $name> $name for MarkedTypes<S> {
|
||||
$(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? {
|
||||
<_>::mark($name::$method(&mut self.0, $($arg.unmark()),*))
|
||||
})*
|
||||
})*
|
||||
}
|
||||
}
|
||||
with_api!(Self, self_, define_mark_types_impls);
|
||||
|
||||
struct Dispatcher<S: Types> {
|
||||
handle_store: HandleStore<S>,
|
||||
server: S,
|
||||
}
|
||||
|
||||
macro_rules! define_dispatcher_impl {
|
||||
($($name:ident {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
|
||||
}),* $(,)?) => {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
|
||||
pub trait DispatcherTrait {
|
||||
// HACK(eddyb) these are here to allow `Self::$name` to work below.
|
||||
|
|
@ -167,35 +99,37 @@ macro_rules! define_dispatcher_impl {
|
|||
fn dispatch(&mut self, buf: Buffer) -> Buffer;
|
||||
}
|
||||
|
||||
impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> {
|
||||
$(type $name = <MarkedTypes<S> as Types>::$name;)*
|
||||
impl<S: Server> DispatcherTrait for Dispatcher<S> {
|
||||
$(type $name = Marked<S::$name, client::$name>;)*
|
||||
|
||||
fn dispatch(&mut self, mut buf: Buffer) -> Buffer {
|
||||
let Dispatcher { handle_store, server } = self;
|
||||
|
||||
let mut reader = &buf[..];
|
||||
match api_tags::Method::decode(&mut reader, &mut ()) {
|
||||
$(api_tags::Method::$name(m) => match m {
|
||||
$(api_tags::$name::$method => {
|
||||
let mut call_method = || {
|
||||
$(let $arg = <$arg_ty>::decode(&mut reader, handle_store);)*
|
||||
$name::$method(server, $($arg),*)
|
||||
};
|
||||
// HACK(eddyb) don't use `panic::catch_unwind` in a panic.
|
||||
// If client and server happen to use the same `std`,
|
||||
// `catch_unwind` asserts that the panic counter was 0,
|
||||
// even when the closure passed to it didn't panic.
|
||||
let r = if thread::panicking() {
|
||||
Ok(call_method())
|
||||
} else {
|
||||
panic::catch_unwind(panic::AssertUnwindSafe(call_method))
|
||||
.map_err(PanicMessage::from)
|
||||
};
|
||||
$(api_tags::Method::$method => {
|
||||
let mut call_method = || {
|
||||
$(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)*
|
||||
let r = server.$method($($arg),*);
|
||||
$(
|
||||
let r: $ret_ty = Mark::mark(r);
|
||||
)*
|
||||
r
|
||||
};
|
||||
// HACK(eddyb) don't use `panic::catch_unwind` in a panic.
|
||||
// If client and server happen to use the same `std`,
|
||||
// `catch_unwind` asserts that the panic counter was 0,
|
||||
// even when the closure passed to it didn't panic.
|
||||
let r = if thread::panicking() {
|
||||
Ok(call_method())
|
||||
} else {
|
||||
panic::catch_unwind(panic::AssertUnwindSafe(call_method))
|
||||
.map_err(PanicMessage::from)
|
||||
};
|
||||
|
||||
buf.clear();
|
||||
r.encode(&mut buf, handle_store);
|
||||
})*
|
||||
}),*
|
||||
buf.clear();
|
||||
r.encode(&mut buf, handle_store);
|
||||
})*
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
|
@ -354,8 +288,8 @@ pub trait MessagePipe<T>: Sized {
|
|||
|
||||
fn run_server<
|
||||
S: Server,
|
||||
I: Encode<HandleStore<MarkedTypes<S>>>,
|
||||
O: for<'a, 's> Decode<'a, 's, HandleStore<MarkedTypes<S>>>,
|
||||
I: Encode<HandleStore<S>>,
|
||||
O: for<'a, 's> Decode<'a, 's, HandleStore<S>>,
|
||||
>(
|
||||
strategy: &impl ExecutionStrategy,
|
||||
handle_counters: &'static client::HandleCounters,
|
||||
|
|
@ -364,13 +298,13 @@ fn run_server<
|
|||
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
|
||||
force_show_panics: bool,
|
||||
) -> Result<O, PanicMessage> {
|
||||
let mut dispatcher =
|
||||
Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) };
|
||||
let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server };
|
||||
|
||||
let globals = dispatcher.server.globals();
|
||||
|
||||
let mut buf = Buffer::new();
|
||||
(globals, input).encode(&mut buf, &mut dispatcher.handle_store);
|
||||
(<ExpnGlobals<Marked<S::Span, client::Span>> as Mark>::mark(globals), input)
|
||||
.encode(&mut buf, &mut dispatcher.handle_store);
|
||||
|
||||
buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics);
|
||||
|
||||
|
|
@ -394,11 +328,13 @@ impl client::Client<crate::TokenStream, crate::TokenStream> {
|
|||
strategy,
|
||||
handle_counters,
|
||||
server,
|
||||
<MarkedTypes<S> as Types>::TokenStream::mark(input),
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input),
|
||||
run,
|
||||
force_show_panics,
|
||||
)
|
||||
.map(|s| <Option<<MarkedTypes<S> as Types>::TokenStream>>::unmark(s).unwrap_or_default())
|
||||
.map(|s| {
|
||||
<Option<Marked<S::TokenStream, client::TokenStream>>>::unmark(s).unwrap_or_default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,12 +357,14 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream
|
|||
handle_counters,
|
||||
server,
|
||||
(
|
||||
<MarkedTypes<S> as Types>::TokenStream::mark(input),
|
||||
<MarkedTypes<S> as Types>::TokenStream::mark(input2),
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input),
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input2),
|
||||
),
|
||||
run,
|
||||
force_show_panics,
|
||||
)
|
||||
.map(|s| <Option<<MarkedTypes<S> as Types>::TokenStream>>::unmark(s).unwrap_or_default())
|
||||
.map(|s| {
|
||||
<Option<Marked<S::TokenStream, client::TokenStream>>>::unmark(s).unwrap_or_default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ impl Symbol {
|
|||
if string.is_ascii() {
|
||||
Err(())
|
||||
} else {
|
||||
client::Symbol::normalize_and_validate_ident(string)
|
||||
client::Methods::symbol_normalize_and_validate_ident(string)
|
||||
}
|
||||
.unwrap_or_else(|_| panic!("`{:?}` is not a valid identifier", string))
|
||||
}
|
||||
|
|
@ -99,18 +99,14 @@ impl<S> Encode<S> for Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: server::Server> Decode<'_, '_, server::HandleStore<server::MarkedTypes<S>>>
|
||||
for Marked<S::Symbol, Symbol>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore<server::MarkedTypes<S>>) -> Self {
|
||||
impl<S: server::Server> Decode<'_, '_, server::HandleStore<S>> for Marked<S::Symbol, Symbol> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore<S>) -> Self {
|
||||
Mark::mark(S::intern_symbol(<&str>::decode(r, s)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: server::Server> Encode<server::HandleStore<server::MarkedTypes<S>>>
|
||||
for Marked<S::Symbol, Symbol>
|
||||
{
|
||||
fn encode(self, w: &mut Writer, s: &mut server::HandleStore<server::MarkedTypes<S>>) {
|
||||
impl<S: server::Server> Encode<server::HandleStore<S>> for Marked<S::Symbol, Symbol> {
|
||||
fn encode(self, w: &mut Writer, s: &mut server::HandleStore<S>) {
|
||||
S::with_symbol_string(&self.unmark(), |sym| sym.encode(w, s))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,6 +170,6 @@ impl Diagnostic {
|
|||
}
|
||||
}
|
||||
|
||||
crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self));
|
||||
crate::bridge::client::Methods::emit_diagnostic(to_internal(self));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ use rustc_literal_escaper::{MixedUnit, unescape_byte_str, unescape_c_str, unesca
|
|||
#[unstable(feature = "proc_macro_totokens", issue = "130977")]
|
||||
pub use to_tokens::ToTokens;
|
||||
|
||||
use crate::bridge::client::Methods as BridgeMethods;
|
||||
use crate::escape::{EscapeOptions, escape_bytes};
|
||||
|
||||
/// Errors returned when trying to retrieve a literal unescaped value.
|
||||
|
|
@ -158,7 +159,7 @@ impl TokenStream {
|
|||
/// Checks if this `TokenStream` is empty.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true)
|
||||
self.0.as_ref().map(|h| BridgeMethods::ts_is_empty(h)).unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Parses this `TokenStream` as an expression and attempts to expand any
|
||||
|
|
@ -174,7 +175,7 @@ impl TokenStream {
|
|||
#[unstable(feature = "proc_macro_expand", issue = "90765")]
|
||||
pub fn expand_expr(&self) -> Result<TokenStream, ExpandError> {
|
||||
let stream = self.0.as_ref().ok_or(ExpandError)?;
|
||||
match bridge::client::TokenStream::expand_expr(stream) {
|
||||
match BridgeMethods::ts_expand_expr(stream) {
|
||||
Ok(stream) => Ok(TokenStream(Some(stream))),
|
||||
Err(_) => Err(ExpandError),
|
||||
}
|
||||
|
|
@ -193,7 +194,7 @@ impl FromStr for TokenStream {
|
|||
type Err = LexError;
|
||||
|
||||
fn from_str(src: &str) -> Result<TokenStream, LexError> {
|
||||
Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src))))
|
||||
Ok(TokenStream(Some(BridgeMethods::ts_from_str(src))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +213,7 @@ impl FromStr for TokenStream {
|
|||
impl fmt::Display for TokenStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self.0 {
|
||||
Some(ts) => write!(f, "{}", ts.to_string()),
|
||||
Some(ts) => write!(f, "{}", BridgeMethods::ts_to_string(ts)),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
@ -252,7 +253,7 @@ fn tree_to_bridge_tree(
|
|||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
impl From<TokenTree> for TokenStream {
|
||||
fn from(tree: TokenTree) -> TokenStream {
|
||||
TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree))))
|
||||
TokenStream(Some(BridgeMethods::ts_from_token_tree(tree_to_bridge_tree(tree))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +282,7 @@ impl ConcatTreesHelper {
|
|||
if self.trees.is_empty() {
|
||||
TokenStream(None)
|
||||
} else {
|
||||
TokenStream(Some(bridge::client::TokenStream::concat_trees(None, self.trees)))
|
||||
TokenStream(Some(BridgeMethods::ts_concat_trees(None, self.trees)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +290,7 @@ impl ConcatTreesHelper {
|
|||
if self.trees.is_empty() {
|
||||
return;
|
||||
}
|
||||
stream.0 = Some(bridge::client::TokenStream::concat_trees(stream.0.take(), self.trees))
|
||||
stream.0 = Some(BridgeMethods::ts_concat_trees(stream.0.take(), self.trees))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +315,7 @@ impl ConcatStreamsHelper {
|
|||
if self.streams.len() <= 1 {
|
||||
TokenStream(self.streams.pop())
|
||||
} else {
|
||||
TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams)))
|
||||
TokenStream(Some(BridgeMethods::ts_concat_streams(None, self.streams)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +327,7 @@ impl ConcatStreamsHelper {
|
|||
if base.is_none() && self.streams.len() == 1 {
|
||||
stream.0 = self.streams.pop();
|
||||
} else {
|
||||
stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams));
|
||||
stream.0 = Some(BridgeMethods::ts_concat_streams(base, self.streams));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -377,7 +378,7 @@ impl Extend<TokenStream> for TokenStream {
|
|||
macro_rules! extend_items {
|
||||
($($item:ident)*) => {
|
||||
$(
|
||||
#[stable(feature = "token_stream_extend_tt_items", since = "1.92.0")]
|
||||
#[stable(feature = "token_stream_extend_ts_items", since = "1.92.0")]
|
||||
impl Extend<$item> for TokenStream {
|
||||
fn extend<T: IntoIterator<Item = $item>>(&mut self, iter: T) {
|
||||
self.extend(iter.into_iter().map(TokenTree::$item));
|
||||
|
|
@ -392,7 +393,7 @@ extend_items!(Group Literal Punct Ident);
|
|||
/// Public implementation details for the `TokenStream` type, such as iterators.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub mod token_stream {
|
||||
use crate::{Group, Ident, Literal, Punct, TokenStream, TokenTree, bridge};
|
||||
use crate::{BridgeMethods, Group, Ident, Literal, Punct, TokenStream, TokenTree, bridge};
|
||||
|
||||
/// An iterator over `TokenStream`'s `TokenTree`s.
|
||||
/// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
|
||||
|
|
@ -437,7 +438,9 @@ pub mod token_stream {
|
|||
type IntoIter = IntoIter;
|
||||
|
||||
fn into_iter(self) -> IntoIter {
|
||||
IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter())
|
||||
IntoIter(
|
||||
self.0.map(|v| BridgeMethods::ts_into_trees(v)).unwrap_or_default().into_iter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -509,7 +512,7 @@ impl Span {
|
|||
/// `self` was generated from, if any.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn parent(&self) -> Option<Span> {
|
||||
self.0.parent().map(Span)
|
||||
BridgeMethods::span_parent(self.0).map(Span)
|
||||
}
|
||||
|
||||
/// The span for the origin source code that `self` was generated from. If
|
||||
|
|
@ -517,25 +520,25 @@ impl Span {
|
|||
/// value is the same as `*self`.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn source(&self) -> Span {
|
||||
Span(self.0.source())
|
||||
Span(BridgeMethods::span_source(self.0))
|
||||
}
|
||||
|
||||
/// Returns the span's byte position range in the source file.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn byte_range(&self) -> Range<usize> {
|
||||
self.0.byte_range()
|
||||
BridgeMethods::span_byte_range(self.0)
|
||||
}
|
||||
|
||||
/// Creates an empty span pointing to directly before this span.
|
||||
#[stable(feature = "proc_macro_span_location", since = "1.88.0")]
|
||||
pub fn start(&self) -> Span {
|
||||
Span(self.0.start())
|
||||
Span(BridgeMethods::span_start(self.0))
|
||||
}
|
||||
|
||||
/// Creates an empty span pointing to directly after this span.
|
||||
#[stable(feature = "proc_macro_span_location", since = "1.88.0")]
|
||||
pub fn end(&self) -> Span {
|
||||
Span(self.0.end())
|
||||
Span(BridgeMethods::span_end(self.0))
|
||||
}
|
||||
|
||||
/// The one-indexed line of the source file where the span starts.
|
||||
|
|
@ -543,7 +546,7 @@ impl Span {
|
|||
/// To obtain the line of the span's end, use `span.end().line()`.
|
||||
#[stable(feature = "proc_macro_span_location", since = "1.88.0")]
|
||||
pub fn line(&self) -> usize {
|
||||
self.0.line()
|
||||
BridgeMethods::span_line(self.0)
|
||||
}
|
||||
|
||||
/// The one-indexed column of the source file where the span starts.
|
||||
|
|
@ -551,7 +554,7 @@ impl Span {
|
|||
/// To obtain the column of the span's end, use `span.end().column()`.
|
||||
#[stable(feature = "proc_macro_span_location", since = "1.88.0")]
|
||||
pub fn column(&self) -> usize {
|
||||
self.0.column()
|
||||
BridgeMethods::span_column(self.0)
|
||||
}
|
||||
|
||||
/// The path to the source file in which this span occurs, for display purposes.
|
||||
|
|
@ -560,7 +563,7 @@ impl Span {
|
|||
/// It might be remapped (e.g. `"/src/lib.rs"`) or an artificial path (e.g. `"<command line>"`).
|
||||
#[stable(feature = "proc_macro_span_file", since = "1.88.0")]
|
||||
pub fn file(&self) -> String {
|
||||
self.0.file()
|
||||
BridgeMethods::span_file(self.0)
|
||||
}
|
||||
|
||||
/// The path to the source file in which this span occurs on the local file system.
|
||||
|
|
@ -570,7 +573,7 @@ impl Span {
|
|||
/// This path should not be embedded in the output of the macro; prefer `file()` instead.
|
||||
#[stable(feature = "proc_macro_span_file", since = "1.88.0")]
|
||||
pub fn local_file(&self) -> Option<PathBuf> {
|
||||
self.0.local_file().map(PathBuf::from)
|
||||
BridgeMethods::span_local_file(self.0).map(PathBuf::from)
|
||||
}
|
||||
|
||||
/// Creates a new span encompassing `self` and `other`.
|
||||
|
|
@ -578,14 +581,14 @@ impl Span {
|
|||
/// Returns `None` if `self` and `other` are from different files.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn join(&self, other: Span) -> Option<Span> {
|
||||
self.0.join(other.0).map(Span)
|
||||
BridgeMethods::span_join(self.0, other.0).map(Span)
|
||||
}
|
||||
|
||||
/// Creates a new span with the same line/column information as `self` but
|
||||
/// that resolves symbols as though it were at `other`.
|
||||
#[stable(feature = "proc_macro_span_resolved_at", since = "1.45.0")]
|
||||
pub fn resolved_at(&self, other: Span) -> Span {
|
||||
Span(self.0.resolved_at(other.0))
|
||||
Span(BridgeMethods::span_resolved_at(self.0, other.0))
|
||||
}
|
||||
|
||||
/// Creates a new span with the same name resolution behavior as `self` but
|
||||
|
|
@ -610,21 +613,21 @@ impl Span {
|
|||
/// be used for diagnostics only.
|
||||
#[stable(feature = "proc_macro_source_text", since = "1.66.0")]
|
||||
pub fn source_text(&self) -> Option<String> {
|
||||
self.0.source_text()
|
||||
BridgeMethods::span_source_text(self.0)
|
||||
}
|
||||
|
||||
// Used by the implementation of `Span::quote`
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||
pub fn save_span(&self) -> usize {
|
||||
self.0.save_span()
|
||||
BridgeMethods::span_save_span(self.0)
|
||||
}
|
||||
|
||||
// Used by the implementation of `Span::quote`
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||
pub fn recover_proc_macro_span(id: usize) -> Span {
|
||||
Span(bridge::client::Span::recover_proc_macro_span(id))
|
||||
Span(BridgeMethods::span_recover_proc_macro_span(id))
|
||||
}
|
||||
|
||||
diagnostic_method!(error, Level::Error);
|
||||
|
|
@ -1389,7 +1392,12 @@ impl Literal {
|
|||
// was 'c' or whether it was '\u{63}'.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
|
||||
self.0.span.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span)
|
||||
BridgeMethods::span_subspan(
|
||||
self.0.span,
|
||||
range.start_bound().cloned(),
|
||||
range.end_bound().cloned(),
|
||||
)
|
||||
.map(Span)
|
||||
}
|
||||
|
||||
fn with_symbol_and_suffix<R>(&self, f: impl FnOnce(&str, &str) -> R) -> R {
|
||||
|
|
@ -1559,7 +1567,7 @@ impl FromStr for Literal {
|
|||
type Err = LexError;
|
||||
|
||||
fn from_str(src: &str) -> Result<Self, LexError> {
|
||||
match bridge::client::FreeFunctions::literal_from_str(src) {
|
||||
match BridgeMethods::literal_from_str(src) {
|
||||
Ok(literal) => Ok(Literal(literal)),
|
||||
Err(()) => Err(LexError),
|
||||
}
|
||||
|
|
@ -1601,11 +1609,12 @@ impl fmt::Debug for Literal {
|
|||
)]
|
||||
/// Functionality for adding environment state to the build dependency info.
|
||||
pub mod tracked {
|
||||
|
||||
use std::env::{self, VarError};
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::BridgeMethods;
|
||||
|
||||
/// Retrieve an environment variable and add it to build dependency info.
|
||||
/// The build system executing the compiler will know that the variable was accessed during
|
||||
/// compilation, and will be able to rerun the build when the value of that variable changes.
|
||||
|
|
@ -1614,9 +1623,8 @@ pub mod tracked {
|
|||
#[unstable(feature = "proc_macro_tracked_env", issue = "99515")]
|
||||
pub fn env_var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> Result<String, VarError> {
|
||||
let key: &str = key.as_ref();
|
||||
let value = crate::bridge::client::FreeFunctions::injected_env_var(key)
|
||||
.map_or_else(|| env::var(key), Ok);
|
||||
crate::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok());
|
||||
let value = BridgeMethods::injected_env_var(key).map_or_else(|| env::var(key), Ok);
|
||||
BridgeMethods::track_env_var(key, value.as_deref().ok());
|
||||
value
|
||||
}
|
||||
|
||||
|
|
@ -1626,6 +1634,6 @@ pub mod tracked {
|
|||
#[unstable(feature = "proc_macro_tracked_path", issue = "99515")]
|
||||
pub fn path<P: AsRef<Path>>(path: P) {
|
||||
let path: &str = path.as_ref().to_str().unwrap();
|
||||
crate::bridge::client::FreeFunctions::track_path(path);
|
||||
BridgeMethods::track_path(path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,7 +468,9 @@ extern crate std as realstd;
|
|||
|
||||
// The standard macros that are not built-in to the compiler.
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "std_internals", issue = "none")]
|
||||
pub mod macros;
|
||||
|
||||
// The runtime entry point and a few unstable public functions used by the
|
||||
// compiler
|
||||
|
|
|
|||
|
|
@ -347,35 +347,70 @@ macro_rules! eprintln {
|
|||
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
|
||||
/// [`log`]: https://crates.io/crates/log
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(std_internals)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")]
|
||||
#[stable(feature = "dbg_macro", since = "1.32.0")]
|
||||
macro_rules! dbg {
|
||||
// NOTE: We cannot use `concat!` to make a static string as a format argument
|
||||
// of `eprintln!` because `file!` could contain a `{` or
|
||||
// `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
|
||||
// will be malformed.
|
||||
() => {
|
||||
$crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!())
|
||||
};
|
||||
($val:expr $(,)?) => {
|
||||
($($val:expr),+ $(,)?) => {
|
||||
$crate::macros::dbg_internal!(() () ($($val),+))
|
||||
};
|
||||
}
|
||||
|
||||
/// Internal macro that processes a list of expressions and produces a chain of
|
||||
/// nested `match`es, one for each expression, before finally calling `eprint!`
|
||||
/// with the collected information and returning all the evaluated expressions
|
||||
/// in a tuple.
|
||||
///
|
||||
/// E.g. `dbg_internal!(() () (1, 2))` expands into
|
||||
/// ```rust, ignore
|
||||
/// match 1 {
|
||||
/// tmp_1 => match 2 {
|
||||
/// tmp_2 => {
|
||||
/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);
|
||||
/// (tmp_1, tmp_2)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This is necessary so that `dbg!` outputs don't get torn, see #136703.
|
||||
#[doc(hidden)]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro dbg_internal {
|
||||
(($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{
|
||||
$crate::eprint!(
|
||||
$crate::concat!($($piece),+),
|
||||
$(
|
||||
$crate::stringify!($processed),
|
||||
// The `&T: Debug` check happens here (not in the format literal desugaring)
|
||||
// to avoid format literal related messages and suggestions.
|
||||
&&$bound as &dyn $crate::fmt::Debug
|
||||
),+,
|
||||
// The location returned here is that of the macro invocation, so
|
||||
// it will be the same for all expressions. Thus, label these
|
||||
// arguments so that they can be reused in every piece of the
|
||||
// formatting template.
|
||||
file=$crate::file!(),
|
||||
line=$crate::line!(),
|
||||
column=$crate::column!()
|
||||
);
|
||||
// Comma separate the variables only when necessary so that this will
|
||||
// not yield a tuple for a single expression, but rather just parenthesize
|
||||
// the expression.
|
||||
($($bound),+)
|
||||
}},
|
||||
(($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => {
|
||||
// Use of `match` here is intentional because it affects the lifetimes
|
||||
// of temporaries - https://stackoverflow.com/a/48732525/1063961
|
||||
match $val {
|
||||
tmp => {
|
||||
$crate::eprintln!("[{}:{}:{}] {} = {:#?}",
|
||||
$crate::file!(),
|
||||
$crate::line!(),
|
||||
$crate::column!(),
|
||||
$crate::stringify!($val),
|
||||
// The `&T: Debug` check happens here (not in the format literal desugaring)
|
||||
// to avoid format literal related messages and suggestions.
|
||||
&&tmp as &dyn $crate::fmt::Debug,
|
||||
);
|
||||
tmp
|
||||
}
|
||||
tmp => $crate::macros::dbg_internal!(
|
||||
($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n")
|
||||
($($processed => $bound,)* $val => tmp)
|
||||
($($rest),*)
|
||||
),
|
||||
}
|
||||
};
|
||||
($($val:expr),+ $(,)?) => {
|
||||
($($crate::dbg!($val)),+,)
|
||||
};
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::sys::pal::time::WaitableTimer;
|
|||
use crate::sys::pal::{dur2timeout, to_u16s};
|
||||
use crate::sys::{FromInner, c, stack_overflow};
|
||||
use crate::thread::ThreadInit;
|
||||
use crate::time::Duration;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::{io, ptr};
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
|
|
@ -120,11 +120,28 @@ pub fn sleep(dur: Duration) {
|
|||
timer.set(dur)?;
|
||||
timer.wait()
|
||||
}
|
||||
// Directly forward to `Sleep` for its zero duration behavior when indeed
|
||||
// zero in order to skip the `Instant::now` calls, useless in this case.
|
||||
if dur.is_zero() {
|
||||
unsafe { c::Sleep(0) };
|
||||
// Attempt to use high-precision sleep (Windows 10, version 1803+).
|
||||
// On error fallback to the standard `Sleep` function.
|
||||
// Also preserves the zero duration behavior of `Sleep`.
|
||||
if dur.is_zero() || high_precision_sleep(dur).is_err() {
|
||||
unsafe { c::Sleep(dur2timeout(dur)) }
|
||||
// On error, fallback to the standard `Sleep` function.
|
||||
} else if high_precision_sleep(dur).is_err() {
|
||||
let start = Instant::now();
|
||||
unsafe { c::Sleep(dur2timeout(dur)) };
|
||||
|
||||
// See #149935: `Sleep` under Windows 7 and probably 8 as well seems a
|
||||
// bit buggy for us as it can last less than the requested time while
|
||||
// our API is meant to guarantee that. This is fixed by measuring the
|
||||
// effective time difference and if needed, sleeping a bit more in
|
||||
// order to ensure the duration is always exceeded. A fixed single
|
||||
// millisecond works because `Sleep` operates based on a system-wide
|
||||
// (until Windows 10 2004 that makes it process-local) interrupt timer
|
||||
// that counts in "tick" units of ~15ms by default: a 1ms timeout
|
||||
// therefore passes the next tick boundary.
|
||||
if start.elapsed() < dur {
|
||||
unsafe { c::Sleep(1) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -509,6 +509,12 @@ impl Step for RustAnalyzer {
|
|||
cargo.arg("--workspace");
|
||||
cargo.arg("--exclude=xtask");
|
||||
|
||||
if build_compiler.stage == 0 {
|
||||
// This builds a proc macro against the bootstrap libproc_macro, which is not ABI
|
||||
// compatible with the ABI proc-macro-srv expects to load.
|
||||
cargo.arg("--exclude=proc-macro-srv");
|
||||
}
|
||||
|
||||
let mut skip_tests = vec![];
|
||||
|
||||
// NOTE: the following test skips is a bit cheeky in that it assumes there are no
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use clippy_utils::macros::{MacroCall, macro_backtrace};
|
|||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
|
||||
use rustc_hir::{Arm, Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, SyntaxContext, sym};
|
||||
|
|
@ -90,33 +90,27 @@ impl LateLintPass<'_> for DbgMacro {
|
|||
(macro_call.span, String::from("()"))
|
||||
}
|
||||
},
|
||||
// dbg!(1)
|
||||
ExprKind::Match(val, ..) => (
|
||||
macro_call.span,
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string(),
|
||||
),
|
||||
// dbg!(2, 3)
|
||||
ExprKind::Tup(
|
||||
[
|
||||
Expr {
|
||||
kind: ExprKind::Match(first, ..),
|
||||
..
|
||||
},
|
||||
..,
|
||||
Expr {
|
||||
kind: ExprKind::Match(last, ..),
|
||||
..
|
||||
},
|
||||
],
|
||||
) => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
"..",
|
||||
&mut applicability,
|
||||
);
|
||||
(macro_call.span, format!("({snippet})"))
|
||||
ExprKind::Match(first, arms, _) => {
|
||||
let vals = collect_vals(first, arms);
|
||||
let suggestion = match vals.as_slice() {
|
||||
// dbg!(1) => 1
|
||||
&[val] => {
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string()
|
||||
}
|
||||
// dbg!(2, 3) => (2, 3)
|
||||
&[first, .., last] => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
"..",
|
||||
&mut applicability,
|
||||
);
|
||||
format!("({snippet})")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
(macro_call.span, suggestion)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
|
@ -169,3 +163,33 @@ fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx
|
|||
fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<MacroCall> {
|
||||
macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id))
|
||||
}
|
||||
|
||||
/// Extracts all value expressions from the `match`-tree generated by `dbg!`.
|
||||
///
|
||||
/// E.g. from
|
||||
/// ```rust, ignore
|
||||
/// match 1 {
|
||||
/// tmp_1 => match 2 {
|
||||
/// tmp_2 => {
|
||||
/// /* printing */
|
||||
/// (tmp_1, tmp_2)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// this extracts `1` and `2`.
|
||||
fn collect_vals<'hir>(first: &'hir Expr<'hir>, mut arms: &'hir [Arm<'hir>]) -> Vec<&'hir Expr<'hir>> {
|
||||
let mut vals = vec![first];
|
||||
loop {
|
||||
let [arm] = arms else { unreachable!("dbg! macro expansion only has single-arm matches") };
|
||||
|
||||
match is_async_move_desugar(arm.body).unwrap_or(arm.body).peel_drop_temps().kind {
|
||||
ExprKind::Block(..) => return vals,
|
||||
ExprKind::Match(val, a, _) => {
|
||||
vals.push(val);
|
||||
arms = a;
|
||||
}
|
||||
_ => unreachable!("dbg! macro expansion only results in block or match expressions"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ help: ALLOC was deallocated here:
|
|||
|
|
||||
LL | };
|
||||
| ^
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LL | dbg!(x.0);
|
|||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
|
||||
ALLOC (stack variable, size: 132, align: 4) {
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ pub enum FnAbi {
|
|||
Win64,
|
||||
Win64Unwind,
|
||||
X86Interrupt,
|
||||
RustPreserveNone,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
|
|
@ -271,6 +272,7 @@ impl FnAbi {
|
|||
s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS,
|
||||
s if *s == sym::rust_dash_call => FnAbi::RustCall,
|
||||
s if *s == sym::rust_dash_cold => FnAbi::RustCold,
|
||||
s if *s == sym::rust_dash_preserve_dash_none => FnAbi::RustPreserveNone,
|
||||
s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic,
|
||||
s if *s == sym::Rust => FnAbi::Rust,
|
||||
s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
|
||||
|
|
@ -314,6 +316,7 @@ impl FnAbi {
|
|||
FnAbi::Rust => "Rust",
|
||||
FnAbi::RustCall => "rust-call",
|
||||
FnAbi::RustCold => "rust-cold",
|
||||
FnAbi::RustPreserveNone => "rust-preserve-none",
|
||||
FnAbi::RustIntrinsic => "rust-intrinsic",
|
||||
FnAbi::Stdcall => "stdcall",
|
||||
FnAbi::StdcallUnwind => "stdcall-unwind",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ define_symbols! {
|
|||
vectorcall_dash_unwind = "vectorcall-unwind",
|
||||
win64_dash_unwind = "win64-unwind",
|
||||
x86_dash_interrupt = "x86-interrupt",
|
||||
rust_dash_preserve_dash_none = "preserve-none",
|
||||
|
||||
@PLAIN:
|
||||
__ra_fixup,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! `proc_macro::bridge` newtypes.
|
||||
|
||||
use proc_macro::bridge as pm_bridge;
|
||||
use rustc_proc_macro::bridge as pm_bridge;
|
||||
|
||||
pub use pm_bridge::{DelimSpan, Diagnostic, ExpnGlobals, LitKind};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
mod proc_macros;
|
||||
mod version;
|
||||
|
||||
use proc_macro::bridge;
|
||||
use rustc_proc_macro::bridge;
|
||||
use std::{fmt, fs, io, time::SystemTime};
|
||||
use temp_dir::TempDir;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Proc macro ABI
|
||||
use crate::{ProcMacroClientHandle, ProcMacroKind, ProcMacroSrvSpan, token_stream::TokenStream};
|
||||
use proc_macro::bridge;
|
||||
use rustc_proc_macro::bridge;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct ProcMacros([bridge::client::ProcMacro]);
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@
|
|||
)]
|
||||
#![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)]
|
||||
|
||||
extern crate proc_macro;
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_driver as _;
|
||||
extern crate rustc_proc_macro;
|
||||
|
||||
#[cfg(not(feature = "in-rust-tree"))]
|
||||
extern crate ra_ap_rustc_lexer as rustc_lexer;
|
||||
|
|
@ -52,7 +52,7 @@ use temp_dir::TempDir;
|
|||
|
||||
pub use crate::server_impl::token_id::SpanId;
|
||||
|
||||
pub use proc_macro::Delimiter;
|
||||
pub use rustc_proc_macro::Delimiter;
|
||||
pub use span;
|
||||
|
||||
pub use crate::bridge::*;
|
||||
|
|
@ -181,7 +181,9 @@ impl ProcMacroSrv<'_> {
|
|||
}
|
||||
|
||||
pub trait ProcMacroSrvSpan: Copy + Send + Sync {
|
||||
type Server<'a>: proc_macro::bridge::server::Server<TokenStream = crate::token_stream::TokenStream<Self>>;
|
||||
type Server<'a>: rustc_proc_macro::bridge::server::Server<
|
||||
TokenStream = crate::token_stream::TokenStream<Self>,
|
||||
>;
|
||||
fn make_server<'a>(
|
||||
call_site: Self,
|
||||
def_site: Self,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
};
|
||||
|
||||
use intern::Symbol;
|
||||
use proc_macro::bridge::server;
|
||||
use rustc_proc_macro::bridge::server;
|
||||
use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TextRange, TextSize};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -19,8 +19,6 @@ use crate::{
|
|||
server_impl::literal_from_str,
|
||||
};
|
||||
|
||||
pub struct FreeFunctions;
|
||||
|
||||
pub struct RaSpanServer<'a> {
|
||||
// FIXME: Report this back to the caller to track as dependencies
|
||||
pub tracked_env_vars: HashMap<Box<str>, Option<Box<str>>>,
|
||||
|
|
@ -33,13 +31,28 @@ pub struct RaSpanServer<'a> {
|
|||
}
|
||||
|
||||
impl server::Types for RaSpanServer<'_> {
|
||||
type FreeFunctions = FreeFunctions;
|
||||
type TokenStream = crate::token_stream::TokenStream<Span>;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::FreeFunctions for RaSpanServer<'_> {
|
||||
impl server::Server for RaSpanServer<'_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
call_site: self.call_site,
|
||||
mixed_site: self.mixed_site,
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_symbol(ident: &str) -> Self::Symbol {
|
||||
Symbol::intern(ident)
|
||||
}
|
||||
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
|
||||
fn injected_env_var(&mut self, _: &str) -> Option<std::string::String> {
|
||||
None
|
||||
}
|
||||
|
|
@ -58,13 +71,19 @@ impl server::FreeFunctions for RaSpanServer<'_> {
|
|||
fn emit_diagnostic(&mut self, _: Diagnostic<Self::Span>) {
|
||||
// FIXME handle diagnostic
|
||||
}
|
||||
}
|
||||
|
||||
impl server::TokenStream for RaSpanServer<'_> {
|
||||
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
fn ts_drop(&mut self, stream: Self::TokenStream) {
|
||||
drop(stream);
|
||||
}
|
||||
|
||||
fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream {
|
||||
stream.clone()
|
||||
}
|
||||
|
||||
fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
stream.is_empty()
|
||||
}
|
||||
fn from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
fn ts_from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
Self::TokenStream::from_str(src, self.call_site).unwrap_or_else(|e| {
|
||||
Self::TokenStream::from_str(
|
||||
&format!("compile_error!(\"failed to parse str to token stream: {e}\")"),
|
||||
|
|
@ -73,15 +92,15 @@ impl server::TokenStream for RaSpanServer<'_> {
|
|||
.unwrap()
|
||||
})
|
||||
}
|
||||
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
stream.to_string()
|
||||
}
|
||||
|
||||
fn from_token_tree(&mut self, tree: TokenTree<Self::Span>) -> Self::TokenStream {
|
||||
fn ts_from_token_tree(&mut self, tree: TokenTree<Self::Span>) -> Self::TokenStream {
|
||||
Self::TokenStream::new(vec![tree])
|
||||
}
|
||||
|
||||
fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
fn ts_expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
// FIXME: requires db, more importantly this requires name resolution so we would need to
|
||||
// eagerly expand this proc-macro, but we can't know that this proc-macro is eager until we
|
||||
// expand it ...
|
||||
|
|
@ -90,7 +109,7 @@ impl server::TokenStream for RaSpanServer<'_> {
|
|||
Ok(self_.clone())
|
||||
}
|
||||
|
||||
fn concat_trees(
|
||||
fn ts_concat_trees(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
trees: Vec<TokenTree<Self::Span>>,
|
||||
|
|
@ -106,7 +125,7 @@ impl server::TokenStream for RaSpanServer<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn concat_streams(
|
||||
fn ts_concat_streams(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
streams: Vec<Self::TokenStream>,
|
||||
|
|
@ -118,28 +137,26 @@ impl server::TokenStream for RaSpanServer<'_> {
|
|||
stream
|
||||
}
|
||||
|
||||
fn into_trees(&mut self, stream: Self::TokenStream) -> Vec<TokenTree<Self::Span>> {
|
||||
fn ts_into_trees(&mut self, stream: Self::TokenStream) -> Vec<TokenTree<Self::Span>> {
|
||||
(*stream.0).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Span for RaSpanServer<'_> {
|
||||
fn debug(&mut self, span: Self::Span) -> String {
|
||||
fn span_debug(&mut self, span: Self::Span) -> String {
|
||||
format!("{:?}", span)
|
||||
}
|
||||
fn file(&mut self, span: Self::Span) -> String {
|
||||
fn span_file(&mut self, span: Self::Span) -> String {
|
||||
self.callback.as_mut().map(|cb| cb.file(span.anchor.file_id.file_id())).unwrap_or_default()
|
||||
}
|
||||
fn local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
fn span_local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id()))
|
||||
}
|
||||
fn save_span(&mut self, _span: Self::Span) -> usize {
|
||||
fn span_save_span(&mut self, _span: Self::Span) -> usize {
|
||||
// FIXME, quote is incompatible with third-party tools
|
||||
// This is called by the quote proc-macro which is expanded when the proc-macro is compiled
|
||||
// As such, r-a will never observe this
|
||||
0
|
||||
}
|
||||
fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
|
||||
fn span_recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
|
||||
// FIXME, quote is incompatible with third-party tools
|
||||
// This is called by the expansion of quote!, r-a will observe this, but we don't have
|
||||
// access to the spans that were encoded
|
||||
|
|
@ -149,23 +166,23 @@ impl server::Span for RaSpanServer<'_> {
|
|||
///
|
||||
/// See PR:
|
||||
/// https://github.com/rust-lang/rust/pull/55780
|
||||
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
fn span_source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.callback.as_mut()?.source_text(span)
|
||||
}
|
||||
|
||||
fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
|
||||
fn span_parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
|
||||
// FIXME requires db, looks up the parent call site
|
||||
None
|
||||
}
|
||||
fn source(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_source(&mut self, span: Self::Span) -> Self::Span {
|
||||
// FIXME requires db, returns the top level call site
|
||||
span
|
||||
}
|
||||
fn byte_range(&mut self, span: Self::Span) -> Range<usize> {
|
||||
fn span_byte_range(&mut self, span: Self::Span) -> Range<usize> {
|
||||
// FIXME requires db to resolve the ast id, THIS IS NOT INCREMENTAL
|
||||
Range { start: span.range.start().into(), end: span.range.end().into() }
|
||||
}
|
||||
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
|
||||
fn span_join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
|
||||
// We can't modify the span range for fixup spans, those are meaningful to fixup, so just
|
||||
// prefer the non-fixup span.
|
||||
if first.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
|
||||
|
|
@ -193,7 +210,7 @@ impl server::Span for RaSpanServer<'_> {
|
|||
ctx: second.ctx,
|
||||
})
|
||||
}
|
||||
fn subspan(
|
||||
fn span_subspan(
|
||||
&mut self,
|
||||
span: Self::Span,
|
||||
start: Bound<usize>,
|
||||
|
|
@ -237,11 +254,11 @@ impl server::Span for RaSpanServer<'_> {
|
|||
})
|
||||
}
|
||||
|
||||
fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||
fn span_resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||
Span { ctx: at.ctx, ..span }
|
||||
}
|
||||
|
||||
fn end(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_end(&mut self, span: Self::Span) -> Self::Span {
|
||||
// We can't modify the span range for fixup spans, those are meaningful to fixup.
|
||||
if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
|
||||
return span;
|
||||
|
|
@ -249,7 +266,7 @@ impl server::Span for RaSpanServer<'_> {
|
|||
Span { range: TextRange::empty(span.range.end()), ..span }
|
||||
}
|
||||
|
||||
fn start(&mut self, span: Self::Span) -> Self::Span {
|
||||
fn span_start(&mut self, span: Self::Span) -> Self::Span {
|
||||
// We can't modify the span range for fixup spans, those are meaningful to fixup.
|
||||
if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
|
||||
return span;
|
||||
|
|
@ -257,38 +274,18 @@ impl server::Span for RaSpanServer<'_> {
|
|||
Span { range: TextRange::empty(span.range.start()), ..span }
|
||||
}
|
||||
|
||||
fn line(&mut self, _span: Self::Span) -> usize {
|
||||
fn span_line(&mut self, _span: Self::Span) -> usize {
|
||||
// FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
|
||||
1
|
||||
}
|
||||
|
||||
fn column(&mut self, _span: Self::Span) -> usize {
|
||||
fn span_column(&mut self, _span: Self::Span) -> usize {
|
||||
// FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Symbol for RaSpanServer<'_> {
|
||||
fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
// FIXME: nfc-normalize and validate idents
|
||||
Ok(<Self as server::Server>::intern_symbol(string))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Server for RaSpanServer<'_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
call_site: self.call_site,
|
||||
mixed_site: self.mixed_site,
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_symbol(ident: &str) -> Self::Symbol {
|
||||
Symbol::intern(ident)
|
||||
}
|
||||
|
||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use intern::Symbol;
|
||||
use proc_macro::bridge::server;
|
||||
use rustc_proc_macro::bridge::server;
|
||||
|
||||
use crate::{
|
||||
ProcMacroClientHandle,
|
||||
|
|
@ -25,8 +25,6 @@ impl std::fmt::Debug for SpanId {
|
|||
|
||||
type Span = SpanId;
|
||||
|
||||
pub struct FreeFunctions;
|
||||
|
||||
pub struct SpanIdServer<'a> {
|
||||
// FIXME: Report this back to the caller to track as dependencies
|
||||
pub tracked_env_vars: HashMap<Box<str>, Option<Box<str>>>,
|
||||
|
|
@ -39,161 +37,11 @@ pub struct SpanIdServer<'a> {
|
|||
}
|
||||
|
||||
impl server::Types for SpanIdServer<'_> {
|
||||
type FreeFunctions = FreeFunctions;
|
||||
type TokenStream = crate::token_stream::TokenStream<Span>;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::FreeFunctions for SpanIdServer<'_> {
|
||||
fn injected_env_var(&mut self, _: &str) -> Option<std::string::String> {
|
||||
None
|
||||
}
|
||||
fn track_env_var(&mut self, var: &str, value: Option<&str>) {
|
||||
self.tracked_env_vars.insert(var.into(), value.map(Into::into));
|
||||
}
|
||||
fn track_path(&mut self, path: &str) {
|
||||
self.tracked_paths.insert(path.into());
|
||||
}
|
||||
|
||||
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span>, ()> {
|
||||
literal_from_str(s, self.call_site)
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, _: Diagnostic<Self::Span>) {}
|
||||
}
|
||||
|
||||
impl server::TokenStream for SpanIdServer<'_> {
|
||||
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
stream.is_empty()
|
||||
}
|
||||
fn from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
Self::TokenStream::from_str(src, self.call_site).unwrap_or_else(|e| {
|
||||
Self::TokenStream::from_str(
|
||||
&format!("compile_error!(\"failed to parse str to token stream: {e}\")"),
|
||||
self.call_site,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
stream.to_string()
|
||||
}
|
||||
fn from_token_tree(&mut self, tree: TokenTree<Self::Span>) -> Self::TokenStream {
|
||||
Self::TokenStream::new(vec![tree])
|
||||
}
|
||||
|
||||
fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
Ok(self_.clone())
|
||||
}
|
||||
|
||||
fn concat_trees(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
trees: Vec<TokenTree<Self::Span>>,
|
||||
) -> Self::TokenStream {
|
||||
match base {
|
||||
Some(mut base) => {
|
||||
for tt in trees {
|
||||
base.push_tree(tt);
|
||||
}
|
||||
base
|
||||
}
|
||||
None => Self::TokenStream::new(trees),
|
||||
}
|
||||
}
|
||||
|
||||
fn concat_streams(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
streams: Vec<Self::TokenStream>,
|
||||
) -> Self::TokenStream {
|
||||
let mut stream = base.unwrap_or_default();
|
||||
for s in streams {
|
||||
stream.push_stream(s);
|
||||
}
|
||||
stream
|
||||
}
|
||||
|
||||
fn into_trees(&mut self, stream: Self::TokenStream) -> Vec<TokenTree<Self::Span>> {
|
||||
(*stream.0).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Span for SpanIdServer<'_> {
|
||||
fn debug(&mut self, span: Self::Span) -> String {
|
||||
format!("{:?}", span.0)
|
||||
}
|
||||
fn file(&mut self, _span: Self::Span) -> String {
|
||||
String::new()
|
||||
}
|
||||
fn local_file(&mut self, _span: Self::Span) -> Option<String> {
|
||||
None
|
||||
}
|
||||
fn save_span(&mut self, _span: Self::Span) -> usize {
|
||||
0
|
||||
}
|
||||
fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
/// Recent feature, not yet in the proc_macro
|
||||
///
|
||||
/// See PR:
|
||||
/// https://github.com/rust-lang/rust/pull/55780
|
||||
fn source_text(&mut self, _span: Self::Span) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
|
||||
None
|
||||
}
|
||||
fn source(&mut self, span: Self::Span) -> Self::Span {
|
||||
span
|
||||
}
|
||||
fn byte_range(&mut self, _span: Self::Span) -> Range<usize> {
|
||||
Range { start: 0, end: 0 }
|
||||
}
|
||||
fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
|
||||
// Just return the first span again, because some macros will unwrap the result.
|
||||
Some(first)
|
||||
}
|
||||
fn subspan(
|
||||
&mut self,
|
||||
span: Self::Span,
|
||||
_start: Bound<usize>,
|
||||
_end: Bound<usize>,
|
||||
) -> Option<Self::Span> {
|
||||
// Just return the span again, because some macros will unwrap the result.
|
||||
Some(span)
|
||||
}
|
||||
fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
|
||||
fn end(&mut self, _self_: Self::Span) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
|
||||
fn start(&mut self, _self_: Self::Span) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
|
||||
fn line(&mut self, _span: Self::Span) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn column(&mut self, _span: Self::Span) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Symbol for SpanIdServer<'_> {
|
||||
fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
// FIXME: nfc-normalize and validate idents
|
||||
Ok(<Self as server::Server>::intern_symbol(string))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Server for SpanIdServer<'_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
|
|
@ -210,4 +58,153 @@ impl server::Server for SpanIdServer<'_> {
|
|||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||
f(symbol.as_str())
|
||||
}
|
||||
|
||||
fn injected_env_var(&mut self, _: &str) -> Option<std::string::String> {
|
||||
None
|
||||
}
|
||||
fn track_env_var(&mut self, var: &str, value: Option<&str>) {
|
||||
self.tracked_env_vars.insert(var.into(), value.map(Into::into));
|
||||
}
|
||||
fn track_path(&mut self, path: &str) {
|
||||
self.tracked_paths.insert(path.into());
|
||||
}
|
||||
|
||||
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span>, ()> {
|
||||
literal_from_str(s, self.call_site)
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, _: Diagnostic<Self::Span>) {}
|
||||
|
||||
fn ts_drop(&mut self, stream: Self::TokenStream) {
|
||||
drop(stream);
|
||||
}
|
||||
|
||||
fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream {
|
||||
stream.clone()
|
||||
}
|
||||
|
||||
fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
stream.is_empty()
|
||||
}
|
||||
fn ts_from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
Self::TokenStream::from_str(src, self.call_site).unwrap_or_else(|e| {
|
||||
Self::TokenStream::from_str(
|
||||
&format!("compile_error!(\"failed to parse str to token stream: {e}\")"),
|
||||
self.call_site,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
stream.to_string()
|
||||
}
|
||||
fn ts_from_token_tree(&mut self, tree: TokenTree<Self::Span>) -> Self::TokenStream {
|
||||
Self::TokenStream::new(vec![tree])
|
||||
}
|
||||
|
||||
fn ts_expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
Ok(self_.clone())
|
||||
}
|
||||
|
||||
fn ts_concat_trees(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
trees: Vec<TokenTree<Self::Span>>,
|
||||
) -> Self::TokenStream {
|
||||
match base {
|
||||
Some(mut base) => {
|
||||
for tt in trees {
|
||||
base.push_tree(tt);
|
||||
}
|
||||
base
|
||||
}
|
||||
None => Self::TokenStream::new(trees),
|
||||
}
|
||||
}
|
||||
|
||||
fn ts_concat_streams(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
streams: Vec<Self::TokenStream>,
|
||||
) -> Self::TokenStream {
|
||||
let mut stream = base.unwrap_or_default();
|
||||
for s in streams {
|
||||
stream.push_stream(s);
|
||||
}
|
||||
stream
|
||||
}
|
||||
|
||||
fn ts_into_trees(&mut self, stream: Self::TokenStream) -> Vec<TokenTree<Self::Span>> {
|
||||
(*stream.0).clone()
|
||||
}
|
||||
|
||||
fn span_debug(&mut self, span: Self::Span) -> String {
|
||||
format!("{:?}", span.0)
|
||||
}
|
||||
fn span_file(&mut self, _span: Self::Span) -> String {
|
||||
String::new()
|
||||
}
|
||||
fn span_local_file(&mut self, _span: Self::Span) -> Option<String> {
|
||||
None
|
||||
}
|
||||
fn span_save_span(&mut self, _span: Self::Span) -> usize {
|
||||
0
|
||||
}
|
||||
fn span_recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
/// Recent feature, not yet in the proc_macro
|
||||
///
|
||||
/// See PR:
|
||||
/// https://github.com/rust-lang/rust/pull/55780
|
||||
fn span_source_text(&mut self, _span: Self::Span) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn span_parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
|
||||
None
|
||||
}
|
||||
fn span_source(&mut self, span: Self::Span) -> Self::Span {
|
||||
span
|
||||
}
|
||||
fn span_byte_range(&mut self, _span: Self::Span) -> Range<usize> {
|
||||
Range { start: 0, end: 0 }
|
||||
}
|
||||
fn span_join(&mut self, first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
|
||||
// Just return the first span again, because some macros will unwrap the result.
|
||||
Some(first)
|
||||
}
|
||||
fn span_subspan(
|
||||
&mut self,
|
||||
span: Self::Span,
|
||||
_start: Bound<usize>,
|
||||
_end: Bound<usize>,
|
||||
) -> Option<Self::Span> {
|
||||
// Just return the span again, because some macros will unwrap the result.
|
||||
Some(span)
|
||||
}
|
||||
fn span_resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
|
||||
fn span_end(&mut self, _self_: Self::Span) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
|
||||
fn span_start(&mut self, _self_: Self::Span) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
|
||||
fn span_line(&mut self, _span: Self::Span) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn span_column(&mut self, _span: Self::Span) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
|
||||
// FIXME: nfc-normalize and validate idents
|
||||
Ok(<Self as server::Server>::intern_symbol(string))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use core::fmt;
|
|||
use std::{mem, sync::Arc};
|
||||
|
||||
use intern::Symbol;
|
||||
use proc_macro::Delimiter;
|
||||
use rustc_lexer::{DocStyle, LiteralKind};
|
||||
use rustc_proc_macro::Delimiter;
|
||||
|
||||
use crate::bridge::{DelimSpan, Group, Ident, LitKind, Literal, Punct, TokenTree};
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ impl<S> TokenStream<S> {
|
|||
S: SpanLike + Copy,
|
||||
{
|
||||
let mut groups = Vec::new();
|
||||
groups.push((proc_macro::Delimiter::None, 0..0, vec![]));
|
||||
groups.push((rustc_proc_macro::Delimiter::None, 0..0, vec![]));
|
||||
let mut offset = 0;
|
||||
let mut tokens = rustc_lexer::tokenize(s, rustc_lexer::FrontmatterAllowed::No).peekable();
|
||||
while let Some(token) = tokens.next() {
|
||||
|
|
@ -102,7 +102,7 @@ impl<S> TokenStream<S> {
|
|||
};
|
||||
match token.kind {
|
||||
rustc_lexer::TokenKind::OpenParen => {
|
||||
groups.push((proc_macro::Delimiter::Parenthesis, range, vec![]))
|
||||
groups.push((rustc_proc_macro::Delimiter::Parenthesis, range, vec![]))
|
||||
}
|
||||
rustc_lexer::TokenKind::CloseParen if *open_delim != Delimiter::Parenthesis => {
|
||||
return if *open_delim == Delimiter::None {
|
||||
|
|
@ -130,7 +130,7 @@ impl<S> TokenStream<S> {
|
|||
);
|
||||
}
|
||||
rustc_lexer::TokenKind::OpenBrace => {
|
||||
groups.push((proc_macro::Delimiter::Brace, range, vec![]))
|
||||
groups.push((rustc_proc_macro::Delimiter::Brace, range, vec![]))
|
||||
}
|
||||
rustc_lexer::TokenKind::CloseBrace if *open_delim != Delimiter::Brace => {
|
||||
return if *open_delim == Delimiter::None {
|
||||
|
|
@ -158,7 +158,7 @@ impl<S> TokenStream<S> {
|
|||
);
|
||||
}
|
||||
rustc_lexer::TokenKind::OpenBracket => {
|
||||
groups.push((proc_macro::Delimiter::Bracket, range, vec![]))
|
||||
groups.push((rustc_proc_macro::Delimiter::Bracket, range, vec![]))
|
||||
}
|
||||
rustc_lexer::TokenKind::CloseBracket if *open_delim != Delimiter::Bracket => {
|
||||
return if *open_delim == Delimiter::None {
|
||||
|
|
@ -460,10 +460,10 @@ fn display_token_tree<S>(
|
|||
f,
|
||||
"{}",
|
||||
match delimiter {
|
||||
proc_macro::Delimiter::Parenthesis => "(",
|
||||
proc_macro::Delimiter::Brace => "{",
|
||||
proc_macro::Delimiter::Bracket => "[",
|
||||
proc_macro::Delimiter::None => "",
|
||||
rustc_proc_macro::Delimiter::Parenthesis => "(",
|
||||
rustc_proc_macro::Delimiter::Brace => "{",
|
||||
rustc_proc_macro::Delimiter::Bracket => "[",
|
||||
rustc_proc_macro::Delimiter::None => "",
|
||||
}
|
||||
)?;
|
||||
if let Some(stream) = stream {
|
||||
|
|
@ -473,10 +473,10 @@ fn display_token_tree<S>(
|
|||
f,
|
||||
"{}",
|
||||
match delimiter {
|
||||
proc_macro::Delimiter::Parenthesis => ")",
|
||||
proc_macro::Delimiter::Brace => "}",
|
||||
proc_macro::Delimiter::Bracket => "]",
|
||||
proc_macro::Delimiter::None => "",
|
||||
rustc_proc_macro::Delimiter::Parenthesis => ")",
|
||||
rustc_proc_macro::Delimiter::Brace => "}",
|
||||
rustc_proc_macro::Delimiter::Bracket => "]",
|
||||
rustc_proc_macro::Delimiter::None => "",
|
||||
}
|
||||
)?;
|
||||
}
|
||||
|
|
@ -587,16 +587,16 @@ fn debug_token_tree<S: fmt::Debug>(
|
|||
f,
|
||||
"GROUP {}{} {:#?} {:#?} {:#?}",
|
||||
match delimiter {
|
||||
proc_macro::Delimiter::Parenthesis => "(",
|
||||
proc_macro::Delimiter::Brace => "{",
|
||||
proc_macro::Delimiter::Bracket => "[",
|
||||
proc_macro::Delimiter::None => "$",
|
||||
rustc_proc_macro::Delimiter::Parenthesis => "(",
|
||||
rustc_proc_macro::Delimiter::Brace => "{",
|
||||
rustc_proc_macro::Delimiter::Bracket => "[",
|
||||
rustc_proc_macro::Delimiter::None => "$",
|
||||
},
|
||||
match delimiter {
|
||||
proc_macro::Delimiter::Parenthesis => ")",
|
||||
proc_macro::Delimiter::Brace => "}",
|
||||
proc_macro::Delimiter::Bracket => "]",
|
||||
proc_macro::Delimiter::None => "$",
|
||||
rustc_proc_macro::Delimiter::Parenthesis => ")",
|
||||
rustc_proc_macro::Delimiter::Brace => "}",
|
||||
rustc_proc_macro::Delimiter::Bracket => "]",
|
||||
rustc_proc_macro::Delimiter::None => "$",
|
||||
},
|
||||
span.open,
|
||||
span.close,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ ignore-loongarch64 (handles dso_local differently)
|
||||
//@ ignore-powerpc64 (handles dso_local differently)
|
||||
//@ ignore-apple (handles dso_local differently)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
//! This test checks that removing trailing zeroes from a `NonZero`,
|
||||
//! then creating a new `NonZero` from the result does not panic.
|
||||
|
||||
//@ min-llvm-version: 21
|
||||
//@ compile-flags: -O -Zmerge-functions=disabled
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::num::NonZero;
|
||||
|
||||
// CHECK-LABEL: @remove_trailing_zeros
|
||||
#[no_mangle]
|
||||
pub fn remove_trailing_zeros(x: NonZero<u8>) -> NonZero<u8> {
|
||||
// CHECK: %[[TRAILING:[a-z0-9_-]+]] = {{.*}} call {{.*}} i8 @llvm.cttz.i8(i8 %x, i1 true)
|
||||
// CHECK-NEXT: %[[RET:[a-z0-9_-]+]] = lshr exact i8 %x, %[[TRAILING]]
|
||||
// CHECK-NEXT: ret i8 %[[RET]]
|
||||
NonZero::new(x.get() >> x.trailing_zeros()).unwrap()
|
||||
}
|
||||
33
tests/codegen-llvm/lib-optimizations/append-elements.rs
Normal file
33
tests/codegen-llvm/lib-optimizations/append-elements.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//@ compile-flags: -O -Zmerge-functions=disabled
|
||||
//@ needs-deterministic-layouts
|
||||
//@ min-llvm-version: 21
|
||||
#![crate_type = "lib"]
|
||||
|
||||
//! Check that a temporary intermediate allocations can eliminated and replaced
|
||||
//! with memcpy forwarding.
|
||||
//! This requires Vec code to be structured in a way that avoids phi nodes from the
|
||||
//! zero-capacity length flowing into the memcpy arguments.
|
||||
|
||||
// CHECK-LABEL: @vec_append_with_temp_alloc
|
||||
// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]]
|
||||
#[no_mangle]
|
||||
pub fn vec_append_with_temp_alloc(dst: &mut Vec<u8>, src: &[u8]) {
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]]
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
let temp = src.to_vec();
|
||||
dst.extend(&temp);
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @string_append_with_temp_alloc
|
||||
// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]]
|
||||
#[no_mangle]
|
||||
pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) {
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]]
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
let temp = src.to_string();
|
||||
dst.push_str(&temp);
|
||||
// CHECK: ret
|
||||
}
|
||||
|
|
@ -23,9 +23,7 @@ pub fn do_call() {
|
|||
|
||||
unsafe {
|
||||
// Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them
|
||||
// CHECK: store float 4.000000e+00, ptr %{{.}}, align 4
|
||||
// CHECK: load float, ptr %{{.}}, align 4
|
||||
// CHECK: call float @llvm.sqrt.f32(float %{{.}}
|
||||
// CHECK: call float @llvm.sqrt.f32(float 4.000000e+00)
|
||||
sqrt(4.0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
47
tests/codegen-llvm/loongarch/direct-access-external-data.rs
Normal file
47
tests/codegen-llvm/loongarch/direct-access-external-data.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
//@ only-loongarch64
|
||||
|
||||
//@ revisions: DEFAULT PIE DIRECT INDIRECT
|
||||
//@ [DEFAULT] compile-flags: -C relocation-model=static
|
||||
//@ [PIE] compile-flags: -C relocation-model=pie
|
||||
//@ [DIRECT] compile-flags: -C relocation-model=pie -Z direct-access-external-data=yes
|
||||
//@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(linkage)]
|
||||
|
||||
unsafe extern "C" {
|
||||
// CHECK: @VAR = external
|
||||
// DEFAULT-NOT: dso_local
|
||||
// PIE-NOT: dso_local
|
||||
// DIRECT-SAME: dso_local
|
||||
// INDIRECT-NOT: dso_local
|
||||
// CHECK-SAME: global i32
|
||||
safe static VAR: i32;
|
||||
|
||||
// When "linkage" is used, we generate an indirection global.
|
||||
// Check dso_local is still applied to the actual global.
|
||||
// CHECK: @EXTERNAL = external
|
||||
// DEFAULT-NOT: dso_local
|
||||
// PIE-NOT: dso_local
|
||||
// DIRECT-SAME: dso_local
|
||||
// INDIRECT-NOT: dso_local
|
||||
// CHECK-SAME: global i8
|
||||
#[linkage = "external"]
|
||||
safe static EXTERNAL: *const u32;
|
||||
|
||||
// CHECK: @WEAK = extern_weak
|
||||
// DEFAULT-NOT: dso_local
|
||||
// PIE-NOT: dso_local
|
||||
// DIRECT-SAME: dso_local
|
||||
// INDIRECT-NOT: dso_local
|
||||
// CHECK-SAME: global i8
|
||||
#[linkage = "extern_weak"]
|
||||
safe static WEAK: *const u32;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn refer() {
|
||||
core::hint::black_box(VAR);
|
||||
core::hint::black_box(EXTERNAL);
|
||||
core::hint::black_box(WEAK);
|
||||
}
|
||||
33
tests/codegen-llvm/preserve-none.rs
Normal file
33
tests/codegen-llvm/preserve-none.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//@ add-minicore
|
||||
//@ revisions: X86 AARCH64 UNSUPPORTED
|
||||
//@ [X86] compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
|
||||
//@ [X86] needs-llvm-components: x86
|
||||
//@ [AARCH64] compile-flags: -C no-prepopulate-passes --target=aarch64-unknown-linux-gnu
|
||||
//@ [AARCH64] needs-llvm-components: aarch64
|
||||
//@ [UNSUPPORTED] compile-flags: -C no-prepopulate-passes --target=i686-unknown-linux-gnu
|
||||
//@ [UNSUPPORTED] needs-llvm-components: x86
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(rust_preserve_none_cc)]
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
|
||||
// X86: define{{( dso_local)?}} preserve_nonecc void @peach(i16
|
||||
// AARCH64: define{{( dso_local)?}} preserve_nonecc void @peach(i16
|
||||
// UNSUPPORTED: define{{( dso_local)?}} void @peach(i16
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
pub extern "rust-preserve-none" fn peach(x: u16) {
|
||||
loop {}
|
||||
}
|
||||
|
||||
// X86: call preserve_nonecc void @peach(i16
|
||||
// AARCH64: call preserve_nonecc void @peach(i16
|
||||
// UNSUPPORTED: call void @peach(i16
|
||||
pub fn quince(x: u16) {
|
||||
if let 12345u16 = x {
|
||||
peach(54321);
|
||||
}
|
||||
}
|
||||
46
tests/codegen-llvm/slice_cse_optimization.rs
Normal file
46
tests/codegen-llvm/slice_cse_optimization.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
//! Various iterating method over slice correctly optimized using common subexpression elimination.
|
||||
//! Checks function has memory(argmem: read) attribute.
|
||||
//! Regression test for <https://github.com/rust-lang/rust/issues/119573>.
|
||||
//@ compile-flags: -O
|
||||
|
||||
#![crate_type = "lib"]
|
||||
// CHECK-LABEL: @has_zero_iter
|
||||
// CHECK-SAME: #[[ATTR:[0-9]+]]
|
||||
#[inline(never)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn has_zero_iter(xs: &[u8]) -> bool {
|
||||
xs.iter().any(|&x| x == 0)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @has_zero_ptr
|
||||
// CHECK-SAME: #[[ATTR]]
|
||||
#[inline(never)]
|
||||
#[unsafe(no_mangle)]
|
||||
fn has_zero_ptr(xs: &[u8]) -> bool {
|
||||
let range = xs.as_ptr_range();
|
||||
let mut start = range.start;
|
||||
let end = range.end;
|
||||
while start < end {
|
||||
unsafe {
|
||||
if *start == 0 {
|
||||
return true;
|
||||
}
|
||||
start = start.add(1);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
// CHECK-LABEL: @has_zero_for
|
||||
// CHECK-SAME: #[[ATTR]]
|
||||
#[inline(never)]
|
||||
#[unsafe(no_mangle)]
|
||||
fn has_zero_for(xs: &[u8]) -> bool {
|
||||
for x in xs {
|
||||
if *x == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// CHECK: attributes #[[ATTR]] = { {{.*}}memory(argmem: read){{.*}} }
|
||||
|
|
@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
scope 3 {
|
||||
let _8: std::ptr::alignment::AlignmentEnum;
|
||||
scope 4 {
|
||||
scope 12 (inlined Layout::size) {
|
||||
scope 17 (inlined Layout::size) {
|
||||
}
|
||||
scope 13 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 15 (inlined NonNull::<[T]>::as_ptr) {
|
||||
scope 18 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 19 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 20 (inlined NonNull::<[T]>::as_ptr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 16 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 17 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
}
|
||||
}
|
||||
scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 19 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 24 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
let mut _9: *mut u8;
|
||||
scope 21 (inlined Layout::size) {
|
||||
scope 26 (inlined Layout::size) {
|
||||
}
|
||||
scope 22 (inlined NonNull::<u8>::as_ptr) {
|
||||
scope 27 (inlined NonNull::<u8>::as_ptr) {
|
||||
}
|
||||
scope 23 (inlined std::alloc::dealloc) {
|
||||
scope 28 (inlined std::alloc::dealloc) {
|
||||
let mut _10: usize;
|
||||
scope 24 (inlined Layout::size) {
|
||||
scope 29 (inlined Layout::size) {
|
||||
}
|
||||
scope 25 (inlined Layout::align) {
|
||||
scope 26 (inlined std::ptr::Alignment::as_usize) {
|
||||
scope 30 (inlined Layout::align) {
|
||||
scope 31 (inlined std::ptr::Alignment::as_usize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
}
|
||||
scope 7 (inlined Layout::for_value_raw::<[T]>) {
|
||||
let mut _5: usize;
|
||||
let mut _6: usize;
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 8 {
|
||||
scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
|
||||
}
|
||||
}
|
||||
scope 9 (inlined size_of_val_raw::<[T]>) {
|
||||
}
|
||||
scope 10 (inlined align_of_val_raw::<[T]>) {
|
||||
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) {
|
||||
let _6: usize;
|
||||
scope 11 {
|
||||
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
|
||||
scope 14 (inlined core::ub_checks::check_language_ub) {
|
||||
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 12 (inlined align_of_val_raw::<[T]>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
StorageLive(_4);
|
||||
_3 = copy _2 as *mut [T] (Transmute);
|
||||
_4 = copy _2 as *const [T] (Transmute);
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_6);
|
||||
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN;
|
||||
StorageLive(_7);
|
||||
_7 = copy _6 as std::ptr::Alignment (Transmute);
|
||||
_8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
_8 = copy (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_4);
|
||||
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
scope 3 {
|
||||
let _8: std::ptr::alignment::AlignmentEnum;
|
||||
scope 4 {
|
||||
scope 12 (inlined Layout::size) {
|
||||
scope 17 (inlined Layout::size) {
|
||||
}
|
||||
scope 13 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 15 (inlined NonNull::<[T]>::as_ptr) {
|
||||
scope 18 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 19 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 20 (inlined NonNull::<[T]>::as_ptr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 16 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 17 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
}
|
||||
}
|
||||
scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 19 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 24 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
let mut _9: *mut u8;
|
||||
scope 21 (inlined Layout::size) {
|
||||
scope 26 (inlined Layout::size) {
|
||||
}
|
||||
scope 22 (inlined NonNull::<u8>::as_ptr) {
|
||||
scope 27 (inlined NonNull::<u8>::as_ptr) {
|
||||
}
|
||||
scope 23 (inlined std::alloc::dealloc) {
|
||||
scope 28 (inlined std::alloc::dealloc) {
|
||||
let mut _10: usize;
|
||||
scope 24 (inlined Layout::size) {
|
||||
scope 29 (inlined Layout::size) {
|
||||
}
|
||||
scope 25 (inlined Layout::align) {
|
||||
scope 26 (inlined std::ptr::Alignment::as_usize) {
|
||||
scope 30 (inlined Layout::align) {
|
||||
scope 31 (inlined std::ptr::Alignment::as_usize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
}
|
||||
scope 7 (inlined Layout::for_value_raw::<[T]>) {
|
||||
let mut _5: usize;
|
||||
let mut _6: usize;
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 8 {
|
||||
scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
|
||||
}
|
||||
}
|
||||
scope 9 (inlined size_of_val_raw::<[T]>) {
|
||||
}
|
||||
scope 10 (inlined align_of_val_raw::<[T]>) {
|
||||
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) {
|
||||
let _6: usize;
|
||||
scope 11 {
|
||||
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
|
||||
scope 14 (inlined core::ub_checks::check_language_ub) {
|
||||
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 12 (inlined align_of_val_raw::<[T]>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
StorageLive(_4);
|
||||
_3 = copy _2 as *mut [T] (Transmute);
|
||||
_4 = copy _2 as *const [T] (Transmute);
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_6);
|
||||
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN;
|
||||
StorageLive(_7);
|
||||
_7 = copy _6 as std::ptr::Alignment (Transmute);
|
||||
_8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
_8 = copy (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_4);
|
||||
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
scope 3 {
|
||||
let _8: std::ptr::alignment::AlignmentEnum;
|
||||
scope 4 {
|
||||
scope 12 (inlined Layout::size) {
|
||||
scope 17 (inlined Layout::size) {
|
||||
}
|
||||
scope 13 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 15 (inlined NonNull::<[T]>::as_ptr) {
|
||||
scope 18 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 19 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 20 (inlined NonNull::<[T]>::as_ptr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 16 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 17 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
}
|
||||
}
|
||||
scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 19 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 24 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
let mut _9: *mut u8;
|
||||
scope 21 (inlined Layout::size) {
|
||||
scope 26 (inlined Layout::size) {
|
||||
}
|
||||
scope 22 (inlined NonNull::<u8>::as_ptr) {
|
||||
scope 27 (inlined NonNull::<u8>::as_ptr) {
|
||||
}
|
||||
scope 23 (inlined std::alloc::dealloc) {
|
||||
scope 28 (inlined std::alloc::dealloc) {
|
||||
let mut _10: usize;
|
||||
scope 24 (inlined Layout::size) {
|
||||
scope 29 (inlined Layout::size) {
|
||||
}
|
||||
scope 25 (inlined Layout::align) {
|
||||
scope 26 (inlined std::ptr::Alignment::as_usize) {
|
||||
scope 30 (inlined Layout::align) {
|
||||
scope 31 (inlined std::ptr::Alignment::as_usize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
}
|
||||
scope 7 (inlined Layout::for_value_raw::<[T]>) {
|
||||
let mut _5: usize;
|
||||
let mut _6: usize;
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 8 {
|
||||
scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
|
||||
}
|
||||
}
|
||||
scope 9 (inlined size_of_val_raw::<[T]>) {
|
||||
}
|
||||
scope 10 (inlined align_of_val_raw::<[T]>) {
|
||||
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) {
|
||||
let _6: usize;
|
||||
scope 11 {
|
||||
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
|
||||
scope 14 (inlined core::ub_checks::check_language_ub) {
|
||||
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 12 (inlined align_of_val_raw::<[T]>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
StorageLive(_4);
|
||||
_3 = copy _2 as *mut [T] (Transmute);
|
||||
_4 = copy _2 as *const [T] (Transmute);
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_6);
|
||||
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN;
|
||||
StorageLive(_7);
|
||||
_7 = copy _6 as std::ptr::Alignment (Transmute);
|
||||
_8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
_8 = copy (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_4);
|
||||
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
scope 3 {
|
||||
let _8: std::ptr::alignment::AlignmentEnum;
|
||||
scope 4 {
|
||||
scope 12 (inlined Layout::size) {
|
||||
scope 17 (inlined Layout::size) {
|
||||
}
|
||||
scope 13 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 14 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 15 (inlined NonNull::<[T]>::as_ptr) {
|
||||
scope 18 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
|
||||
scope 19 (inlined NonNull::<[T]>::cast::<u8>) {
|
||||
scope 20 (inlined NonNull::<[T]>::as_ptr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 16 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 17 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
|
||||
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
|
||||
}
|
||||
}
|
||||
scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 19 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
|
||||
scope 24 (inlined std::alloc::Global::deallocate_impl) {
|
||||
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
|
||||
let mut _9: *mut u8;
|
||||
scope 21 (inlined Layout::size) {
|
||||
scope 26 (inlined Layout::size) {
|
||||
}
|
||||
scope 22 (inlined NonNull::<u8>::as_ptr) {
|
||||
scope 27 (inlined NonNull::<u8>::as_ptr) {
|
||||
}
|
||||
scope 23 (inlined std::alloc::dealloc) {
|
||||
scope 28 (inlined std::alloc::dealloc) {
|
||||
let mut _10: usize;
|
||||
scope 24 (inlined Layout::size) {
|
||||
scope 29 (inlined Layout::size) {
|
||||
}
|
||||
scope 25 (inlined Layout::align) {
|
||||
scope 26 (inlined std::ptr::Alignment::as_usize) {
|
||||
scope 30 (inlined Layout::align) {
|
||||
scope 31 (inlined std::ptr::Alignment::as_usize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
}
|
||||
scope 7 (inlined Layout::for_value_raw::<[T]>) {
|
||||
let mut _5: usize;
|
||||
let mut _6: usize;
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 8 {
|
||||
scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) {
|
||||
let mut _7: std::ptr::Alignment;
|
||||
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
|
||||
}
|
||||
}
|
||||
scope 9 (inlined size_of_val_raw::<[T]>) {
|
||||
}
|
||||
scope 10 (inlined align_of_val_raw::<[T]>) {
|
||||
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) {
|
||||
let _6: usize;
|
||||
scope 11 {
|
||||
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
|
||||
scope 14 (inlined core::ub_checks::check_language_ub) {
|
||||
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 12 (inlined align_of_val_raw::<[T]>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
|
|||
StorageLive(_4);
|
||||
_3 = copy _2 as *mut [T] (Transmute);
|
||||
_4 = copy _2 as *const [T] (Transmute);
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_6);
|
||||
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN;
|
||||
StorageLive(_7);
|
||||
_7 = copy _6 as std::ptr::Alignment (Transmute);
|
||||
_8 = move (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
_8 = copy (_7.0: std::ptr::alignment::AlignmentEnum);
|
||||
StorageDead(_7);
|
||||
StorageDead(_4);
|
||||
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub unsafe fn generic_in_place<T: Copy>(ptr: *mut Box<[T]>) {
|
|||
// CHECK: [[SIZE:_.+]] = std::intrinsics::size_of_val::<[T]>
|
||||
// CHECK: [[ALIGN:_.+]] = const <T as std::mem::SizedTypeProperties>::ALIGN;
|
||||
// CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute);
|
||||
// CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum);
|
||||
// CHECK: [[C:_.+]] = copy ([[B]].0: std::ptr::alignment::AlignmentEnum);
|
||||
// CHECK: [[D:_.+]] = discriminant([[C]]);
|
||||
// CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) ->
|
||||
std::ptr::drop_in_place(ptr)
|
||||
|
|
|
|||
67
tests/ui/abi/rust-preserve-none-cc.rs
Normal file
67
tests/ui/abi/rust-preserve-none-cc.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//@ run-pass
|
||||
//@ needs-unwind
|
||||
|
||||
#![feature(rust_preserve_none_cc)]
|
||||
|
||||
struct CrateOf<'a> {
|
||||
mcintosh: f64,
|
||||
golden_delicious: u64,
|
||||
jonagold: Option<&'a u64>,
|
||||
rome: [u64; 12],
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
extern "rust-preserve-none" fn oven_explosion() {
|
||||
panic!("bad time");
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn bite_into(yummy: u64) -> u64 {
|
||||
let did_it_actually = std::panic::catch_unwind(move || {
|
||||
oven_explosion()
|
||||
});
|
||||
assert!(did_it_actually.is_err());
|
||||
yummy - 25
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
extern "rust-preserve-none" fn lotsa_apples(
|
||||
honeycrisp: u64,
|
||||
gala: u32,
|
||||
fuji: f64,
|
||||
granny_smith: &[u64],
|
||||
pink_lady: (),
|
||||
and_a: CrateOf<'static>,
|
||||
cosmic_crisp: u64,
|
||||
ambrosia: f64,
|
||||
winesap: &[u64],
|
||||
) -> (u64, f64, u64, u64) {
|
||||
assert_eq!(honeycrisp, 220);
|
||||
assert_eq!(gala, 140);
|
||||
assert_eq!(fuji, 210.54201234);
|
||||
assert_eq!(granny_smith, &[180, 210]);
|
||||
assert_eq!(pink_lady, ());
|
||||
assert_eq!(and_a.mcintosh, 150.0);
|
||||
assert_eq!(and_a.golden_delicious, 185);
|
||||
assert_eq!(and_a.jonagold, None); // my scales can't weight these gargantuans.
|
||||
assert_eq!(and_a.rome, [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]);
|
||||
assert_eq!(cosmic_crisp, 270);
|
||||
assert_eq!(ambrosia, 193.1);
|
||||
assert_eq!(winesap, &[]);
|
||||
(
|
||||
and_a.rome.iter().sum(),
|
||||
fuji + ambrosia,
|
||||
cosmic_crisp - honeycrisp,
|
||||
bite_into(and_a.golden_delicious)
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let pie = lotsa_apples(220, 140, 210.54201234, &[180, 210], (), CrateOf {
|
||||
mcintosh: 150.0,
|
||||
golden_delicious: 185,
|
||||
jonagold: None,
|
||||
rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]
|
||||
}, 270, 193.1, &[]);
|
||||
assert_eq!(pie, (2292, 403.64201234, 50, 160));
|
||||
}
|
||||
7
tests/ui/coercion/closure-in-array.rs
Normal file
7
tests/ui/coercion/closure-in-array.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// Weakened closure sig inference by #140283.
|
||||
fn foo<F: FnOnce(&str) -> usize, const N: usize>(x: [F; N]) {}
|
||||
|
||||
fn main() {
|
||||
foo([|s| s.len()])
|
||||
//~^ ERROR: type annotations needed
|
||||
}
|
||||
14
tests/ui/coercion/closure-in-array.stderr
Normal file
14
tests/ui/coercion/closure-in-array.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
error[E0282]: type annotations needed
|
||||
--> $DIR/closure-in-array.rs:5:11
|
||||
|
|
||||
LL | foo([|s| s.len()])
|
||||
| ^ - type must be known at this point
|
||||
|
|
||||
help: consider giving this closure parameter an explicit type
|
||||
|
|
||||
LL | foo([|s: /* Type */| s.len()])
|
||||
| ++++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
36
tests/ui/coercion/coerce-many-with-ty-var.rs
Normal file
36
tests/ui/coercion/coerce-many-with-ty-var.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
//@ run-pass
|
||||
// Check that least upper bound coercions don't resolve type variable merely based on the first
|
||||
// coercion. Check issue #136420.
|
||||
|
||||
fn foo() {}
|
||||
fn bar() {}
|
||||
|
||||
fn infer<T>(_: T) {}
|
||||
|
||||
fn infer_array_element<T>(_: [T; 2]) {}
|
||||
|
||||
fn main() {
|
||||
// Previously the element type's ty var will be unified with `foo`.
|
||||
let _: [_; 2] = [foo, bar];
|
||||
infer_array_element([foo, bar]);
|
||||
|
||||
let _ = if false {
|
||||
foo
|
||||
} else {
|
||||
bar
|
||||
};
|
||||
infer(if false {
|
||||
foo
|
||||
} else {
|
||||
bar
|
||||
});
|
||||
|
||||
let _ = match false {
|
||||
true => foo,
|
||||
false => bar,
|
||||
};
|
||||
infer(match false {
|
||||
true => foo,
|
||||
false => bar,
|
||||
});
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier
|
|||
LL | dbg!(b);
|
||||
| ^^^^^^^ expected named lifetime parameter
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0425]: cannot find function `a` in this scope
|
||||
--> $DIR/ice-line-bounds-issue-148732.rs:1:7
|
||||
|
|
@ -37,7 +37,7 @@ LL | dbg!(b);
|
|||
| ^^^^^^^ the trait `Debug` is not implemented for fn item `fn() {b}`
|
||||
|
|
||||
= help: use parentheses to call this function: `b()`
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
|||
21
tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.rs
Normal file
21
tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#![crate_type = "lib"]
|
||||
|
||||
extern "rust-preserve-none" fn apple() {} //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
|
||||
trait T {
|
||||
extern "rust-preserve-none" fn banana(); //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
extern "rust-preserve-none" fn citrus() {} //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
}
|
||||
|
||||
struct S;
|
||||
impl T for S {
|
||||
extern "rust-preserve-none" fn banana() {} //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
}
|
||||
|
||||
impl S {
|
||||
extern "rust-preserve-none" fn durian() {} //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
}
|
||||
|
||||
type Fig = extern "rust-preserve-none" fn(); //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
|
||||
extern "rust-preserve-none" {} //~ ERROR "rust-preserve-none" ABI is experimental
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:3:8
|
||||
|
|
||||
LL | extern "rust-preserve-none" fn apple() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:6:12
|
||||
|
|
||||
LL | extern "rust-preserve-none" fn banana();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:7:12
|
||||
|
|
||||
LL | extern "rust-preserve-none" fn citrus() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:12:12
|
||||
|
|
||||
LL | extern "rust-preserve-none" fn banana() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:16:12
|
||||
|
|
||||
LL | extern "rust-preserve-none" fn durian() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:19:19
|
||||
|
|
||||
LL | type Fig = extern "rust-preserve-none" fn();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-rust-preserve-none-cc.rs:21:8
|
||||
|
|
||||
LL | extern "rust-preserve-none" {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #151401 <https://github.com/rust-lang/rust/issues/151401> for more information
|
||||
= help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-pass
|
||||
#![allow(unused_variables)]
|
||||
#![warn(unused)]
|
||||
#![deny(non_shorthand_field_patterns)]
|
||||
|
||||
pub struct Value<A> { pub value: A }
|
||||
|
|
@ -13,5 +13,5 @@ macro_rules! pat {
|
|||
|
||||
fn main() {
|
||||
let pat!(value) = Value { value: () };
|
||||
//~^ WARN value assigned to `value` is never read
|
||||
//~^ WARN unused variable: `value`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
warning: value assigned to `value` is never read
|
||||
warning: unused variable: `value`
|
||||
--> $DIR/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs:15:14
|
||||
|
|
||||
LL | let pat!(value) = Value { value: () };
|
||||
| ^^^^^
|
||||
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_value`
|
||||
|
|
||||
= help: maybe it is overwritten before being read?
|
||||
= note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs:2:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
#![feature(proc_macro_quote)]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_derive(Drop)]
|
||||
pub fn generate(ts: TokenStream) -> TokenStream {
|
||||
let mut ts = ts.into_iter();
|
||||
let _pub = ts.next();
|
||||
let _struct = ts.next();
|
||||
let name = ts.next().unwrap();
|
||||
let TokenTree::Group(fields) = ts.next().unwrap() else { panic!() };
|
||||
let mut fields = fields.stream().into_iter();
|
||||
let field = fields.next().unwrap();
|
||||
|
||||
quote! {
|
||||
impl Drop for $name {
|
||||
fn drop(&mut self) {
|
||||
let Self { $field } = self;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
tests/ui/lint/unused/unused_assignment.rs
Normal file
21
tests/ui/lint/unused/unused_assignment.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Unused assignments to an unused variable should trigger only the `unused_variables` lint and not
|
||||
// also the `unused_assignments` lint. This test covers the situation where the span of the unused
|
||||
// variable identifier comes from a different scope to the binding pattern - here, from a proc
|
||||
// macro's input tokenstream (whereas the binding pattern is generated within the proc macro
|
||||
// itself).
|
||||
//
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/151514
|
||||
//
|
||||
//@ check-pass
|
||||
//@ proc-macro: unused_assignment_proc_macro.rs
|
||||
#![warn(unused)]
|
||||
|
||||
extern crate unused_assignment_proc_macro;
|
||||
use unused_assignment_proc_macro::Drop;
|
||||
|
||||
#[derive(Drop)]
|
||||
pub struct S {
|
||||
a: (), //~ WARN unused variable: `a`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
15
tests/ui/lint/unused/unused_assignment.stderr
Normal file
15
tests/ui/lint/unused/unused_assignment.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
warning: unused variable: `a`
|
||||
--> $DIR/unused_assignment.rs:18:5
|
||||
|
|
||||
LL | a: (),
|
||||
| ^ help: try ignoring the field: `a: _`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unused_assignment.rs:11:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
@ -4,7 +4,7 @@ error[E0308]: mismatched types
|
|||
LL | x => dbg!(x),
|
||||
| ^^^^^^^ expected `()`, found integer
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | x => return dbg!(x),
|
||||
|
|
@ -16,7 +16,7 @@ error[E0308]: mismatched types
|
|||
LL | dbg!(x)
|
||||
| ^^^^^^^ expected `()`, found integer
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | return dbg!(x)
|
||||
|
|
@ -28,7 +28,7 @@ error[E0308]: mismatched types
|
|||
LL | _ => dbg!(1)
|
||||
| ^^^^^^^ expected `()`, found integer
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | _ => return dbg!(1)
|
||||
|
|
@ -40,7 +40,7 @@ error[E0308]: mismatched types
|
|||
LL | _ => {dbg!(1)}
|
||||
| ^^^^^^^ expected `()`, found integer
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | _ => {return dbg!(1)}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ error[E0277]: `Dummy` doesn't implement `Debug`
|
|||
| ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `Dummy`
|
||||
|
|
||||
= note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy`
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider annotating `Dummy` with `#[derive(Debug)]`
|
||||
--> $DIR/auxiliary/dummy_lib.rs:2:1
|
||||
|
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ pub fn main() {
|
|||
}
|
||||
match (E::E { a: 10, e: C { c: 20 } }) {
|
||||
mut x @ E::E{ a, e: C { mut c } } => {
|
||||
//~^ WARN value assigned to `a` is never read
|
||||
x = E::NotE;
|
||||
//~^ WARN value assigned to `x` is never read
|
||||
c += 30;
|
||||
|
|
|
|||
|
|
@ -20,20 +20,12 @@ LL | y.d.c = 30;
|
|||
= help: maybe it is overwritten before being read?
|
||||
|
||||
warning: value assigned to `x` is never read
|
||||
--> $DIR/bind-by-copy.rs:57:13
|
||||
--> $DIR/bind-by-copy.rs:56:13
|
||||
|
|
||||
LL | x = E::NotE;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: maybe it is overwritten before being read?
|
||||
|
||||
warning: value assigned to `a` is never read
|
||||
--> $DIR/bind-by-copy.rs:55:23
|
||||
|
|
||||
LL | mut x @ E::E{ a, e: C { mut c } } => {
|
||||
| ^
|
||||
|
|
||||
= help: maybe it is overwritten before being read?
|
||||
|
||||
warning: 4 warnings emitted
|
||||
warning: 3 warnings emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ riscv-interrupt-s
|
|||
rust-call
|
||||
rust-cold
|
||||
rust-invalid
|
||||
rust-preserve-none
|
||||
stdcall
|
||||
stdcall-unwind
|
||||
system
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ LL | let _ = dbg!(a);
|
|||
LL | let _ = dbg!(a);
|
||||
| ^^^^^^^ value used here after move
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | let _ = dbg!(&a);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | let _: NotDebug = dbg!(NotDebug);
|
|||
| ^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `NotDebug`
|
||||
|
|
||||
= note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug`
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider annotating `NotDebug` with `#[derive(Debug)]`
|
||||
|
|
||||
LL + #[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error: target feature `soft-float` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
|
||||
error: target feature `soft-float` cannot be enabled with `#[target_feature]`: use a soft-float target instead
|
||||
--> $DIR/abi-incompatible-target-feature-attribute.rs:17:32
|
||||
|
|
||||
LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))]
|
||||
|
|
|
|||
|
|
@ -19,4 +19,5 @@ extern crate minicore;
|
|||
use minicore::*;
|
||||
|
||||
//~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly
|
||||
//~? WARN unstable feature specified for `-Ctarget-feature`
|
||||
//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
|
||||
//[x86]~? WARN use a soft-float target instead
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
warning: unstable feature specified for `-Ctarget-feature`: `soft-float`
|
||||
warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: use a soft-float target instead
|
||||
|
|
||||
= note: this feature is not stably supported; its behavior can change in the future
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly
|
||||
|
|
||||
|
|
|
|||
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