Auto merge of #68011 - JohnTitor:rollup-44s8twu, r=JohnTitor

Rollup of 10 pull requests

Successful merges:

 - #67774 (Try statx for all linux-gnu target.)
 - #67781 (Move `is_min_const_fn` query to librustc_mir.)
 - #67798 (Remove wrong advice about spin locks from `spin_loop_hint` docs)
 - #67849 (Add a check for swapped words when we can't find an identifier)
 - #67875 (Distinguish between private items and hidden items in rustdoc)
 - #67887 (`Option::{expect,unwrap}` and `Result::{expect, expect_err, unwrap, unwrap_err}` have `#[track_caller]`)
 - #67955 (rustdoc: Remove more `#[doc(cfg(..))]` duplicates)
 - #67977 (Updates for VxWorks)
 - #67985 (Remove insignificant notes from CStr documentation)
 - #68003 (ci: fix wrong shared.sh import for publish_toolstate)

Failed merges:

 - #67820 (Parse the syntax described in RFC 2632)
 - #67979 (Move `intravisit` => `rustc_hir` + misc cleanup)

r? @ghost
This commit is contained in:
bors 2020-01-08 19:46:58 +00:00
commit caa231d998
47 changed files with 538 additions and 386 deletions

View File

@ -3,7 +3,7 @@
set -euo pipefail
IFS=$'\n\t'
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
source "$(cd "$(dirname "$0")" && pwd)/shared.sh"
# The following lines are also found in src/bootstrap/toolstate.rs,
# so if updating here, please also update that file.

View File

