Auto merge of #151634 - matthiaskrgr:rollup-cE0JR24, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - rust-lang/rust#145393 (Add codegen test for removing trailing zeroes from `NonZero`)
 - rust-lang/rust#148764 (ptr_aligment_type: add more APIs)
 - rust-lang/rust#149869 (std: avoid tearing `dbg!` prints)
 - rust-lang/rust#150065 (add CSE optimization tests for iterating over slice)
 - rust-lang/rust#150842 (Fix(lib/win/thread): Ensure `Sleep`'s usage passes over the requested duration under Win7)
 - rust-lang/rust#151505 (Various refactors to the proc_macro bridge)
 - rust-lang/rust#151560 (relnotes: fix 1.93's `as_mut_array` methods)
 - rust-lang/rust#151317 (x86 soft-float feature: mark it as forbidden rather than unstable)
 - rust-lang/rust#151577 (Rename `DepKindStruct` to `DepKindVTable`)
 - rust-lang/rust#151620 (Fix 'the the' typo in library/core/src/array/iter.rs)
This commit is contained in:
bors 2026-01-25 09:56:27 +00:00
commit 4d38622e8b
59 changed files with 1171 additions and 934 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

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

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

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

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

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

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

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

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

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

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

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

View file

@ -0,0 +1,17 @@
//! The soft-float target feature is *not* exposed as `cfg` on x86.
//@ revisions: soft hard
//@[hard] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
//@[hard] needs-llvm-components: x86
//@[soft] compile-flags: --target=x86_64-unknown-none --crate-type=lib
//@[soft] needs-llvm-components: x86
//@ check-pass
//@ ignore-backends: gcc
//@ add-minicore
#![feature(no_core)]
#![no_core]
#![allow(unexpected_cfgs)]
// The compile_error macro does not exist, so if the `cfg` evaluates to `true` this
// complains about the missing macro rather than showing the error... but that's good enough.
#[cfg(target_feature = "soft-float")]
compile_error!("the soft-float feature should NOT be exposed in `cfg`");

View file

@ -68,7 +68,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::concrete).10)
span: $DIR/offset_of.rs:37:5: 1440:57 (#0)
span: $DIR/offset_of.rs:37:5: 1445:57 (#0)
}
}
Stmt {
@ -117,7 +117,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::concrete).20)
span: $DIR/offset_of.rs:38:5: 1440:57 (#0)
span: $DIR/offset_of.rs:38:5: 1445:57 (#0)
}
}
Stmt {
@ -166,7 +166,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::concrete).30)
span: $DIR/offset_of.rs:39:5: 1440:57 (#0)
span: $DIR/offset_of.rs:39:5: 1445:57 (#0)
}
}
Stmt {
@ -215,7 +215,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::concrete).40)
span: $DIR/offset_of.rs:40:5: 1440:57 (#0)
span: $DIR/offset_of.rs:40:5: 1445:57 (#0)
}
}
Stmt {
@ -264,7 +264,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::concrete).50)
span: $DIR/offset_of.rs:41:5: 1440:57 (#0)
span: $DIR/offset_of.rs:41:5: 1445:57 (#0)
}
}
]
@ -864,7 +864,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::generic).12)
span: $DIR/offset_of.rs:45:5: 1440:57 (#0)
span: $DIR/offset_of.rs:45:5: 1445:57 (#0)
}
}
Stmt {
@ -913,7 +913,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::generic).24)
span: $DIR/offset_of.rs:46:5: 1440:57 (#0)
span: $DIR/offset_of.rs:46:5: 1445:57 (#0)
}
}
Stmt {
@ -962,7 +962,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::generic).36)
span: $DIR/offset_of.rs:47:5: 1440:57 (#0)
span: $DIR/offset_of.rs:47:5: 1445:57 (#0)
}
}
Stmt {
@ -1011,7 +1011,7 @@ body:
)
else_block: None
hir_id: HirId(DefId(offset_of::generic).48)
span: $DIR/offset_of.rs:48:5: 1440:57 (#0)
span: $DIR/offset_of.rs:48:5: 1445:57 (#0)
}
}
]

View file

@ -15,7 +15,7 @@ error[E0308]: mismatched types
LL | b"abc".iter().for_each(|x| dbg!(x));
| ^^^^^^^ expected `()`, found `&u8`
|
= 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[E0308]: mismatched types
--> $DIR/closure-ty-mismatch-issue-128561.rs:8:9

View file

@ -26,7 +26,7 @@ error[E0308]: mismatched types
LL | let c: S = dbg!(field);
| ^^^^^^^^^^^ expected `S`, found `&S`
|
= 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 using clone here
|
LL | let c: S = dbg!(field).clone();
@ -38,7 +38,7 @@ error[E0308]: mismatched types
LL | let c: S = dbg!(dbg!(field));
| ^^^^^^^^^^^^^^^^^ expected `S`, found `&S`
|
= 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 using clone here
|
LL | let c: S = dbg!(dbg!(field)).clone();