Auto merge of #109791 - compiler-errors:rollup-c3o710k, r=compiler-errors

Rollup of 6 pull requests

Successful merges:

 - #109347 (Skip no_mangle if the item has no name.)
 - #109522 (Implement current_dll_path for AIX)
 - #109679 (Freshen normalizes-to hack goal RHS in the evaluate loop)
 - #109704 (resolve: Minor improvements to effective visibilities)
 - #109739 (Closures always implement `FnOnce` in new solver)
 - #109758 (Parallel compiler cleanups)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-30 22:02:10 +00:00
commit c1d3610ac1
17 changed files with 320 additions and 216 deletions

View file

@ -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;
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
}
Some(sym::cfi) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
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::kcfi) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
}
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();
}
}
}

View file

@ -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>(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<T> {
shards: [CacheAligned<Lock<T>>; SHARDS],
}

View file

@ -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<T>` | `rc::Rc<T>` | `sync::Arc<T>` |
//! |` Weak<T>` | `rc::Weak<T>` | `sync::Weak<T>` |
//! | | | |
//! | `AtomicBool` | `Cell<bool>` | `atomic::AtomicBool` |
//! | `AtomicU32` | `Cell<u32>` | `atomic::AtomicU32` |
//! | `AtomicU64` | `Cell<u64>` | `atomic::AtomicU64` |
//! | `AtomicUsize` | `Cell<usize>` | `atomic::AtomicUsize` |
//! | | | |
//! | `Lock<T>` | `RefCell<T>` | `parking_lot::Mutex<T>` |
//! | `RwLock<T>` | `RefCell<T>` | `parking_lot::RwLock<T>` |
//! | `MTLock<T>` [^1] | `T` | `Lock<T>` |
//! | `MTLockRef<'a, T>` [^2] | `&'a mut MTLock<T>` | `&'a MTLock<T>` |
//! | | | |
//! | `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<T>;
#[derive(Debug, Default)]
pub struct MTLock<T>(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<T>;
#[derive(Debug, Default)]
pub struct MTLock<T>(Lock<T>);
@ -553,18 +578,6 @@ impl<T> RwLock<T> {
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 {

View file

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

View file

@ -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<MonoItem<
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
starting_point: Spanned<MonoItem<'tcx>>,
visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
visited: MTLockRef<'_, FxHashSet<MonoItem<'tcx>>>,
recursion_depths: &mut DefIdMap<usize>,
recursion_limit: Limit,
inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
inlining_map: MTLockRef<'_, InliningMap<'tcx>>,
) {
if !visited.lock_mut().insert(starting_point.node) {
// We've been here already, no need to search again.

View file

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

View file

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

View file

@ -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);
// 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);
parent_id = ParentId::Import(binding_id);
binding = nested_binding;
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;
}
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);
}
} 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);
parent_id = ParentId::Import(binding_id);
binding = nested_binding;
}
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;
}
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);
}
}

View file

@ -68,6 +68,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
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<PathBuf, String> {
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::<libc::ld_info>(); 64];
loop {
if libc::loadquery(
libc::L_GETINFO,
buffer.as_mut_ptr() as *mut i8,
(std::mem::size_of::<libc::ld_info>() * 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::<libc::ld_info>());
}
}
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)]

View file

@ -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<Goal<'tcx, ty::ProjectionPredicate<'tcx>>>,
/// The rest of the goals which have not yet processed or remain ambiguous.
pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}
@ -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));
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
#![rustc_effective_visibility] //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
#![feature(rustc_attrs)]
#[rustc_effective_visibility]

View file

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

View file

@ -0,0 +1,11 @@
// compile-flags: -Ztrait-solver=next
// check-pass
fn foo(i: isize) -> isize { i + 1 }
fn apply<A, F>(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);
}