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:
commit
c1d3610ac1
17 changed files with 320 additions and 216 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()))))
|
||||
}
|
||||
|
|
11
tests/ui/attributes/no-mangle-closure.rs
Normal file
11
tests/ui/attributes/no-mangle-closure.rs
Normal 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
|
||||
}
|
8
tests/ui/attributes/no-mangle-closure.stderr
Normal file
8
tests/ui/attributes/no-mangle-closure.stderr
Normal 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
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#![rustc_effective_visibility] //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_effective_visibility]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
11
tests/ui/traits/new-solver/closure-inference-guidance.rs
Normal file
11
tests/ui/traits/new-solver/closure-inference-guidance.rs
Normal 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);
|
||||
}
|
Loading…
Add table
Reference in a new issue