diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh index fb828477f98b7..7c43d034d8b7f 100755 --- a/src/ci/publish_toolstate.sh +++ b/src/ci/publish_toolstate.sh @@ -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. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 2066a484dac80..fb534586fc615 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -341,6 +341,7 @@ impl Option { /// 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 Option { /// 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 Option { /// } /// ``` #[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 Option { /// } /// ``` #[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 Option> { // 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) } diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 5cfc81097dd44..b39abf917850d 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -957,6 +957,7 @@ impl Result { /// 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 Result { /// 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 Result { /// 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 Result { /// 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 Result, 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) } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index a2352c08e7316..fae95ca5cdb36 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -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. diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs deleted file mode 100644 index cc5131cb21795..0000000000000 --- a/src/librustc/ty/constness.rs +++ /dev/null @@ -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 { - 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 { - 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 - }; -} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7cca12308e65f..747e6e8da99af 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index ac04ae285884b..7b2ce7f9ac7be 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -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. diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/src/librustc_mir/const_eval/fn_queries.rs new file mode 100644 index 0000000000000..2443e1e91d378 --- /dev/null +++ b/src/librustc_mir/const_eval/fn_queries.rs @@ -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 { + 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 { + 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 + }; +} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 9f70f1dd57688..36c6568029d5f 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -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); diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 0aa42de538d2b..b818397247624 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -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) { diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 5cf5c54dd4878..d07e58b744771 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -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); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index b6656e720c5c3..00a39905c0232 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -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, diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 9dea44e020010..fcdabb29cd0e2 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -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!( diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 13df1892a5f17..84e6ff648a38f 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -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]); + } } } } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 309f72040615d..d090bf325038f 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -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")]) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2400dded66668..c7e0f1e9e704b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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, || { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bb46a15258e0f..be9654612f504 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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 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 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 diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 0af25efc04234..26b49d2f9624e 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -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, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 50d62027c8c6d..be7f7ea364f47 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index eeaac1d8c7431..91150899877fe 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -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 { 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") diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 803bcc2cfdf86..7ed531c9206af 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -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", }; diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index a4ca9010f2e9f..79548eb6d647a 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -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", }; diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index c6b22883e9723..c2185592d1483 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -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", }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 8a3966c320b8e..b1cd3deecb479 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -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", }; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index c00e231ef70a2..da0e97f1075b0 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -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", }; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index aebed9171d0e4..355ea15223b0c 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -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, +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 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, +/// The list of default passes run when `--doc-coverage` is passed to rustdoc. +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` is passed to rustdoc. -pub const DEFAULT_COVERAGE_PASSES: &[Pass] = - &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE]; +impl ConditionalPass { + pub const fn always(pass: Pass) -> Self { + Self::new(pass, Always) + } -/// 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]; + 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 { + PASSES.iter().find(|p| p.name == pass_name).copied() } struct Stripper<'a> { diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 23e272709705d..aec5a6bd4e221 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -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", }; diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index a296e73e3b5fd..64b0c45ba65d3 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -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", }; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 08a88c00cb0dd..f82e72b488bb7 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -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", }; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index af34842ad0f89..35b26fb8ab0be 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -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", }; diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index f4ec9cc364904..f244956e50336 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -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", }; diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 3212af055efc5..d4e09ce47a3c1 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -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", }; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index d2ee65f0a74eb..700e015b08edc 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -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 diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 4fa9095c89983..ab2a871b92df4 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -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)* } diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs index f102e4d6adf59..12bbfa1d4e1a6 100644 --- a/src/libstd/sys/vxworks/mod.rs +++ b/src/libstd/sys/vxworks/mod.rs @@ -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; diff --git a/src/libstd/sys/vxworks/weak.rs b/src/libstd/sys/vxworks/weak.rs deleted file mode 100644 index 4c6fddefd3f84..0000000000000 --- a/src/libstd/sys/vxworks/weak.rs +++ /dev/null @@ -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 { - name: &'static str, - addr: AtomicUsize, - _marker: marker::PhantomData, -} - -impl Weak { - pub const fn new(name: &'static str) -> Weak { - Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData } - } - - pub fn get(&self) -> Option { - assert_eq!(mem::size_of::(), mem::size_of::()); - 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::(&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 -} diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs index fc697026fe4f8..cce86fed9891c 100644 --- a/src/libsyntax/util/lev_distance.rs +++ b/src/libsyntax/util/lev_distance.rs @@ -54,14 +54,16 @@ where T: Iterator, { 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 { + 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("_") +} diff --git a/src/libsyntax/util/lev_distance/tests.rs b/src/libsyntax/util/lev_distance/tests.rs index f65f9275d0341..222661687c1c2 100644 --- a/src/libsyntax/util/lev_distance/tests.rs +++ b/src/libsyntax/util/lev_distance/tests.rs @@ -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")) + ); }) } diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 505d6ee769ab3..9ccc5d7882eb8 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -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; +} diff --git a/src/test/rustdoc/issue-46380.rs b/src/test/rustdoc/issue-46380.rs deleted file mode 100644 index 8837a6b463e88..0000000000000 --- a/src/test/rustdoc/issue-46380.rs +++ /dev/null @@ -1,5 +0,0 @@ -// compile-flags: --document-private-items - -// @has issue_46380/struct.Hidden.html -#[doc(hidden)] -pub struct Hidden; diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs new file mode 100644 index 0000000000000..d69b943173412 --- /dev/null +++ b/src/test/rustdoc/issue-67851-both.rs @@ -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; diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs new file mode 100644 index 0000000000000..8a3cafe4c3dc7 --- /dev/null +++ b/src/test/rustdoc/issue-67851-hidden.rs @@ -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; diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs new file mode 100644 index 0000000000000..4e3cd83285388 --- /dev/null +++ b/src/test/rustdoc/issue-67851-neither.rs @@ -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; diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs new file mode 100644 index 0000000000000..8addc7f3e4b53 --- /dev/null +++ b/src/test/rustdoc/issue-67851-private.rs @@ -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; diff --git a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs new file mode 100644 index 0000000000000..be13076b8af52 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs @@ -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("")); +} diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs new file mode 100644 index 0000000000000..440bb653a83c3 --- /dev/null +++ b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs @@ -0,0 +1,4 @@ +fn main() { + let a_longer_variable_name = 1; + println!("{}", a_variable_longer_name); //~ ERROR E0425 +} diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr new file mode 100644 index 0000000000000..d7b33ea41f79a --- /dev/null +++ b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr @@ -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`.