diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 57856b4ddb1b7..8542bab689d6d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -89,44 +89,39 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }; match name { - sym::cold => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; - } - sym::rustc_allocator => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; - } + sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, + sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR, sym::ffi_returns_twice => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; - } - sym::ffi_pure => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE; - } - sym::ffi_const => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; - } - sym::rustc_nounwind => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } - sym::rustc_reallocator => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR; - } - sym::rustc_deallocator => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE } + sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, + sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST, + sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, + sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR, + sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR, sym::rustc_allocator_zeroed => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED; - } - sym::naked => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } + sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, sym::no_mangle => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - } - sym::no_coverage => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; + if tcx.opt_item_name(did.to_def_id()).is_some() { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE + } else { + tcx.sess + .struct_span_err( + attr.span, + format!( + "`#[no_mangle]` cannot be used on {} {} as it has no name", + tcx.def_descr_article(did.to_def_id()), + tcx.def_descr(did.to_def_id()), + ), + ) + .emit(); + } } + sym::no_coverage => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE, sym::rustc_std_internal_symbol => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } sym::used => { let inner = attr.meta_item_list(); @@ -207,11 +202,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") .emit(); } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; - } - sym::thread_local => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY } + sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { if !tcx.is_closure(did.to_def_id()) && let Some(fn_sig) = fn_sig() @@ -229,7 +222,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { ) .emit(); } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER } sym::export_name => { if let Some(s) = attr.value_str() { @@ -306,20 +299,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::link_section => { if let Some(val) = attr.value_str() { if val.as_str().bytes().any(|b| b == 0) { - let msg = format!( - "illegal null byte in link_section \ - value: `{}`", - &val - ); + let msg = format!("illegal null byte in link_section value: `{}`", &val); tcx.sess.span_err(attr.span, &msg); } else { codegen_fn_attrs.link_section = Some(val); } } } - sym::link_name => { - codegen_fn_attrs.link_name = attr.value_str(); - } + sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), sym::link_ordinal => { link_ordinal_span = Some(attr.span); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { @@ -330,37 +317,27 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { no_sanitize_span = Some(attr.span); if let Some(list) = attr.meta_item_list() { for item in list.iter() { - match item.ident().map(|ident| ident.name) { - Some(sym::address) => { + match item.name_or_empty() { + sym::address => { codegen_fn_attrs.no_sanitize |= - SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS; - } - Some(sym::cfi) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI; + SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS } - Some(sym::kcfi) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI; + sym::cfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI, + sym::kcfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI, + sym::memory => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY, + sym::memtag => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG, + sym::shadow_call_stack => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK } - Some(sym::memory) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; - } - Some(sym::memtag) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG; - } - Some(sym::shadow_call_stack) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK; - } - Some(sym::thread) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; - } - Some(sym::hwaddress) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS; + sym::thread => codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD, + sym::hwaddress => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS } _ => { tcx.sess - .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") - .emit(); + .struct_span_err(item.span(), "invalid argument for `no_sanitize`") + .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") + .emit(); } } } diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 01d292dde8d13..f88c055a9b569 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -5,7 +5,7 @@ use std::collections::hash_map::RawEntryMut; use std::hash::{Hash, Hasher}; use std::mem; -#[derive(Clone, Default)] +#[derive(Default)] #[cfg_attr(parallel_compiler, repr(align(64)))] struct CacheAligned(T); @@ -21,7 +21,6 @@ const SHARD_BITS: usize = 0; pub const SHARDS: usize = 1 << SHARD_BITS; /// An array of cache-line aligned inner locked structures with convenience methods. -#[derive(Clone)] pub struct Sharded { shards: [CacheAligned>; SHARDS], } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 31323c21df009..4e2126fff7be9 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -1,21 +1,46 @@ -//! This module defines types which are thread safe if cfg!(parallel_compiler) is true. +//! This module defines various operations and types that are implemented in +//! one way for the serial compiler, and another way the parallel compiler. //! -//! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise. +//! Operations +//! ---------- +//! The parallel versions of operations use Rayon to execute code in parallel, +//! while the serial versions degenerate straightforwardly to serial execution. +//! The operations include `join`, `parallel`, `par_iter`, and `par_for_each`. //! -//! `Lock` is a mutex. -//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true, -//! `RefCell` otherwise. +//! `rustc_erase_owner!` erases an `OwningRef` owner into `Erased` for the +//! serial version and `Erased + Send + Sync` for the parallel version. //! -//! `RwLock` is a read-write lock. -//! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true, -//! `RefCell` otherwise. +//! Types +//! ----- +//! The parallel versions of types provide various kinds of synchronization, +//! while the serial compiler versions do not. //! -//! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false. +//! The following table shows how the types are implemented internally. Except +//! where noted otherwise, the type in column one is defined as a +//! newtype around the type from column two or three. //! -//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise. +//! | Type | Serial version | Parallel version | +//! | ----------------------- | ------------------- | ------------------------------- | +//! | `Lrc` | `rc::Rc` | `sync::Arc` | +//! |` Weak` | `rc::Weak` | `sync::Weak` | +//! | | | | +//! | `AtomicBool` | `Cell` | `atomic::AtomicBool` | +//! | `AtomicU32` | `Cell` | `atomic::AtomicU32` | +//! | `AtomicU64` | `Cell` | `atomic::AtomicU64` | +//! | `AtomicUsize` | `Cell` | `atomic::AtomicUsize` | +//! | | | | +//! | `Lock` | `RefCell` | `parking_lot::Mutex` | +//! | `RwLock` | `RefCell` | `parking_lot::RwLock` | +//! | `MTLock` [^1] | `T` | `Lock` | +//! | `MTLockRef<'a, T>` [^2] | `&'a mut MTLock` | `&'a MTLock` | +//! | | | | +//! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` | //! -//! `rustc_erase_owner!` erases an OwningRef owner into Erased or Erased + Send + Sync -//! depending on the value of cfg!(parallel_compiler). +//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost +//! of a `RefCell`. This is appropriate when interior mutability is not +//! required. +//! +//! [^2] `MTLockRef` is a typedef. use crate::owning_ref::{Erased, OwningRef}; use std::collections::HashMap; @@ -209,7 +234,7 @@ cfg_if! { } } - pub type MTRef<'a, T> = &'a mut T; + pub type MTLockRef<'a, T> = &'a mut MTLock; #[derive(Debug, Default)] pub struct MTLock(T); @@ -267,7 +292,7 @@ cfg_if! { pub use std::sync::Arc as Lrc; pub use std::sync::Weak as Weak; - pub type MTRef<'a, T> = &'a T; + pub type MTLockRef<'a, T> = &'a MTLock; #[derive(Debug, Default)] pub struct MTLock(Lock); @@ -553,18 +578,6 @@ impl RwLock { self.write() } - #[cfg(not(parallel_compiler))] - #[inline(always)] - pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> { - ReadGuard::clone(rg) - } - - #[cfg(parallel_compiler)] - #[inline(always)] - pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> { - ReadGuard::rwlock(&rg).read() - } - #[cfg(not(parallel_compiler))] #[inline(always)] pub fn leak(&self) -> &T { diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 171cf1c1ab173..967fed687b6a8 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; use std::hash::Hash; /// Represents the levels of effective visibility an item can have. @@ -107,6 +107,10 @@ impl EffectiveVisibilities { }) } + pub fn update_root(&mut self) { + self.map.insert(CRATE_DEF_ID, EffectiveVisibility::from_vis(Visibility::Public)); + } + // FIXME: Share code with `fn update`. pub fn update_eff_vis( &mut self, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index af0222c8172d2..7ca18fca18c14 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -174,7 +174,7 @@ //! regardless of whether it is actually needed or not. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{par_for_each_in, MTLock, MTRef}; +use rustc_data_structures::sync::{par_for_each_in, MTLock, MTLockRef}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; @@ -341,8 +341,8 @@ pub fn collect_crate_mono_items( let recursion_limit = tcx.recursion_limit(); { - let visited: MTRef<'_, _> = &mut visited; - let inlining_map: MTRef<'_, _> = &mut inlining_map; + let visited: MTLockRef<'_, _> = &mut visited; + let inlining_map: MTLockRef<'_, _> = &mut inlining_map; tcx.sess.time("monomorphization_collector_graph_walk", || { par_for_each_in(roots, |root| { @@ -407,10 +407,10 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec( tcx: TyCtxt<'tcx>, starting_point: Spanned>, - visited: MTRef<'_, MTLock>>>, + visited: MTLockRef<'_, FxHashSet>>, recursion_depths: &mut DefIdMap, recursion_limit: Limit, - inlining_map: MTRef<'_, MTLock>>, + inlining_map: MTLockRef<'_, InliningMap<'tcx>>, ) { if !visited.lock_mut().insert(starting_point.node) { // We've been here already, no need to search again. diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 3be0160d56173..51a0a3e9a197c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -2149,6 +2149,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { let mut check_visitor = TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities }; + check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID); tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor); tcx.arena.alloc(visitor.effective_visibilities) diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 5f554a54deac1..d3efc22a19451 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -21,9 +21,6 @@ pub trait QueryCache: Sized { type Value: Copy + Debug; /// Checks if the query is already computed and in the cache. - /// It returns the shard index and a lock guard to the shard, - /// which will be used if the query is not in the cache and we need - /// to compute it. fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>; fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index a1ae9b8a52181..3673f603d1676 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -61,7 +61,7 @@ impl Resolver<'_, '_> { // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent. let normal_mod_id = self.nearest_normal_mod(def_id); if normal_mod_id == def_id { - self.tcx.opt_local_parent(def_id).map_or(Visibility::Public, Visibility::Restricted) + Visibility::Restricted(self.tcx.local_parent(def_id)) } else { Visibility::Restricted(normal_mod_id) } @@ -80,12 +80,11 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { r, def_effective_visibilities: Default::default(), import_effective_visibilities: Default::default(), - current_private_vis: Visibility::Public, + current_private_vis: Visibility::Restricted(CRATE_DEF_ID), changed: false, }; - visitor.update(CRATE_DEF_ID, CRATE_DEF_ID); - visitor.current_private_vis = Visibility::Restricted(CRATE_DEF_ID); + visitor.def_effective_visibilities.update_root(); visitor.set_bindings_effective_visibilities(CRATE_DEF_ID); while visitor.changed { @@ -125,43 +124,32 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { for (_, name_resolution) in resolutions.borrow().iter() { if let Some(mut binding) = name_resolution.borrow().binding() { - if !binding.is_ambiguity() { - // Set the given effective visibility level to `Level::Direct` and - // sets the rest of the `use` chain to `Level::Reexported` until - // we hit the actual exported item. - let mut parent_id = ParentId::Def(module_id); - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind - { - let binding_id = ImportId::new_unchecked(binding); - self.update_import(binding_id, parent_id); - - parent_id = ParentId::Import(binding_id); - binding = nested_binding; - } - - if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + // Set the given effective visibility level to `Level::Direct` and + // sets the rest of the `use` chain to `Level::Reexported` until + // we hit the actual exported item. + // + // If the binding is ambiguous, put the root ambiguity binding and all reexports + // leading to it into the table. They are used by the `ambiguous_glob_reexports` + // lint. For all bindings added to the table this way `is_ambiguity` returns true. + let mut parent_id = ParentId::Def(module_id); + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { + let binding_id = ImportId::new_unchecked(binding); + self.update_import(binding_id, parent_id); + + if binding.ambiguity.is_some() { + // Stop at the root ambiguity, further bindings in the chain should not + // be reexported because the root ambiguity blocks any access to them. + // (Those further bindings are most likely not ambiguities themselves.) + break; } - } else { - // Put the root ambiguity binding and all reexports leading to it into the - // table. They are used by the `ambiguous_glob_reexports` lint. For all - // bindings added to the table here `is_ambiguity` returns true. - let mut parent_id = ParentId::Def(module_id); - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind - { - let binding_id = ImportId::new_unchecked(binding); - self.update_import(binding_id, parent_id); - if binding.ambiguity.is_some() { - // Stop at the root ambiguity, further bindings in the chain should not - // be reexported because the root ambiguity blocks any access to them. - // (Those further bindings are most likely not ambiguities themselves.) - break; - } + parent_id = ParentId::Import(binding_id); + binding = nested_binding; + } - parent_id = ParentId::Import(binding_id); - binding = nested_binding; - } + if binding.ambiguity.is_none() + && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + self.update_def(def_id, binding.vis.expect_local(), parent_id); } } } @@ -213,7 +201,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { ); } - fn update(&mut self, def_id: LocalDefId, parent_id: LocalDefId) { + fn update_field(&mut self, def_id: LocalDefId, parent_id: LocalDefId) { self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id)); } } @@ -245,14 +233,14 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't for variant in variants { let variant_def_id = self.r.local_def_id(variant.id); for field in variant.data.fields() { - self.update(self.r.local_def_id(field.id), variant_def_id); + self.update_field(self.r.local_def_id(field.id), variant_def_id); } } } ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { for field in def.fields() { - self.update(self.r.local_def_id(field.id), def_id); + self.update_field(self.r.local_def_id(field.id), def_id); } } diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 2404928b254d6..40879db49def9 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -68,6 +68,7 @@ fn current_dll_path() -> Result { use std::ffi::{CStr, OsStr}; use std::os::unix::prelude::*; + #[cfg(not(target_os = "aix"))] unsafe { let addr = current_dll_path as usize as *mut _; let mut info = std::mem::zeroed(); @@ -81,6 +82,49 @@ fn current_dll_path() -> Result { let os = OsStr::from_bytes(bytes); Ok(PathBuf::from(os)) } + + #[cfg(target_os = "aix")] + unsafe { + // On AIX, the symbol `current_dll_path` references a function descriptor. + // A function descriptor is consisted of (See https://reviews.llvm.org/D62532) + // * The address of the entry point of the function. + // * The TOC base address for the function. + // * The environment pointer. + // The function descriptor is in the data section. + let addr = current_dll_path as u64; + let mut buffer = vec![std::mem::zeroed::(); 64]; + loop { + if libc::loadquery( + libc::L_GETINFO, + buffer.as_mut_ptr() as *mut i8, + (std::mem::size_of::() * buffer.len()) as u32, + ) >= 0 + { + break; + } else { + if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM { + return Err("loadquery failed".into()); + } + buffer.resize(buffer.len() * 2, std::mem::zeroed::()); + } + } + let mut current = buffer.as_mut_ptr() as *mut libc::ld_info; + loop { + let data_base = (*current).ldinfo_dataorg as u64; + let data_end = data_base + (*current).ldinfo_datasize; + if (data_base..data_end).contains(&addr) { + let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes(); + let os = OsStr::from_bytes(bytes); + return Ok(PathBuf::from(os)); + } + if (*current).ldinfo_next == 0 { + break; + } + current = + (current as *mut i8).offset((*current).ldinfo_next as isize) as *mut libc::ld_info; + } + return Err(format!("current dll's address {} is not in the load map", addr)); + } } #[cfg(windows)] diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index e64b4a7656f25..705e79aebd8c1 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -67,7 +67,20 @@ pub(super) enum IsNormalizesToHack { #[derive(Debug, Clone)] pub(super) struct NestedGoals<'tcx> { + /// This normalizes-to goal that is treated specially during the evaluation + /// loop. In each iteration we take the RHS of the projection, replace it with + /// a fresh inference variable, and only after evaluating that goal do we + /// equate the fresh inference variable with the actual RHS of the predicate. + /// + /// This is both to improve caching, and to avoid using the RHS of the + /// projection predicate to influence the normalizes-to candidate we select. + /// + /// This is not a 'real' nested goal. We must not forget to replace the RHS + /// with a fresh inference variable when we evaluate this goal. That can result + /// in a trait solver cycle. This would currently result in overflow but can be + /// can be unsound with more powerful coinduction in the future. pub(super) normalizes_to_hack_goal: Option>>, + /// The rest of the goals which have not yet processed or remain ambiguous. pub(super) goals: Vec>>, } @@ -182,6 +195,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { canonical_response, )?; + if !has_changed && !nested_goals.is_empty() { + bug!("an unchanged goal shouldn't have any side-effects on instantiation"); + } + // Check that rerunning this query with its inference constraints applied // doesn't result in new inference constraints and has the same result. // @@ -199,9 +216,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; if !canonical_response.value.var_values.is_identity() { - bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}"); + bug!( + "unstable result: re-canonicalized goal={canonical_goal:#?} \ + response={canonical_response:#?}" + ); + } + if certainty != canonical_response.value.certainty { + bug!( + "unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \ + response={canonical_response:#?}" + ); } - assert_eq!(certainty, canonical_response.value.certainty); } Ok((has_changed, certainty, nested_goals)) @@ -281,15 +306,44 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut has_changed = Err(Certainty::Yes); if let Some(goal) = goals.normalizes_to_hack_goal.take() { - let (_, certainty, nested_goals) = match this.evaluate_goal( - IsNormalizesToHack::Yes, - goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), + // Replace the goal with an unconstrained infer var, so the + // RHS does not affect projection candidate assembly. + let unconstrained_rhs = this.next_term_infer_of_kind(goal.predicate.term); + let unconstrained_goal = goal.with( + this.tcx(), + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: goal.predicate.projection_ty, + term: unconstrained_rhs, + }), + ); + + let (_, certainty, instantiate_goals) = + match this.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal) { + Ok(r) => r, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + new_goals.goals.extend(instantiate_goals); + + // Finally, equate the goal's RHS with the unconstrained var. + // We put the nested goals from this into goals instead of + // next_goals to avoid needing to process the loop one extra + // time if this goal returns something -- I don't think this + // matters in practice, though. + match this.eq_and_get_goals( + goal.param_env, + goal.predicate.term, + unconstrained_rhs, ) { - Ok(r) => r, + Ok(eq_goals) => { + goals.goals.extend(eq_goals); + } Err(NoSolution) => return Some(Err(NoSolution)), }; - new_goals.goals.extend(nested_goals); + // We only look at the `projection_ty` part here rather than + // looking at the "has changed" return from evaluate_goal, + // because we expect the `unconstrained_rhs` part of the predicate + // to have changed -- that means we actually normalized successfully! if goal.predicate.projection_ty != this.resolve_vars_if_possible(goal.predicate.projection_ty) { @@ -299,40 +353,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { match certainty { Certainty::Yes => {} Certainty::Maybe(_) => { - let goal = this.resolve_vars_if_possible(goal); - - // The rhs of this `normalizes-to` must always be an unconstrained infer var as it is - // the hack used by `normalizes-to` to ensure that every `normalizes-to` behaves the same - // regardless of the rhs. - // - // However it is important not to unconditionally replace the rhs with a new infer var - // as otherwise we may replace the original unconstrained infer var with a new infer var - // and never propagate any constraints on the new var back to the original var. - let term = this - .term_is_fully_unconstrained(goal) - .then_some(goal.predicate.term) - .unwrap_or_else(|| { - this.next_term_infer_of_kind(goal.predicate.term) - }); - let projection_pred = ty::ProjectionPredicate { - term, - projection_ty: goal.predicate.projection_ty, - }; + // We need to resolve vars here so that we correctly + // deal with `has_changed` in the next iteration. new_goals.normalizes_to_hack_goal = - Some(goal.with(this.tcx(), projection_pred)); - + Some(this.resolve_vars_if_possible(goal)); has_changed = has_changed.map_err(|c| c.unify_and(certainty)); } } } - for nested_goal in goals.goals.drain(..) { - let (changed, certainty, nested_goals) = - match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) { + for goal in goals.goals.drain(..) { + let (changed, certainty, instantiate_goals) = + match this.evaluate_goal(IsNormalizesToHack::No, goal) { Ok(result) => result, Err(NoSolution) => return Some(Err(NoSolution)), }; - new_goals.goals.extend(nested_goals); + new_goals.goals.extend(instantiate_goals); if changed { has_changed = Ok(()); @@ -341,7 +377,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { match certainty { Certainty::Yes => {} Certainty::Maybe(_) => { - new_goals.goals.push(nested_goal); + new_goals.goals.push(goal); has_changed = has_changed.map_err(|c| c.unify_and(certainty)); } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index fd2aa10caa23a..da713268f1123 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -34,16 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) } else { - let predicate = goal.predicate; - let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term); - let unconstrained_predicate = ProjectionPredicate { - projection_ty: goal.predicate.projection_ty, - term: unconstrained_rhs, - }; - - self.set_normalizes_to_hack_goal(goal.with(self.tcx(), unconstrained_predicate)); - self.try_evaluate_added_goals()?; - self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; + self.set_normalizes_to_hack_goal(goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 9817186b874cc..fcb965dd725af 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -214,9 +214,20 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( ty::Closure(_, substs) => { let closure_substs = substs.as_closure(); match closure_substs.kind_ty().to_opt_closure_kind() { - Some(closure_kind) if closure_kind.extends(goal_kind) => {} - None => return Ok(None), - _ => return Err(NoSolution), + // If the closure's kind doesn't extend the goal kind, + // then the closure doesn't implement the trait. + Some(closure_kind) => { + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + } + // Closure kind is not yet determined, so we return ambiguity unless + // the expected kind is `FnOnce` as that is always implemented. + None => { + if goal_kind != ty::ClosureKind::FnOnce { + return Ok(None); + } + } } Ok(Some(closure_substs.sig().map_bound(|sig| (sig.inputs()[0], sig.output())))) } diff --git a/tests/ui/attributes/no-mangle-closure.rs b/tests/ui/attributes/no-mangle-closure.rs new file mode 100644 index 0000000000000..c76baa27f38a0 --- /dev/null +++ b/tests/ui/attributes/no-mangle-closure.rs @@ -0,0 +1,11 @@ +// Check that we do not ICE when `no_mangle` is applied to something that has no name. + +#![crate_type = "lib"] +#![feature(stmt_expr_attributes)] + +pub struct S([usize; 8]); + +pub fn outer_function(x: S, y: S) -> usize { + (#[no_mangle] || y.0[0])() + //~^ ERROR `#[no_mangle]` cannot be used on a closure as it has no name +} diff --git a/tests/ui/attributes/no-mangle-closure.stderr b/tests/ui/attributes/no-mangle-closure.stderr new file mode 100644 index 0000000000000..949eb70510e4d --- /dev/null +++ b/tests/ui/attributes/no-mangle-closure.stderr @@ -0,0 +1,8 @@ +error: `#[no_mangle]` cannot be used on a closure as it has no name + --> $DIR/no-mangle-closure.rs:9:6 + | +LL | (#[no_mangle] || y.0[0])() + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/privacy/effective_visibilities.rs b/tests/ui/privacy/effective_visibilities.rs index ff20e20d33288..3e9eef462306c 100644 --- a/tests/ui/privacy/effective_visibilities.rs +++ b/tests/ui/privacy/effective_visibilities.rs @@ -1,3 +1,4 @@ +#![rustc_effective_visibility] //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub #![feature(rustc_attrs)] #[rustc_effective_visibility] diff --git a/tests/ui/privacy/effective_visibilities.stderr b/tests/ui/privacy/effective_visibilities.stderr index 046b6095f4e79..2618fc427e917 100644 --- a/tests/ui/privacy/effective_visibilities.stderr +++ b/tests/ui/privacy/effective_visibilities.stderr @@ -1,140 +1,152 @@ +error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub + --> $DIR/effective_visibilities.rs:1:1 + | +LL | / #![rustc_effective_visibility] +LL | | #![feature(rustc_attrs)] +LL | | +LL | | #[rustc_effective_visibility] +... | +LL | | +LL | | fn main() {} + | |____________^ + error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate) - --> $DIR/effective_visibilities.rs:4:1 + --> $DIR/effective_visibilities.rs:5:1 | LL | mod outer { | ^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:6:5 + --> $DIR/effective_visibilities.rs:7:5 | LL | pub mod inner1 { | ^^^^^^^^^^^^^^ error: not in the table - --> $DIR/effective_visibilities.rs:9:9 + --> $DIR/effective_visibilities.rs:10:9 | LL | extern "C" {} | ^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:12:9 + --> $DIR/effective_visibilities.rs:13:9 | LL | pub trait PubTrait { | ^^^^^^^^^^^^^^^^^^ error: Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self) - --> $DIR/effective_visibilities.rs:20:9 + --> $DIR/effective_visibilities.rs:21:9 | LL | struct PrivStruct; | ^^^^^^^^^^^^^^^^^ error: Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self) - --> $DIR/effective_visibilities.rs:20:9 + --> $DIR/effective_visibilities.rs:21:9 | LL | struct PrivStruct; | ^^^^^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:24:9 + --> $DIR/effective_visibilities.rs:25:9 | LL | pub union PubUnion { | ^^^^^^^^^^^^^^^^^^ error: Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self) - --> $DIR/effective_visibilities.rs:26:13 + --> $DIR/effective_visibilities.rs:27:13 | LL | a: u8, | ^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:28:13 + --> $DIR/effective_visibilities.rs:29:13 | LL | pub b: u8, | ^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:32:9 + --> $DIR/effective_visibilities.rs:33:9 | LL | pub enum Enum { | ^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:34:13 + --> $DIR/effective_visibilities.rs:35:13 | LL | A( | ^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:34:13 + --> $DIR/effective_visibilities.rs:35:13 | LL | A( | ^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:37:17 + --> $DIR/effective_visibilities.rs:38:17 | LL | PubUnion, | ^^^^^^^^ error: not in the table - --> $DIR/effective_visibilities.rs:43:5 + --> $DIR/effective_visibilities.rs:44:5 | LL | macro_rules! none_macro { | ^^^^^^^^^^^^^^^^^^^^^^^ error: Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:49:5 + --> $DIR/effective_visibilities.rs:50:5 | LL | macro_rules! public_macro { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:54:5 + --> $DIR/effective_visibilities.rs:55:5 | LL | pub struct ReachableStruct { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:56:9 + --> $DIR/effective_visibilities.rs:57:9 | LL | pub a: u8, | ^^^^^^^^^ error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:61:9 + --> $DIR/effective_visibilities.rs:62:9 | LL | pub use outer::inner1; | ^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:67:5 + --> $DIR/effective_visibilities.rs:68:5 | LL | pub type HalfPublicImport = u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate) - --> $DIR/effective_visibilities.rs:70:5 + --> $DIR/effective_visibilities.rs:71:5 | LL | pub(crate) const HalfPublicImport: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:74:9 + --> $DIR/effective_visibilities.rs:75:9 | LL | pub use half_public_import::HalfPublicImport; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:14:13 + --> $DIR/effective_visibilities.rs:15:13 | LL | const A: i32; | ^^^^^^^^^^^^ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub - --> $DIR/effective_visibilities.rs:16:13 + --> $DIR/effective_visibilities.rs:17:13 | LL | type B; | ^^^^^^ -error: aborting due to 23 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/traits/new-solver/closure-inference-guidance.rs b/tests/ui/traits/new-solver/closure-inference-guidance.rs new file mode 100644 index 0000000000000..d2ad0cc0316e3 --- /dev/null +++ b/tests/ui/traits/new-solver/closure-inference-guidance.rs @@ -0,0 +1,11 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +fn foo(i: isize) -> isize { i + 1 } + +fn apply(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) } + +pub fn main() { + let f = |i| foo(i); + assert_eq!(apply(f, 2), 3); +}