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:
The Miri Cronjob Bot 2026-01-26 05:15:06 +00:00
commit 58f38eb01d
104 changed files with 1680 additions and 967 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -400,6 +400,7 @@ impl<'a> AstValidator<'a> {
CanonAbi::C
| CanonAbi::Rust
| CanonAbi::RustCold
| CanonAbi::RustPreserveNone
| CanonAbi::Arm(_)
| CanonAbi::X86(_) => { /* nothing to check */ }

View file

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

View file

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

View file

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

View file

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

View file

@ -167,6 +167,7 @@ pub(crate) enum CallConv {
PreserveMost = 14,
PreserveAll = 15,
Tail = 18,
PreserveNone = 21,
X86StdcallCallConv = 64,
X86FastcallCallConv = 65,
ArmAapcsCallConv = 67,

View file

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

View file

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

View file

@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
CanonAbi::C
| CanonAbi::Rust
| CanonAbi::RustCold
| CanonAbi::RustPreserveNone
| CanonAbi::Arm(_)
| CanonAbi::X86(_) => {}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(),

View file

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

View file

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

View file

@ -432,6 +432,7 @@ pub enum CallConvention {
Cold,
PreserveMost,
PreserveAll,
PreserveNone,
Custom,

View file

@ -1139,6 +1139,7 @@ pub enum Abi {
RustCold,
RiscvInterruptM,
RiscvInterruptS,
RustPreserveNone,
RustInvalid,
Custom,
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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"]),

View file

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

View file

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

View file

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

View file

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

View file

@ -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")]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -170,6 +170,6 @@ impl Diagnostic {
}
}
crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self));
crate::bridge::client::Methods::emit_diagnostic(to_internal(self));
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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"),
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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]);

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
//@ ignore-loongarch64 (handles dso_local differently)
//@ ignore-powerpc64 (handles dso_local differently)
//@ ignore-apple (handles dso_local differently)

View file

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

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

View file

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

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

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

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

View file

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

View 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

View file

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

View file

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

View file

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

View file

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

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,6 +21,7 @@ riscv-interrupt-s
rust-call
rust-cold
rust-invalid
rust-preserve-none
stdcall
stdcall-unwind
system

View file

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

View file

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

View file

@ -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"))]

View file

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

View file

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