@ -341,6 +341,7 @@ impl<T> Option<T> {
/// x.expect("the world is ending"); // panics with `the world is ending`
/// ```
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn expect(self, msg: &str) -> T {
match self {
@ -374,6 +375,7 @@ impl<T> Option<T> {
/// assert_eq!(x.unwrap(), "air"); // fails
/// ```
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap(self) -> T {
match self {
@ -1015,6 +1017,7 @@ impl<T: fmt::Debug> Option<T> {
/// }
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_expect_none", reason = "newly added", issue = "62633")]
pub fn expect_none(self, msg: &str) {
if let Some(val) = self {
@ -1057,6 +1060,7 @@ impl<T: fmt::Debug> Option<T> {
/// }
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_unwrap_none", reason = "newly added", issue = "62633")]
pub fn unwrap_none(self) {
if let Some(val) = self {
@ -1184,6 +1188,7 @@ impl<T, E> Option<Result<T, E>> {
// This is a separate function to reduce the code size of .expect() itself.
#[inline(never)]
#[cold]
#[track_caller]
fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}
@ -1191,6 +1196,7 @@ fn expect_failed(msg: &str) -> ! {
// This is a separate function to reduce the code size of .expect_none() itself.
#[inline(never)]
#[cold]
#[track_caller]
fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
panic!("{}: {:?}", msg, value)
}

View File

@ -957,6 +957,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
/// x.unwrap(); // panics with `emergency failure`
/// ```
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap(self) -> T {
match self {
@ -984,6 +985,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
/// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
/// ```
#[inline]
#[track_caller]
#[stable(feature = "result_expect", since = "1.4.0")]
pub fn expect(self, msg: &str) -> T {
match self {
@ -1017,6 +1019,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
/// assert_eq!(x.unwrap_err(), "emergency failure");
/// ```
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap_err(self) -> E {
match self {
@ -1044,6 +1047,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
/// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
/// ```
#[inline]
#[track_caller]
#[stable(feature = "result_expect_err", since = "1.17.0")]
pub fn expect_err(self, msg: &str) -> E {
match self {
@ -1188,6 +1192,7 @@ impl<T, E> Result<Option<T>, E> {
// This is a separate function to reduce the code size of the methods
#[inline(never)]
#[cold]
#[track_caller]
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
panic!("{}: {:?}", msg, error)
}

View File

@ -134,16 +134,10 @@ use crate::hint::spin_loop;
/// This function is different from [`std::thread::yield_now`] which directly yields to the
/// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system.
///
/// Spin locks can be very efficient for short lock durations because they do not involve context
/// switches or interaction with the operating system. For long lock durations they become wasteful
/// however because they use CPU cycles for the entire lock duration, and using a
/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is
/// required, e.g. because code polls a non-blocking API, calling [`std::thread::yield_now`]
/// or [`std::thread::sleep`] may be the best option.
///
/// **Note**: Spin locks are based on the underlying assumption that another thread will release
/// the lock 'soon'. In order for this to work, that other thread must run on a different CPU or
/// core (at least potentially). Spin locks do not work efficiently on single CPU / core platforms.
/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS
/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly
/// recommended that the spin loop is terminated after a finite amount of iterations and an
/// appropriate blocking syscall is made.
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.

View File

@ -1,156 +0,0 @@
use crate::hir::map::blocks::FnLikeNode;
use crate::ty::query::Providers;
use crate::ty::TyCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;
use syntax::attr;
impl<'tcx> TyCtxt<'tcx> {
/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(self, def_id: DefId) -> bool {
self.is_const_fn_raw(def_id)
&& match self.is_unstable_const_fn(def_id) {
Some(feature_name) => {
// has a `rustc_const_unstable` attribute, check whether the user enabled the
// corresponding feature gate.
self.features()
.declared_lib_features
.iter()
.any(|&(sym, _)| sym == feature_name)
}
// functions without const stability are either stable user written
// const fn or the user is using feature gates and we thus don't
// care what they do
None => true,
}
}
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
if self.is_const_fn_raw(def_id) {
let const_stab = self.lookup_const_stability(def_id)?;
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
} else {
None
}
}
/// Returns `true` if this function must conform to `min_const_fn`
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
// Bail out if the signature doesn't contain `const`
if !self.is_const_fn_raw(def_id) {
return false;
}
if self.features().staged_api {
// In order for a libstd function to be considered min_const_fn
// it needs to be stable and have no `rustc_const_unstable` attribute.
match self.lookup_const_stability(def_id) {
// `rustc_const_unstable` functions don't need to conform.
Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
None => {
if let Some(stab) = self.lookup_stability(def_id) {
if stab.level.is_stable() {
self.sess.span_err(
self.def_span(def_id),
"stable const functions must have either `rustc_const_stable` or \
`rustc_const_unstable` attribute",
);
// While we errored above, because we don't know if we need to conform, we
// err on the "safe" side and require min_const_fn.
true
} else {
// Unstable functions need not conform to min_const_fn.
false
}
} else {
// Internal functions are forced to conform to min_const_fn.
// Annotate the internal function with a const stability attribute if
// you need to use unstable features.
// Note: this is an arbitrary choice that does not affect stability or const
// safety or anything, it just changes whether we need to annotate some
// internal functions with `rustc_const_stable` or with `rustc_const_unstable`
true
}
}
// Everything else needs to conform, because it would be callable from
// other `min_const_fn` functions.
_ => true,
}
} else {
// users enabling the `const_fn` feature gate can do what they want
!self.features().const_fn
}
}
}
pub fn provide(providers: &mut Providers<'_>) {
/// Const evaluability whitelist is here to check evaluability at the
/// top level beforehand.
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
match tcx.fn_sig(def_id).abi() {
Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
Some(tcx.lookup_const_stability(def_id).is_some())
}
_ => None,
}
}
/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
/// said intrinsic is on the whitelist for being const callable.
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let hir_id = tcx
.hir()
.as_local_hir_id(def_id)
.expect("Non-local call to local provider is_const_fn");
let node = tcx.hir().get(hir_id);
if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
whitelisted
} else if let Some(fn_like) = FnLikeNode::from_node(node) {
fn_like.constness() == hir::Constness::Const
} else if let hir::Node::Ctor(_) = node {
true
} else {
false
}
}
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
tcx.is_const_fn(def_id)
&& match tcx.lookup_const_stability(def_id) {
Some(stab) => {
if cfg!(debug_assertions) && stab.promotable {
let sig = tcx.fn_sig(def_id);
assert_eq!(
sig.unsafety(),
hir::Unsafety::Normal,
"don't mark const unsafe fns as promotable",
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
);
}
stab.promotable
}
None => false,
}
}
fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
tcx.is_const_fn(def_id)
&& tcx
.lookup_const_stability(def_id)
.map(|stab| stab.allow_const_fn_ptr)
.unwrap_or(false)
}
*providers = Providers {
is_const_fn_raw,
is_promotable_const_fn,
const_fn_is_allowed_fn_ptr,
..*providers
};
}

View File

@ -97,7 +97,6 @@ pub mod cast;
#[macro_use]
pub mod codec;
pub mod _match;
mod constness;
mod erase_regions;
pub mod error;
pub mod fast_reject;
@ -3318,7 +3317,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
context::provide(providers);
erase_regions::provide(providers);
layout::provide(providers);
constness::provide(providers);
*providers = ty::query::Providers {
asyncness,
associated_item,

View File

@ -9,10 +9,12 @@ use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
mod error;
mod eval_queries;
mod fn_queries;
mod machine;
pub use error::*;
pub use eval_queries::*;
pub use fn_queries::*;
pub use machine::*;
/// Extracts a field of a (variant of a) const.

View File

@ -0,0 +1,151 @@
use rustc::hir::map::blocks::FnLikeNode;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;
use syntax::attr;
/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
tcx.is_const_fn_raw(def_id)
&& match is_unstable_const_fn(tcx, def_id) {
Some(feature_name) => {
// has a `rustc_const_unstable` attribute, check whether the user enabled the
// corresponding feature gate.
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
}
// functions without const stability are either stable user written
// const fn or the user is using feature gates and we thus don't
// care what they do
None => true,
}
}
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
if tcx.is_const_fn_raw(def_id) {
let const_stab = tcx.lookup_const_stability(def_id)?;
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
} else {
None
}
}
/// Returns `true` if this function must conform to `min_const_fn`
pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Bail out if the signature doesn't contain `const`
if !tcx.is_const_fn_raw(def_id) {
return false;
}
if tcx.features().staged_api {
// In order for a libstd function to be considered min_const_fn
// it needs to be stable and have no `rustc_const_unstable` attribute.
match tcx.lookup_const_stability(def_id) {
// `rustc_const_unstable` functions don't need to conform.
Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
None => {
if let Some(stab) = tcx.lookup_stability(def_id) {
if stab.level.is_stable() {
tcx.sess.span_err(
tcx.def_span(def_id),
"stable const functions must have either `rustc_const_stable` or \
`rustc_const_unstable` attribute",
);
// While we errored above, because we don't know if we need to conform, we
// err on the "safe" side and require min_const_fn.
true
} else {
// Unstable functions need not conform to min_const_fn.
false
}
} else {
// Internal functions are forced to conform to min_const_fn.
// Annotate the internal function with a const stability attribute if
// you need to use unstable features.
// Note: this is an arbitrary choice that does not affect stability or const
// safety or anything, it just changes whether we need to annotate some
// internal functions with `rustc_const_stable` or with `rustc_const_unstable`
true
}
}
// Everything else needs to conform, because it would be callable from
// other `min_const_fn` functions.
_ => true,
}
} else {
// users enabling the `const_fn` feature gate can do what they want
!tcx.features().const_fn
}
}
pub fn provide(providers: &mut Providers<'_>) {
/// Const evaluability whitelist is here to check evaluability at the
/// top level beforehand.
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
match tcx.fn_sig(def_id).abi() {
Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
Some(tcx.lookup_const_stability(def_id).is_some())
}
_ => None,
}
}
/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
/// said intrinsic is on the whitelist for being const callable.
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let hir_id = tcx
.hir()
.as_local_hir_id(def_id)
.expect("Non-local call to local provider is_const_fn");
let node = tcx.hir().get(hir_id);
if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
whitelisted
} else if let Some(fn_like) = FnLikeNode::from_node(node) {
fn_like.constness() == hir::Constness::Const
} else if let hir::Node::Ctor(_) = node {
true
} else {
false
}
}
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
is_const_fn(tcx, def_id)
&& match tcx.lookup_const_stability(def_id) {
Some(stab) => {
if cfg!(debug_assertions) && stab.promotable {
let sig = tcx.fn_sig(def_id);
assert_eq!(
sig.unsafety(),
hir::Unsafety::Normal,
"don't mark const unsafe fns as promotable",
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
);
}
stab.promotable
}
None => false,
}
}
fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
is_const_fn(tcx, def_id)
&& tcx
.lookup_const_stability(def_id)
.map(|stab| stab.allow_const_fn_ptr)
.unwrap_or(false)
}
*providers = Providers {
is_const_fn_raw,
is_promotable_const_fn,
const_fn_is_allowed_fn_ptr,
..*providers
};
}

View File

@ -52,6 +52,7 @@ use rustc::ty::query::Providers;
pub fn provide(providers: &mut Providers<'_>) {
borrow_check::provide(providers);
const_eval::provide(providers);
shim::provide(providers);
transform::provide(providers);
monomorphize::partitioning::provide(providers);

View File

@ -21,6 +21,7 @@ use super::ops::{self, NonConstOp};
use super::qualifs::{self, HasMutInterior, NeedsDrop};
use super::resolver::FlowSensitiveAnalysis;
use super::{is_lang_panic_fn, ConstKind, Item, Qualif};
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
use crate::dataflow::{self as old_dataflow, generic as dataflow};
pub type IndirectlyMutableResults<'mir, 'tcx> =
@ -173,7 +174,7 @@ impl Validator<'a, 'mir, 'tcx> {
let Item { tcx, body, def_id, const_kind, .. } = *self.item;
let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
&& tcx.is_min_const_fn(def_id))
&& crate::const_eval::is_min_const_fn(tcx, def_id))
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
if use_min_const_fn_checks {
@ -560,13 +561,13 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
};
// At this point, we are calling a function whose `DefId` is known...
if self.tcx.is_const_fn(def_id) {
if is_const_fn(self.tcx, def_id) {
return;
}
if is_lang_panic_fn(self.tcx, def_id) {
self.check_op(ops::Panic);
} else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
} else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
// Exempt unstable const fns inside of macros with
// `#[allow_internal_unstable]`.
if !self.span.allows_unstable(feature) {

View File

@ -14,6 +14,7 @@ use rustc_span::symbol::{sym, Symbol};
use std::ops::Bound;
use crate::const_eval::{is_const_fn, is_min_const_fn};
use crate::util;
use rustc_error_codes::*;
@ -523,7 +524,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
hir::BodyOwnerKind::Closure => (false, false),
hir::BodyOwnerKind::Fn => (tcx.is_const_fn(def_id), tcx.is_min_const_fn(def_id)),
hir::BodyOwnerKind::Fn => (is_const_fn(tcx, def_id), is_min_const_fn(tcx, def_id)),
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
};
let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);

View File

@ -29,6 +29,7 @@ use rustc_target::spec::abi::Abi;
use std::cell::Cell;
use std::{iter, mem, usize};
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
use crate::transform::{MirPass, MirSource};
@ -702,8 +703,8 @@ impl<'tcx> Validator<'_, 'tcx> {
let is_const_fn = match fn_ty.kind {
ty::FnDef(def_id, _) => {
self.tcx.is_const_fn(def_id)
|| self.tcx.is_unstable_const_fn(def_id).is_some()
is_const_fn(self.tcx, def_id)
|| is_unstable_const_fn(self.tcx, def_id).is_some()
|| is_lang_panic_fn(self.tcx, self.def_id)
}
_ => false,

View File

@ -327,7 +327,7 @@ fn check_terminator(
TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
let fn_ty = func.ty(body, tcx);
if let ty::FnDef(def_id, _) = fn_ty.kind {
if !tcx.is_min_const_fn(def_id) {
if !crate::const_eval::is_min_const_fn(tcx, def_id) {
return Err((
span,
format!(

View File

@ -202,23 +202,34 @@ impl ops::Not for Cfg {
impl ops::BitAndAssign for Cfg {
fn bitand_assign(&mut self, other: Cfg) {
if *self == other {
return;
}
match (self, other) {
(&mut Cfg::False, _) | (_, Cfg::True) => {}
(s, Cfg::False) => *s = Cfg::False,
(s @ &mut Cfg::True, b) => *s = b,
(&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => a.append(b),
(&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
(&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => {
for c in b.drain(..) {
if !a.contains(&c) {
a.push(c);
}
}
}
(&mut Cfg::All(ref mut a), ref mut b) => {
if !a.contains(b) {
a.push(mem::replace(b, Cfg::True));
}
}
(s, Cfg::All(mut a)) => {
let b = mem::replace(s, Cfg::True);
a.push(b);
if !a.contains(&b) {
a.push(b);
}
*s = Cfg::All(a);
}
(s, b) => {
let a = mem::replace(s, Cfg::True);
*s = Cfg::All(vec![a, b]);
if *s != b {
let a = mem::replace(s, Cfg::True);
*s = Cfg::All(vec![a, b]);
}
}
}
}
@ -234,23 +245,34 @@ impl ops::BitAnd for Cfg {
impl ops::BitOrAssign for Cfg {
fn bitor_assign(&mut self, other: Cfg) {
if *self == other {
return;
}
match (self, other) {
(&mut Cfg::True, _) | (_, Cfg::False) => {}
(s, Cfg::True) => *s = Cfg::True,
(s @ &mut Cfg::False, b) => *s = b,
(&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => a.append(b),
(&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
(&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => {
for c in b.drain(..) {
if !a.contains(&c) {
a.push(c);
}
}
}
(&mut Cfg::Any(ref mut a), ref mut b) => {
if !a.contains(b) {
a.push(mem::replace(b, Cfg::True));
}
}
(s, Cfg::Any(mut a)) => {
let b = mem::replace(s, Cfg::True);
a.push(b);
if !a.contains(&b) {
a.push(b);
}
*s = Cfg::Any(a);
}
(s, b) => {
let a = mem::replace(s, Cfg::True);
*s = Cfg::Any(vec![a, b]);
if *s != b {
let a = mem::replace(s, Cfg::True);
*s = Cfg::Any(vec![a, b]);
}
}
}
}

View File

@ -87,6 +87,12 @@ fn test_cfg_and() {
x &= word_cfg("test3");
assert_eq!(x, word_cfg("test3"));
x &= word_cfg("test3");
assert_eq!(x, word_cfg("test3"));
x &= word_cfg("test4");
assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
x &= word_cfg("test4");
assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
@ -105,6 +111,18 @@ fn test_cfg_and() {
])
);
x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
assert_eq!(
x,
Cfg::All(vec![
word_cfg("test3"),
word_cfg("test4"),
word_cfg("test5"),
word_cfg("test6"),
word_cfg("test7"),
])
);
let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
y &= x;
assert_eq!(
@ -119,6 +137,14 @@ fn test_cfg_and() {
])
);
let mut z = word_cfg("test8");
z &= Cfg::All(vec![word_cfg("test9"), word_cfg("test10")]);
assert_eq!(z, Cfg::All(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
let mut z = word_cfg("test11");
z &= Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]);
assert_eq!(z, Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]));
assert_eq!(
word_cfg("a") & word_cfg("b") & word_cfg("c"),
Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
@ -145,6 +171,12 @@ fn test_cfg_or() {
x |= word_cfg("test3");
assert_eq!(x, word_cfg("test3"));
x |= word_cfg("test3");
assert_eq!(x, word_cfg("test3"));
x |= word_cfg("test4");
assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
x |= word_cfg("test4");
assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
@ -163,6 +195,18 @@ fn test_cfg_or() {
])
);
x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
assert_eq!(
x,
Cfg::Any(vec![
word_cfg("test3"),
word_cfg("test4"),
word_cfg("test5"),
word_cfg("test6"),
word_cfg("test7"),
])
);
let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
y |= x;
assert_eq!(
@ -177,6 +221,14 @@ fn test_cfg_or() {
])
);
let mut z = word_cfg("test8");
z |= Cfg::Any(vec![word_cfg("test9"), word_cfg("test10")]);
assert_eq!(z, Cfg::Any(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
let mut z = word_cfg("test11");
z |= Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]);
assert_eq!(z, Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]));
assert_eq!(
word_cfg("a") | word_cfg("b") | word_cfg("c"),
Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])

View File

@ -9,6 +9,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::Mutability;
use rustc_metadata::creader::LoadedMacro;
use rustc_mir::const_eval::is_min_const_fn;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::sym;
use rustc_span::Span;
@ -212,7 +213,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
let sig = cx.tcx.fn_sig(did);
let constness =
if cx.tcx.is_min_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst };
if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
let asyncness = cx.tcx.asyncness(did);
let predicates = cx.tcx.predicates_of(did);
let (generics, decl) = clean::enter_impl_trait(cx, || {

View File

@ -21,6 +21,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
use rustc_index::vec::{Idx, IndexVec};
use rustc_mir::const_eval::is_min_const_fn;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym};
use rustc_span::{self, Pos};
@ -895,7 +896,7 @@ impl Clean<Item> for doctree::Function<'_> {
enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx)));
let did = cx.tcx.hir().local_def_id(self.id);
let constness = if cx.tcx.is_min_const_fn(did) {
let constness = if is_min_const_fn(cx.tcx, did) {
hir::Constness::Const
} else {
hir::Constness::NotConst
@ -1187,7 +1188,7 @@ impl Clean<Item> for ty::AssocItem {
};
let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
if provided {
let constness = if cx.tcx.is_min_const_fn(self.def_id) {
let constness = if is_min_const_fn(cx.tcx, self.def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst

View File

@ -24,7 +24,7 @@ use crate::html;
use crate::html::markdown::IdMap;
use crate::html::static_files;
use crate::opts;
use crate::passes::{self, DefaultPassOption};
use crate::passes::{self, Condition, DefaultPassOption};
use crate::theme;
/// Configuration options for rustdoc.
@ -98,6 +98,10 @@ pub struct Options {
///
/// Be aware: This option can come both from the CLI and from crate attributes!
pub default_passes: DefaultPassOption,
/// Document items that have lower than `pub` visibility.
pub document_private: bool,
/// Document items that have `doc(hidden)`.
pub document_hidden: bool,
/// Any passes manually selected by the user.
///
/// Be aware: This option can come both from the CLI and from crate attributes!
@ -146,6 +150,8 @@ impl fmt::Debug for Options {
.field("test_args", &self.test_args)
.field("persist_doctests", &self.persist_doctests)
.field("default_passes", &self.default_passes)
.field("document_private", &self.document_private)
.field("document_hidden", &self.document_hidden)
.field("manual_passes", &self.manual_passes)
.field("display_warnings", &self.display_warnings)
.field("show_coverage", &self.show_coverage)
@ -240,22 +246,26 @@ impl Options {
println!("{:>20} - {}", pass.name, pass.description);
}
println!("\nDefault passes for rustdoc:");
for pass in passes::DEFAULT_PASSES {
println!("{:>20}", pass.name);
}
println!("\nPasses run with `--document-private-items`:");
for pass in passes::DEFAULT_PRIVATE_PASSES {
println!("{:>20}", pass.name);
for p in passes::DEFAULT_PASSES {
print!("{:>20}", p.pass.name);
println_condition(p.condition);
}
if nightly_options::is_nightly_build() {
println!("\nPasses run with `--show-coverage`:");
for pass in passes::DEFAULT_COVERAGE_PASSES {
println!("{:>20}", pass.name);
for p in passes::COVERAGE_PASSES {
print!("{:>20}", p.pass.name);
println_condition(p.condition);
}
println!("\nPasses run with `--show-coverage --document-private-items`:");
for pass in passes::PRIVATE_COVERAGE_PASSES {
println!("{:>20}", pass.name);
}
fn println_condition(condition: Condition) {
use Condition::*;
match condition {
Always => println!(),
WhenDocumentPrivate => println!(" (when --document-private-items)"),
WhenNotDocumentPrivate => println!(" (when not --document-private-items)"),
WhenNotDocumentHidden => println!(" (when not --document-hidden-items)"),
}
}
@ -444,16 +454,11 @@ impl Options {
});
let show_coverage = matches.opt_present("show-coverage");
let document_private = matches.opt_present("document-private-items");
let default_passes = if matches.opt_present("no-defaults") {
passes::DefaultPassOption::None
} else if show_coverage && document_private {
passes::DefaultPassOption::PrivateCoverage
} else if show_coverage {
passes::DefaultPassOption::Coverage
} else if document_private {
passes::DefaultPassOption::Private
} else {
passes::DefaultPassOption::Default
};
@ -492,6 +497,8 @@ impl Options {
let runtool = matches.opt_str("runtool");
let runtool_args = matches.opt_strs("runtool-arg");
let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
let document_private = matches.opt_present("document-private-items");
let document_hidden = matches.opt_present("document-hidden-items");
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
@ -518,6 +525,8 @@ impl Options {
should_test,
test_args,
default_passes,
document_private,
document_hidden,
manual_passes,
display_warnings,
show_coverage,

View File

@ -33,7 +33,7 @@ use crate::clean::{AttributesExt, MAX_DEF_ID};
use crate::config::{Options as RustdocOptions, RenderOptions};
use crate::html::render::RenderInfo;
use crate::passes;
use crate::passes::{self, Condition::*, ConditionalPass};
pub use rustc::session::config::{CodegenOptions, DebuggingOptions, Input, Options};
pub use rustc::session::search_paths::SearchPath;
@ -221,6 +221,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
describe_lints,
lint_cap,
mut default_passes,
mut document_private,
document_hidden,
mut manual_passes,
display_warnings,
render_options,
@ -457,16 +459,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
}
if attr.is_word() && name == sym::document_private_items {
if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::Private;
}
document_private = true;
}
}
let passes = passes::defaults(default_passes).iter().chain(
let passes = passes::defaults(default_passes).iter().copied().chain(
manual_passes.into_iter().flat_map(|name| {
if let Some(pass) = passes::find_pass(&name) {
Some(pass)
Some(ConditionalPass::always(pass))
} else {
error!("unknown pass {}, skipping", name);
None
@ -476,9 +476,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
info!("Executing passes");
for pass in passes {
debug!("running pass {}", pass.name);
krate = (pass.pass)(krate, &ctxt);
for p in passes {
let run = match p.condition {
Always => true,
WhenDocumentPrivate => document_private,
WhenNotDocumentPrivate => !document_private,
WhenNotDocumentHidden => !document_hidden,
};
if run {
debug!("running pass {}", p.pass.name);
krate = (p.pass.run)(krate, &ctxt);
}
}
ctxt.sess().abort_if_errors();

View File

@ -32,6 +32,7 @@ extern crate rustc_interface;
extern crate rustc_lexer;
extern crate rustc_lint;
extern crate rustc_metadata;
extern crate rustc_mir;
extern crate rustc_parse;
extern crate rustc_resolve;
extern crate rustc_span as rustc_span;
@ -173,6 +174,9 @@ fn opts() -> Vec<RustcOptGroup> {
stable("document-private-items", |o| {
o.optflag("", "document-private-items", "document private items")
}),
unstable("document-hidden-items", |o| {
o.optflag("", "document-hidden-items", "document items that have doc(hidden)")
}),
stable("test", |o| o.optflag("", "test", "run code examples as tests")),
stable("test-args", |o| {
o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")

View File

@ -12,7 +12,7 @@ use std::ops;
pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
name: "calculate-doc-coverage",
pass: calculate_doc_coverage,
run: calculate_doc_coverage,
description: "counts the number of items with and without documentation",
};

View File

@ -14,7 +14,7 @@ use crate::passes::Pass;
pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
name: "check-code-block-syntax",
pass: check_code_block_syntax,
run: check_code_block_syntax,
description: "validates syntax inside Rust code blocks",
};

View File

@ -8,7 +8,7 @@ use std::mem::take;
pub const COLLAPSE_DOCS: Pass = Pass {
name: "collapse-docs",
pass: collapse_docs,
run: collapse_docs,
description: "concatenates all document attributes into one document attribute",
};

View File

@ -28,7 +28,7 @@ use super::span_of_attrs;
pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
name: "collect-intra-doc-links",
pass: collect_intra_doc_links,
run: collect_intra_doc_links,
description: "reads a crate's documentation to resolve intra-doc-links",
};

View File

@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
name: "collect-trait-impls",
pass: collect_trait_impls,
run: collect_trait_impls,
description: "retrieves trait impls for items in the crate",
};

View File

@ -8,6 +8,7 @@ use rustc_span::{InnerSpan, Span, DUMMY_SP};
use std::mem;
use std::ops::Range;
use self::Condition::*;
use crate::clean::{self, GetDefId, Item};
use crate::core::DocContext;
use crate::fold::{DocFolder, StripItem};
@ -52,10 +53,29 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
#[derive(Copy, Clone)]
pub struct Pass {
pub name: &'static str,
pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
pub description: &'static str,
}
/// In a list of passes, a pass that may or may not need to be run depending on options.
#[derive(Copy, Clone)]
pub struct ConditionalPass {
pub pass: Pass,
pub condition: Condition,
}
/// How to decide whether to run a conditional pass.
#[derive(Copy, Clone)]
pub enum Condition {
Always,
/// When `--document-private-items` is passed.
WhenDocumentPrivate,
/// When `--document-private-items` is not passed.
WhenNotDocumentPrivate,
/// When `--document-hidden-items` is not passed.
WhenNotDocumentHidden,
}
/// The full list of passes.
pub const PASSES: &[Pass] = &[
CHECK_PRIVATE_ITEMS_DOC_TESTS,
@ -72,63 +92,58 @@ pub const PASSES: &[Pass] = &[
];
/// The list of passes run by default.
pub const DEFAULT_PASSES: &[Pass] = &[
COLLECT_TRAIT_IMPLS,
COLLAPSE_DOCS,
UNINDENT_COMMENTS,
CHECK_PRIVATE_ITEMS_DOC_TESTS,
STRIP_HIDDEN,
STRIP_PRIVATE,
COLLECT_INTRA_DOC_LINKS,
CHECK_CODE_BLOCK_SYNTAX,
PROPAGATE_DOC_CFG,
];
/// The list of default passes run with `--document-private-items` is passed to rustdoc.
pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[
COLLECT_TRAIT_IMPLS,
COLLAPSE_DOCS,
UNINDENT_COMMENTS,
CHECK_PRIVATE_ITEMS_DOC_TESTS,
STRIP_PRIV_IMPORTS,
COLLECT_INTRA_DOC_LINKS,
CHECK_CODE_BLOCK_SYNTAX,
PROPAGATE_DOC_CFG,
pub const DEFAULT_PASSES: &[ConditionalPass] = &[
ConditionalPass::always(COLLECT_TRAIT_IMPLS),
ConditionalPass::always(COLLAPSE_DOCS),
ConditionalPass::always(UNINDENT_COMMENTS),
ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS),
ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
ConditionalPass::always(PROPAGATE_DOC_CFG),
];
/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
pub const DEFAULT_COVERAGE_PASSES: &[Pass] =
&[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE];
pub const COVERAGE_PASSES: &[ConditionalPass] = &[
ConditionalPass::always(COLLECT_TRAIT_IMPLS),
ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
ConditionalPass::always(CALCULATE_DOC_COVERAGE),
];
/// The list of default passes run when `--doc-coverage --document-private-items` is passed to
/// rustdoc.
pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE];
impl ConditionalPass {
pub const fn always(pass: Pass) -> Self {
Self::new(pass, Always)
}
pub const fn new(pass: Pass, condition: Condition) -> Self {
ConditionalPass { pass, condition }
}
}
/// A shorthand way to refer to which set of passes to use, based on the presence of
/// `--no-defaults` or `--document-private-items`.
/// `--no-defaults` and `--show-coverage`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DefaultPassOption {
Default,
Private,
Coverage,
PrivateCoverage,
None,
}
/// Returns the given default set of passes.
pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] {
pub fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] {
match default_set {
DefaultPassOption::Default => DEFAULT_PASSES,
DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES,
DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES,
DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES,
DefaultPassOption::Coverage => COVERAGE_PASSES,
DefaultPassOption::None => &[],
}
}
/// If the given name matches a known pass, returns its information.
pub fn find_pass(pass_name: &str) -> Option<&'static Pass> {
PASSES.iter().find(|p| p.name == pass_name)
pub fn find_pass(pass_name: &str) -> Option<Pass> {
PASSES.iter().find(|p| p.name == pass_name).copied()
}
struct Stripper<'a> {

View File

@ -5,7 +5,7 @@ use crate::passes::{look_for_tests, Pass};
pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
name: "check-private-items-doc-tests",
pass: check_private_items_doc_tests,
run: check_private_items_doc_tests,
description: "check private items doc tests",
};

View File

@ -8,7 +8,7 @@ use crate::passes::Pass;
pub const PROPAGATE_DOC_CFG: Pass = Pass {
name: "propagate-doc-cfg",
pass: propagate_doc_cfg,
run: propagate_doc_cfg,
description: "propagates `#[doc(cfg(...))]` to child items",
};

View File

@ -10,7 +10,7 @@ use crate::passes::{ImplStripper, Pass};
pub const STRIP_HIDDEN: Pass = Pass {
name: "strip-hidden",
pass: strip_hidden,
run: strip_hidden,
description: "strips all doc(hidden) items from the output",
};

View File

@ -5,7 +5,7 @@ use crate::passes::{ImportStripper, Pass};
pub const STRIP_PRIV_IMPORTS: Pass = Pass {
name: "strip-priv-imports",
pass: strip_priv_imports,
run: strip_priv_imports,
description: "strips all private import statements (`use`, `extern crate`) from a crate",
};

View File

@ -7,7 +7,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
pub const STRIP_PRIVATE: Pass = Pass {
name: "strip-private",
pass: strip_private,
run: strip_private,
description: "strips all private items from a crate which cannot be seen externally, \
implies strip-priv-imports",
};

View File

@ -12,7 +12,7 @@ mod tests;
pub const UNINDENT_COMMENTS: Pass = Pass {
name: "unindent-comments",
pass: unindent_comments,
run: unindent_comments,
description: "removes excess indentation on comments in order for markdown to like it",
};

View File

@ -1187,11 +1187,6 @@ impl CStr {
/// function will return the corresponding [`&str`] slice. Otherwise,
/// it will return an error with details of where UTF-8 validation failed.
///
/// > **Note**: This method is currently implemented to check for validity
/// > after a constant-time cast, but it is planned to alter its definition
/// > in the future to perform the length calculation in addition to the
/// > UTF-8 check whenever this method is called.
///
/// [`&str`]: ../primitive.str.html
///
/// # Examples
@ -1220,11 +1215,6 @@ impl CStr {
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
/// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
///
/// > **Note**: This method is currently implemented to check for validity
/// > after a constant-time cast, but it is planned to alter its definition
/// > in the future to perform the length calculation in addition to the
/// > UTF-8 check whenever this method is called.
///
/// [`Cow`]: ../borrow/enum.Cow.html
/// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
/// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned

View File

@ -51,24 +51,14 @@ pub use crate::sys_common::fs::remove_dir_all;
pub struct File(FileDesc);
// FIXME: This should be available on Linux with all `target_arch` and `target_env`.
// https://github.com/rust-lang/libc/issues/1545
// FIXME: This should be available on Linux with all `target_env`.
// But currently only glibc exposes `statx` fn and structs.
// We don't want to import unverified raw C structs here directly.
// https://github.com/rust-lang/rust/pull/67774
macro_rules! cfg_has_statx {
({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
cfg_if::cfg_if! {
if #[cfg(all(target_os = "linux", target_env = "gnu", any(
target_arch = "x86",
target_arch = "arm",
// target_arch = "mips",
target_arch = "powerpc",
target_arch = "x86_64",
// target_arch = "aarch64",
target_arch = "powerpc64",
// target_arch = "mips64",
// target_arch = "s390x",
target_arch = "sparc64",
target_arch = "riscv64",
)))] {
if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
$($then_tt)*
} else {
$($else_tt)*
@ -76,19 +66,7 @@ macro_rules! cfg_has_statx {
}
};
($($block_inner:tt)*) => {
#[cfg(all(target_os = "linux", target_env = "gnu", any(
target_arch = "x86",
target_arch = "arm",
// target_arch = "mips",
target_arch = "powerpc",
target_arch = "x86_64",
// target_arch = "aarch64",
target_arch = "powerpc64",
// target_arch = "mips64",
// target_arch = "s390x",
target_arch = "sparc64",
target_arch = "riscv64",
)))]
#[cfg(all(target_os = "linux", target_env = "gnu"))]
{
$($block_inner)*
}

View File

@ -36,18 +36,10 @@ pub use crate::sys_common::os_str_bytes as os_str;
#[cfg(not(test))]
pub fn init() {
// By default, some platforms will send a *signal* when an EPIPE error
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
// handler, causing it to kill the program, which isn't exactly what we
// want!
//
// Hence, we set SIGPIPE to ignore when the program starts up in order
// to prevent this problem.
// ignore SIGPIPE
unsafe {
reset_sigpipe();
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
}
unsafe fn reset_sigpipe() {}
}
pub use libc::signal;

View File

@ -1,56 +0,0 @@
//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).
use crate::ffi::CStr;
use crate::marker;
use crate::mem;
use crate::sync::atomic::{AtomicUsize, Ordering};
pub struct Weak<F> {
name: &'static str,
addr: AtomicUsize,
_marker: marker::PhantomData<F>,
}
impl<F> Weak<F> {
pub const fn new(name: &'static str) -> Weak<F> {
Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
}
pub fn get(&self) -> Option<F> {
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
unsafe {
if self.addr.load(Ordering::SeqCst) == 1 {
self.addr.store(fetch(self.name), Ordering::SeqCst);
}
match self.addr.load(Ordering::SeqCst) {
0 => None,
addr => Some(mem::transmute_copy::<usize, F>(&addr)),
}
}
}
}
unsafe fn fetch(name: &str) -> usize {
let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
Ok(cstr) => cstr,
Err(..) => return 0,
};
assert!(false, "FIXME: fetch");
libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

View File

@ -54,14 +54,16 @@ where
T: Iterator<Item = &'a Symbol>,
{
let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
let name_vec: Vec<&Symbol> = iter_names.collect();
let (case_insensitive_match, levenstein_match) = iter_names
let (case_insensitive_match, levenshtein_match) = name_vec
.iter()
.filter_map(|&name| {
let dist = lev_distance(lookup, &name.as_str());
if dist <= max_dist { Some((name, dist)) } else { None }
})
// Here we are collecting the next structure:
// (case_insensitive_match, (levenstein_match, levenstein_distance))
// (case_insensitive_match, (levenshtein_match, levenshtein_distance))
.fold((None, None), |result, (candidate, dist)| {
(
if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
@ -75,10 +77,31 @@ where
},
)
});
// Priority of matches:
// 1. Exact case insensitive match
// 2. Levenshtein distance match
// 3. Sorted word match
if let Some(candidate) = case_insensitive_match {
Some(candidate) // exact case insensitive match has a higher priority
Some(*candidate)
} else if levenshtein_match.is_some() {
levenshtein_match.map(|(candidate, _)| *candidate)
} else {
levenstein_match.map(|(candidate, _)| candidate)
find_match_by_sorted_words(name_vec, lookup)
}
}
fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option<Symbol> {
iter_names.iter().fold(None, |result, candidate| {
if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
Some(**candidate)
} else {
result
}
})
}
fn sort_by_words(name: &str) -> String {
let mut split_words: Vec<&str> = name.split('_').collect();
split_words.sort();
split_words.join("_")
}

View File

@ -46,5 +46,11 @@ fn test_find_best_match_for_name() {
find_best_match_for_name(input.iter(), "aaaa", Some(4)),
Some(Symbol::intern("AAAA"))
);
let input = vec![Symbol::intern("a_longer_variable_name")];
assert_eq!(
find_best_match_for_name(input.iter(), "a_variable_longer_name", None),
Some(Symbol::intern("a_longer_variable_name"))
);
})
}

View File

@ -1,15 +1,42 @@
// ignore-tidy-linelength
#![crate_name = "foo"]
#![feature(doc_cfg)]
// @has 'foo/index.html'
// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
// @has 'foo/struct.Foo.html'
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
#[doc(cfg(feature = "sync"))]
#[doc(cfg(feature = "sync"))]
pub struct Foo;
// @has 'foo/bar/struct.Bar.html'
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
#[doc(cfg(feature = "sync"))]
pub mod bar {
#[doc(cfg(feature = "sync"))]
pub struct Bar;
}
// @has 'foo/baz/struct.Baz.html'
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.'
#[doc(cfg(all(feature = "sync", feature = "send")))]
pub mod baz {
#[doc(cfg(feature = "sync"))]
pub struct Baz;
}
// @has 'foo/qux/struct.Qux.html'
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.'
#[doc(cfg(feature = "sync"))]
pub mod qux {
#[doc(cfg(all(feature = "sync", feature = "send")))]
pub struct Qux;
}
// @has 'foo/quux/struct.Quux.html'
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" and foo and bar only.'
#[doc(cfg(all(feature = "sync", feature = "send", foo)))]
pub mod quux {
#[doc(cfg(all(feature = "send", feature = "sync", bar)))]
pub struct Quux;
}

View File

@ -1,5 +0,0 @@
// compile-flags: --document-private-items
// @has issue_46380/struct.Hidden.html
#[doc(hidden)]
pub struct Hidden;

View File

@ -0,0 +1,8 @@
// compile-flags: -Zunstable-options --document-private-items --document-hidden-items
// @has issue_67851_both/struct.Hidden.html
#[doc(hidden)]
pub struct Hidden;
// @has issue_67851_both/struct.Private.html
struct Private;

View File

@ -0,0 +1,8 @@
// compile-flags: -Zunstable-options --document-hidden-items
// @has issue_67851_hidden/struct.Hidden.html
#[doc(hidden)]
pub struct Hidden;
// @!has issue_67851_hidden/struct.Private.html
struct Private;

View File

@ -0,0 +1,6 @@
// @!has issue_67851_neither/struct.Hidden.html
#[doc(hidden)]
pub struct Hidden;
// @!has issue_67851_neither/struct.Private.html
struct Private;

View File

@ -0,0 +1,8 @@
// compile-flags: --document-private-items
// @!has issue_67851_private/struct.Hidden.html
#[doc(hidden)]
pub struct Hidden;
// @has issue_67851_private/struct.Private.html
struct Private;

View File

@ -0,0 +1,38 @@
// run-pass
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(option_expect_none, option_unwrap_none)]
//! Test that panic locations for `#[track_caller]` functions in std have the correct
//! location reported.
fn main() {
// inspect the `PanicInfo` we receive to ensure the right file is the source
std::panic::set_hook(Box::new(|info| {
let actual = info.location().unwrap();
if actual.file() != file!() {
eprintln!("expected a location in the test file, found {:?}", actual);
panic!();
}
}));
fn assert_panicked(f: impl FnOnce() + std::panic::UnwindSafe) {
std::panic::catch_unwind(f).unwrap_err();
}
let nope: Option<()> = None;
assert_panicked(|| nope.unwrap());
assert_panicked(|| nope.expect(""));
let yep: Option<()> = Some(());
assert_panicked(|| yep.unwrap_none());
assert_panicked(|| yep.expect_none(""));
let oops: Result<(), ()> = Err(());
assert_panicked(|| oops.unwrap());
assert_panicked(|| oops.expect(""));
let fine: Result<(), ()> = Ok(());
assert_panicked(|| fine.unwrap_err());
assert_panicked(|| fine.expect_err(""));
}

View File

@ -0,0 +1,4 @@
fn main() {
let a_longer_variable_name = 1;
println!("{}", a_variable_longer_name); //~ ERROR E0425
}

View File

@ -0,0 +1,9 @@
error[E0425]: cannot find value `a_variable_longer_name` in this scope
--> $DIR/issue-66968-suggest-sorted-words.rs:3:20
|
LL | println!("{}", a_variable_longer_name);
| ^^^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `a_longer_variable_name`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.