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:
commit
caa231d998
|
@ -3,7 +3,7 @@
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
IFS=$'\n\t'
|
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,
|
# The following lines are also found in src/bootstrap/toolstate.rs,
|
||||||
# so if updating here, please also update that file.
|
# so if updating here, please also update that file.
|
||||||
|
|
|
@ -341,6 +341,7 @@ impl<T> Option<T> {
|
||||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn expect(self, msg: &str) -> T {
|
pub fn expect(self, msg: &str) -> T {
|
||||||
match self {
|
match self {
|
||||||
|
@ -374,6 +375,7 @@ impl<T> Option<T> {
|
||||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn unwrap(self) -> T {
|
pub fn unwrap(self) -> T {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1015,6 +1017,7 @@ impl<T: fmt::Debug> Option<T> {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[unstable(feature = "option_expect_none", reason = "newly added", issue = "62633")]
|
#[unstable(feature = "option_expect_none", reason = "newly added", issue = "62633")]
|
||||||
pub fn expect_none(self, msg: &str) {
|
pub fn expect_none(self, msg: &str) {
|
||||||
if let Some(val) = self {
|
if let Some(val) = self {
|
||||||
|
@ -1057,6 +1060,7 @@ impl<T: fmt::Debug> Option<T> {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[unstable(feature = "option_unwrap_none", reason = "newly added", issue = "62633")]
|
#[unstable(feature = "option_unwrap_none", reason = "newly added", issue = "62633")]
|
||||||
pub fn unwrap_none(self) {
|
pub fn unwrap_none(self) {
|
||||||
if let Some(val) = 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.
|
// This is a separate function to reduce the code size of .expect() itself.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
|
#[track_caller]
|
||||||
fn expect_failed(msg: &str) -> ! {
|
fn expect_failed(msg: &str) -> ! {
|
||||||
panic!("{}", msg)
|
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.
|
// This is a separate function to reduce the code size of .expect_none() itself.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
|
#[track_caller]
|
||||||
fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
|
fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
|
||||||
panic!("{}: {:?}", msg, value)
|
panic!("{}: {:?}", msg, value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -957,6 +957,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
|
||||||
/// x.unwrap(); // panics with `emergency failure`
|
/// x.unwrap(); // panics with `emergency failure`
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn unwrap(self) -> T {
|
pub fn unwrap(self) -> T {
|
||||||
match self {
|
match self {
|
||||||
|
@ -984,6 +985,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
|
||||||
/// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
|
/// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[stable(feature = "result_expect", since = "1.4.0")]
|
#[stable(feature = "result_expect", since = "1.4.0")]
|
||||||
pub fn expect(self, msg: &str) -> T {
|
pub fn expect(self, msg: &str) -> T {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1017,6 +1019,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
|
||||||
/// assert_eq!(x.unwrap_err(), "emergency failure");
|
/// assert_eq!(x.unwrap_err(), "emergency failure");
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn unwrap_err(self) -> E {
|
pub fn unwrap_err(self) -> E {
|
||||||
match self {
|
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`
|
/// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
#[stable(feature = "result_expect_err", since = "1.17.0")]
|
#[stable(feature = "result_expect_err", since = "1.17.0")]
|
||||||
pub fn expect_err(self, msg: &str) -> E {
|
pub fn expect_err(self, msg: &str) -> E {
|
||||||
match self {
|
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
|
// This is a separate function to reduce the code size of the methods
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
|
#[track_caller]
|
||||||
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
|
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
|
||||||
panic!("{}: {:?}", msg, error)
|
panic!("{}: {:?}", msg, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,16 +134,10 @@ use crate::hint::spin_loop;
|
||||||
/// This function is different from [`std::thread::yield_now`] which directly yields to the
|
/// 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.
|
/// 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
|
/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS
|
||||||
/// switches or interaction with the operating system. For long lock durations they become wasteful
|
/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly
|
||||||
/// however because they use CPU cycles for the entire lock duration, and using a
|
/// recommended that the spin loop is terminated after a finite amount of iterations and an
|
||||||
/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is
|
/// appropriate blocking syscall is made.
|
||||||
/// 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.
|
|
||||||
///
|
///
|
||||||
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
|
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
|
||||||
/// do anything at all.
|
/// do anything at all.
|
||||||
|
|
|
@ -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
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -97,7 +97,6 @@ pub mod cast;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
pub mod _match;
|
pub mod _match;
|
||||||
mod constness;
|
|
||||||
mod erase_regions;
|
mod erase_regions;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod fast_reject;
|
pub mod fast_reject;
|
||||||
|
@ -3318,7 +3317,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||||
context::provide(providers);
|
context::provide(providers);
|
||||||
erase_regions::provide(providers);
|
erase_regions::provide(providers);
|
||||||
layout::provide(providers);
|
layout::provide(providers);
|
||||||
constness::provide(providers);
|
|
||||||
*providers = ty::query::Providers {
|
*providers = ty::query::Providers {
|
||||||
asyncness,
|
asyncness,
|
||||||
associated_item,
|
associated_item,
|
||||||
|
|
|
@ -9,10 +9,12 @@ use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod eval_queries;
|
mod eval_queries;
|
||||||
|
mod fn_queries;
|
||||||
mod machine;
|
mod machine;
|
||||||
|
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use eval_queries::*;
|
pub use eval_queries::*;
|
||||||
|
pub use fn_queries::*;
|
||||||
pub use machine::*;
|
pub use machine::*;
|
||||||
|
|
||||||
/// Extracts a field of a (variant of a) const.
|
/// Extracts a field of a (variant of a) const.
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ use rustc::ty::query::Providers;
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers<'_>) {
|
pub fn provide(providers: &mut Providers<'_>) {
|
||||||
borrow_check::provide(providers);
|
borrow_check::provide(providers);
|
||||||
|
const_eval::provide(providers);
|
||||||
shim::provide(providers);
|
shim::provide(providers);
|
||||||
transform::provide(providers);
|
transform::provide(providers);
|
||||||
monomorphize::partitioning::provide(providers);
|
monomorphize::partitioning::provide(providers);
|
||||||
|
|
|
@ -21,6 +21,7 @@ use super::ops::{self, NonConstOp};
|
||||||
use super::qualifs::{self, HasMutInterior, NeedsDrop};
|
use super::qualifs::{self, HasMutInterior, NeedsDrop};
|
||||||
use super::resolver::FlowSensitiveAnalysis;
|
use super::resolver::FlowSensitiveAnalysis;
|
||||||
use super::{is_lang_panic_fn, ConstKind, Item, Qualif};
|
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};
|
use crate::dataflow::{self as old_dataflow, generic as dataflow};
|
||||||
|
|
||||||
pub type IndirectlyMutableResults<'mir, 'tcx> =
|
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 Item { tcx, body, def_id, const_kind, .. } = *self.item;
|
||||||
|
|
||||||
let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
|
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;
|
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
|
||||||
|
|
||||||
if use_min_const_fn_checks {
|
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...
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_lang_panic_fn(self.tcx, def_id) {
|
if is_lang_panic_fn(self.tcx, def_id) {
|
||||||
self.check_op(ops::Panic);
|
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
|
// Exempt unstable const fns inside of macros with
|
||||||
// `#[allow_internal_unstable]`.
|
// `#[allow_internal_unstable]`.
|
||||||
if !self.span.allows_unstable(feature) {
|
if !self.span.allows_unstable(feature) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ use rustc_span::symbol::{sym, Symbol};
|
||||||
|
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
use crate::const_eval::{is_const_fn, is_min_const_fn};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use rustc_error_codes::*;
|
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 id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||||
let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
|
let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
|
||||||
hir::BodyOwnerKind::Closure => (false, false),
|
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),
|
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
|
||||||
};
|
};
|
||||||
let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
|
let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
|
||||||
|
|
|
@ -29,6 +29,7 @@ use rustc_target::spec::abi::Abi;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::{iter, mem, usize};
|
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::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
|
||||||
use crate::transform::{MirPass, MirSource};
|
use crate::transform::{MirPass, MirSource};
|
||||||
|
|
||||||
|
@ -702,8 +703,8 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
|
|
||||||
let is_const_fn = match fn_ty.kind {
|
let is_const_fn = match fn_ty.kind {
|
||||||
ty::FnDef(def_id, _) => {
|
ty::FnDef(def_id, _) => {
|
||||||
self.tcx.is_const_fn(def_id)
|
is_const_fn(self.tcx, def_id)
|
||||||
|| self.tcx.is_unstable_const_fn(def_id).is_some()
|
|| is_unstable_const_fn(self.tcx, def_id).is_some()
|
||||||
|| is_lang_panic_fn(self.tcx, self.def_id)
|
|| is_lang_panic_fn(self.tcx, self.def_id)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -327,7 +327,7 @@ fn check_terminator(
|
||||||
TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
|
TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
|
||||||
let fn_ty = func.ty(body, tcx);
|
let fn_ty = func.ty(body, tcx);
|
||||||
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
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((
|
return Err((
|
||||||
span,
|
span,
|
||||||
format!(
|
format!(
|
||||||
|
|
|
@ -202,27 +202,38 @@ impl ops::Not for Cfg {
|
||||||
|
|
||||||
impl ops::BitAndAssign for Cfg {
|
impl ops::BitAndAssign for Cfg {
|
||||||
fn bitand_assign(&mut self, other: Cfg) {
|
fn bitand_assign(&mut self, other: Cfg) {
|
||||||
if *self == other {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&mut Cfg::False, _) | (_, Cfg::True) => {}
|
(&mut Cfg::False, _) | (_, Cfg::True) => {}
|
||||||
(s, Cfg::False) => *s = Cfg::False,
|
(s, Cfg::False) => *s = Cfg::False,
|
||||||
(s @ &mut Cfg::True, b) => *s = b,
|
(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), Cfg::All(ref mut b)) => {
|
||||||
(&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
|
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)) => {
|
(s, Cfg::All(mut a)) => {
|
||||||
let b = mem::replace(s, Cfg::True);
|
let b = mem::replace(s, Cfg::True);
|
||||||
|
if !a.contains(&b) {
|
||||||
a.push(b);
|
a.push(b);
|
||||||
|
}
|
||||||
*s = Cfg::All(a);
|
*s = Cfg::All(a);
|
||||||
}
|
}
|
||||||
(s, b) => {
|
(s, b) => {
|
||||||
|
if *s != b {
|
||||||
let a = mem::replace(s, Cfg::True);
|
let a = mem::replace(s, Cfg::True);
|
||||||
*s = Cfg::All(vec![a, b]);
|
*s = Cfg::All(vec![a, b]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ops::BitAnd for Cfg {
|
impl ops::BitAnd for Cfg {
|
||||||
type Output = Cfg;
|
type Output = Cfg;
|
||||||
|
@ -234,27 +245,38 @@ impl ops::BitAnd for Cfg {
|
||||||
|
|
||||||
impl ops::BitOrAssign for Cfg {
|
impl ops::BitOrAssign for Cfg {
|
||||||
fn bitor_assign(&mut self, other: Cfg) {
|
fn bitor_assign(&mut self, other: Cfg) {
|
||||||
if *self == other {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&mut Cfg::True, _) | (_, Cfg::False) => {}
|
(&mut Cfg::True, _) | (_, Cfg::False) => {}
|
||||||
(s, Cfg::True) => *s = Cfg::True,
|
(s, Cfg::True) => *s = Cfg::True,
|
||||||
(s @ &mut Cfg::False, b) => *s = b,
|
(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), Cfg::Any(ref mut b)) => {
|
||||||
(&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
|
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)) => {
|
(s, Cfg::Any(mut a)) => {
|
||||||
let b = mem::replace(s, Cfg::True);
|
let b = mem::replace(s, Cfg::True);
|
||||||
|
if !a.contains(&b) {
|
||||||
a.push(b);
|
a.push(b);
|
||||||
|
}
|
||||||
*s = Cfg::Any(a);
|
*s = Cfg::Any(a);
|
||||||
}
|
}
|
||||||
(s, b) => {
|
(s, b) => {
|
||||||
|
if *s != b {
|
||||||
let a = mem::replace(s, Cfg::True);
|
let a = mem::replace(s, Cfg::True);
|
||||||
*s = Cfg::Any(vec![a, b]);
|
*s = Cfg::Any(vec![a, b]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ops::BitOr for Cfg {
|
impl ops::BitOr for Cfg {
|
||||||
type Output = Cfg;
|
type Output = Cfg;
|
||||||
|
|
|
@ -87,6 +87,12 @@ fn test_cfg_and() {
|
||||||
x &= word_cfg("test3");
|
x &= word_cfg("test3");
|
||||||
assert_eq!(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");
|
x &= word_cfg("test4");
|
||||||
assert_eq!(x, Cfg::All(vec![word_cfg("test3"), 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")]);
|
let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
|
||||||
y &= x;
|
y &= x;
|
||||||
assert_eq!(
|
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!(
|
assert_eq!(
|
||||||
word_cfg("a") & word_cfg("b") & word_cfg("c"),
|
word_cfg("a") & word_cfg("b") & word_cfg("c"),
|
||||||
Cfg::All(vec![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");
|
x |= word_cfg("test3");
|
||||||
assert_eq!(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");
|
x |= word_cfg("test4");
|
||||||
assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), 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")]);
|
let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
|
||||||
y |= x;
|
y |= x;
|
||||||
assert_eq!(
|
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!(
|
assert_eq!(
|
||||||
word_cfg("a") | word_cfg("b") | word_cfg("c"),
|
word_cfg("a") | word_cfg("b") | word_cfg("c"),
|
||||||
Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
|
Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
|
||||||
|
|
|
@ -9,6 +9,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::Mutability;
|
use rustc_hir::Mutability;
|
||||||
use rustc_metadata::creader::LoadedMacro;
|
use rustc_metadata::creader::LoadedMacro;
|
||||||
|
use rustc_mir::const_eval::is_min_const_fn;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
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 sig = cx.tcx.fn_sig(did);
|
||||||
|
|
||||||
let constness =
|
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 asyncness = cx.tcx.asyncness(did);
|
||||||
let predicates = cx.tcx.predicates_of(did);
|
let predicates = cx.tcx.predicates_of(did);
|
||||||
let (generics, decl) = clean::enter_impl_trait(cx, || {
|
let (generics, decl) = clean::enter_impl_trait(cx, || {
|
||||||
|
|
|
@ -21,6 +21,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
|
use rustc_mir::const_eval::is_min_const_fn;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::{self, Pos};
|
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)));
|
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 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
|
hir::Constness::Const
|
||||||
} else {
|
} else {
|
||||||
hir::Constness::NotConst
|
hir::Constness::NotConst
|
||||||
|
@ -1187,7 +1188,7 @@ impl Clean<Item> for ty::AssocItem {
|
||||||
};
|
};
|
||||||
let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
|
let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
|
||||||
if provided {
|
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
|
hir::Constness::Const
|
||||||
} else {
|
} else {
|
||||||
hir::Constness::NotConst
|
hir::Constness::NotConst
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::html;
|
||||||
use crate::html::markdown::IdMap;
|
use crate::html::markdown::IdMap;
|
||||||
use crate::html::static_files;
|
use crate::html::static_files;
|
||||||
use crate::opts;
|
use crate::opts;
|
||||||
use crate::passes::{self, DefaultPassOption};
|
use crate::passes::{self, Condition, DefaultPassOption};
|
||||||
use crate::theme;
|
use crate::theme;
|
||||||
|
|
||||||
/// Configuration options for rustdoc.
|
/// 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!
|
/// Be aware: This option can come both from the CLI and from crate attributes!
|
||||||
pub default_passes: DefaultPassOption,
|
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.
|
/// Any passes manually selected by the user.
|
||||||
///
|
///
|
||||||
/// Be aware: This option can come both from the CLI and from crate attributes!
|
/// 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("test_args", &self.test_args)
|
||||||
.field("persist_doctests", &self.persist_doctests)
|
.field("persist_doctests", &self.persist_doctests)
|
||||||
.field("default_passes", &self.default_passes)
|
.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("manual_passes", &self.manual_passes)
|
||||||
.field("display_warnings", &self.display_warnings)
|
.field("display_warnings", &self.display_warnings)
|
||||||
.field("show_coverage", &self.show_coverage)
|
.field("show_coverage", &self.show_coverage)
|
||||||
|
@ -240,22 +246,26 @@ impl Options {
|
||||||
println!("{:>20} - {}", pass.name, pass.description);
|
println!("{:>20} - {}", pass.name, pass.description);
|
||||||
}
|
}
|
||||||
println!("\nDefault passes for rustdoc:");
|
println!("\nDefault passes for rustdoc:");
|
||||||
for pass in passes::DEFAULT_PASSES {
|
for p in passes::DEFAULT_PASSES {
|
||||||
println!("{:>20}", pass.name);
|
print!("{:>20}", p.pass.name);
|
||||||
}
|
println_condition(p.condition);
|
||||||
println!("\nPasses run with `--document-private-items`:");
|
|
||||||
for pass in passes::DEFAULT_PRIVATE_PASSES {
|
|
||||||
println!("{:>20}", pass.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if nightly_options::is_nightly_build() {
|
if nightly_options::is_nightly_build() {
|
||||||
println!("\nPasses run with `--show-coverage`:");
|
println!("\nPasses run with `--show-coverage`:");
|
||||||
for pass in passes::DEFAULT_COVERAGE_PASSES {
|
for p in passes::COVERAGE_PASSES {
|
||||||
println!("{:>20}", pass.name);
|
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 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") {
|
let default_passes = if matches.opt_present("no-defaults") {
|
||||||
passes::DefaultPassOption::None
|
passes::DefaultPassOption::None
|
||||||
} else if show_coverage && document_private {
|
|
||||||
passes::DefaultPassOption::PrivateCoverage
|
|
||||||
} else if show_coverage {
|
} else if show_coverage {
|
||||||
passes::DefaultPassOption::Coverage
|
passes::DefaultPassOption::Coverage
|
||||||
} else if document_private {
|
|
||||||
passes::DefaultPassOption::Private
|
|
||||||
} else {
|
} else {
|
||||||
passes::DefaultPassOption::Default
|
passes::DefaultPassOption::Default
|
||||||
};
|
};
|
||||||
|
@ -492,6 +497,8 @@ impl Options {
|
||||||
let runtool = matches.opt_str("runtool");
|
let runtool = matches.opt_str("runtool");
|
||||||
let runtool_args = matches.opt_strs("runtool-arg");
|
let runtool_args = matches.opt_strs("runtool-arg");
|
||||||
let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
|
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);
|
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
|
||||||
|
|
||||||
|
@ -518,6 +525,8 @@ impl Options {
|
||||||
should_test,
|
should_test,
|
||||||
test_args,
|
test_args,
|
||||||
default_passes,
|
default_passes,
|
||||||
|
document_private,
|
||||||
|
document_hidden,
|
||||||
manual_passes,
|
manual_passes,
|
||||||
display_warnings,
|
display_warnings,
|
||||||
show_coverage,
|
show_coverage,
|
||||||
|
|
|
@ -33,7 +33,7 @@ use crate::clean::{AttributesExt, MAX_DEF_ID};
|
||||||
use crate::config::{Options as RustdocOptions, RenderOptions};
|
use crate::config::{Options as RustdocOptions, RenderOptions};
|
||||||
use crate::html::render::RenderInfo;
|
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::config::{CodegenOptions, DebuggingOptions, Input, Options};
|
||||||
pub use rustc::session::search_paths::SearchPath;
|
pub use rustc::session::search_paths::SearchPath;
|
||||||
|
@ -221,6 +221,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||||
describe_lints,
|
describe_lints,
|
||||||
lint_cap,
|
lint_cap,
|
||||||
mut default_passes,
|
mut default_passes,
|
||||||
|
mut document_private,
|
||||||
|
document_hidden,
|
||||||
mut manual_passes,
|
mut manual_passes,
|
||||||
display_warnings,
|
display_warnings,
|
||||||
render_options,
|
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 attr.is_word() && name == sym::document_private_items {
|
||||||
if default_passes == passes::DefaultPassOption::Default {
|
document_private = true;
|
||||||
default_passes = passes::DefaultPassOption::Private;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let passes = passes::defaults(default_passes).iter().chain(
|
let passes = passes::defaults(default_passes).iter().copied().chain(
|
||||||
manual_passes.into_iter().flat_map(|name| {
|
manual_passes.into_iter().flat_map(|name| {
|
||||||
if let Some(pass) = passes::find_pass(&name) {
|
if let Some(pass) = passes::find_pass(&name) {
|
||||||
Some(pass)
|
Some(ConditionalPass::always(pass))
|
||||||
} else {
|
} else {
|
||||||
error!("unknown pass {}, skipping", name);
|
error!("unknown pass {}, skipping", name);
|
||||||
None
|
None
|
||||||
|
@ -476,9 +476,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||||
|
|
||||||
info!("Executing passes");
|
info!("Executing passes");
|
||||||
|
|
||||||
for pass in passes {
|
for p in passes {
|
||||||
debug!("running pass {}", pass.name);
|
let run = match p.condition {
|
||||||
krate = (pass.pass)(krate, &ctxt);
|
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();
|
ctxt.sess().abort_if_errors();
|
||||||
|
|
|
@ -32,6 +32,7 @@ extern crate rustc_interface;
|
||||||
extern crate rustc_lexer;
|
extern crate rustc_lexer;
|
||||||
extern crate rustc_lint;
|
extern crate rustc_lint;
|
||||||
extern crate rustc_metadata;
|
extern crate rustc_metadata;
|
||||||
|
extern crate rustc_mir;
|
||||||
extern crate rustc_parse;
|
extern crate rustc_parse;
|
||||||
extern crate rustc_resolve;
|
extern crate rustc_resolve;
|
||||||
extern crate rustc_span as rustc_span;
|
extern crate rustc_span as rustc_span;
|
||||||
|
@ -173,6 +174,9 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||||
stable("document-private-items", |o| {
|
stable("document-private-items", |o| {
|
||||||
o.optflag("", "document-private-items", "document private items")
|
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", |o| o.optflag("", "test", "run code examples as tests")),
|
||||||
stable("test-args", |o| {
|
stable("test-args", |o| {
|
||||||
o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
|
o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::ops;
|
||||||
|
|
||||||
pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
|
pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
|
||||||
name: "calculate-doc-coverage",
|
name: "calculate-doc-coverage",
|
||||||
pass: calculate_doc_coverage,
|
run: calculate_doc_coverage,
|
||||||
description: "counts the number of items with and without documentation",
|
description: "counts the number of items with and without documentation",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::passes::Pass;
|
||||||
|
|
||||||
pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
|
pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
|
||||||
name: "check-code-block-syntax",
|
name: "check-code-block-syntax",
|
||||||
pass: check_code_block_syntax,
|
run: check_code_block_syntax,
|
||||||
description: "validates syntax inside Rust code blocks",
|
description: "validates syntax inside Rust code blocks",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::mem::take;
|
||||||
|
|
||||||
pub const COLLAPSE_DOCS: Pass = Pass {
|
pub const COLLAPSE_DOCS: Pass = Pass {
|
||||||
name: "collapse-docs",
|
name: "collapse-docs",
|
||||||
pass: collapse_docs,
|
run: collapse_docs,
|
||||||
description: "concatenates all document attributes into one document attribute",
|
description: "concatenates all document attributes into one document attribute",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ use super::span_of_attrs;
|
||||||
|
|
||||||
pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
|
pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
|
||||||
name: "collect-intra-doc-links",
|
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",
|
description: "reads a crate's documentation to resolve intra-doc-links",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
|
||||||
|
|
||||||
pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
|
pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
|
||||||
name: "collect-trait-impls",
|
name: "collect-trait-impls",
|
||||||
pass: collect_trait_impls,
|
run: collect_trait_impls,
|
||||||
description: "retrieves trait impls for items in the crate",
|
description: "retrieves trait impls for items in the crate",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ use rustc_span::{InnerSpan, Span, DUMMY_SP};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use self::Condition::*;
|
||||||
use crate::clean::{self, GetDefId, Item};
|
use crate::clean::{self, GetDefId, Item};
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use crate::fold::{DocFolder, StripItem};
|
use crate::fold::{DocFolder, StripItem};
|
||||||
|
@ -52,10 +53,29 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Pass {
|
pub struct Pass {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
|
pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
|
||||||
pub description: &'static str,
|
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.
|
/// The full list of passes.
|
||||||
pub const PASSES: &[Pass] = &[
|
pub const PASSES: &[Pass] = &[
|
||||||
CHECK_PRIVATE_ITEMS_DOC_TESTS,
|
CHECK_PRIVATE_ITEMS_DOC_TESTS,
|
||||||
|
@ -72,63 +92,58 @@ pub const PASSES: &[Pass] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The list of passes run by default.
|
/// The list of passes run by default.
|
||||||
pub const DEFAULT_PASSES: &[Pass] = &[
|
pub const DEFAULT_PASSES: &[ConditionalPass] = &[
|
||||||
COLLECT_TRAIT_IMPLS,
|
ConditionalPass::always(COLLECT_TRAIT_IMPLS),
|
||||||
COLLAPSE_DOCS,
|
ConditionalPass::always(COLLAPSE_DOCS),
|
||||||
UNINDENT_COMMENTS,
|
ConditionalPass::always(UNINDENT_COMMENTS),
|
||||||
CHECK_PRIVATE_ITEMS_DOC_TESTS,
|
ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS),
|
||||||
STRIP_HIDDEN,
|
ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
|
||||||
STRIP_PRIVATE,
|
ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
|
||||||
COLLECT_INTRA_DOC_LINKS,
|
ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
|
||||||
CHECK_CODE_BLOCK_SYNTAX,
|
ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
|
||||||
PROPAGATE_DOC_CFG,
|
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.
|
/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
|
||||||
pub const DEFAULT_COVERAGE_PASSES: &[Pass] =
|
pub const COVERAGE_PASSES: &[ConditionalPass] = &[
|
||||||
&[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE];
|
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
|
impl ConditionalPass {
|
||||||
/// rustdoc.
|
pub const fn always(pass: Pass) -> Self {
|
||||||
pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE];
|
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
|
/// 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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum DefaultPassOption {
|
pub enum DefaultPassOption {
|
||||||
Default,
|
Default,
|
||||||
Private,
|
|
||||||
Coverage,
|
Coverage,
|
||||||
PrivateCoverage,
|
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the given default set of passes.
|
/// 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 {
|
match default_set {
|
||||||
DefaultPassOption::Default => DEFAULT_PASSES,
|
DefaultPassOption::Default => DEFAULT_PASSES,
|
||||||
DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES,
|
DefaultPassOption::Coverage => COVERAGE_PASSES,
|
||||||
DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES,
|
|
||||||
DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES,
|
|
||||||
DefaultPassOption::None => &[],
|
DefaultPassOption::None => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the given name matches a known pass, returns its information.
|
/// If the given name matches a known pass, returns its information.
|
||||||
pub fn find_pass(pass_name: &str) -> Option<&'static Pass> {
|
pub fn find_pass(pass_name: &str) -> Option<Pass> {
|
||||||
PASSES.iter().find(|p| p.name == pass_name)
|
PASSES.iter().find(|p| p.name == pass_name).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Stripper<'a> {
|
struct Stripper<'a> {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::passes::{look_for_tests, Pass};
|
||||||
|
|
||||||
pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
|
pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
|
||||||
name: "check-private-items-doc-tests",
|
name: "check-private-items-doc-tests",
|
||||||
pass: check_private_items_doc_tests,
|
run: check_private_items_doc_tests,
|
||||||
description: "check private items doc tests",
|
description: "check private items doc tests",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::passes::Pass;
|
||||||
|
|
||||||
pub const PROPAGATE_DOC_CFG: Pass = Pass {
|
pub const PROPAGATE_DOC_CFG: Pass = Pass {
|
||||||
name: "propagate-doc-cfg",
|
name: "propagate-doc-cfg",
|
||||||
pass: propagate_doc_cfg,
|
run: propagate_doc_cfg,
|
||||||
description: "propagates `#[doc(cfg(...))]` to child items",
|
description: "propagates `#[doc(cfg(...))]` to child items",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::passes::{ImplStripper, Pass};
|
||||||
|
|
||||||
pub const STRIP_HIDDEN: Pass = Pass {
|
pub const STRIP_HIDDEN: Pass = Pass {
|
||||||
name: "strip-hidden",
|
name: "strip-hidden",
|
||||||
pass: strip_hidden,
|
run: strip_hidden,
|
||||||
description: "strips all doc(hidden) items from the output",
|
description: "strips all doc(hidden) items from the output",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::passes::{ImportStripper, Pass};
|
||||||
|
|
||||||
pub const STRIP_PRIV_IMPORTS: Pass = Pass {
|
pub const STRIP_PRIV_IMPORTS: Pass = Pass {
|
||||||
name: "strip-priv-imports",
|
name: "strip-priv-imports",
|
||||||
pass: strip_priv_imports,
|
run: strip_priv_imports,
|
||||||
description: "strips all private import statements (`use`, `extern crate`) from a crate",
|
description: "strips all private import statements (`use`, `extern crate`) from a crate",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
|
||||||
|
|
||||||
pub const STRIP_PRIVATE: Pass = Pass {
|
pub const STRIP_PRIVATE: Pass = Pass {
|
||||||
name: "strip-private",
|
name: "strip-private",
|
||||||
pass: strip_private,
|
run: strip_private,
|
||||||
description: "strips all private items from a crate which cannot be seen externally, \
|
description: "strips all private items from a crate which cannot be seen externally, \
|
||||||
implies strip-priv-imports",
|
implies strip-priv-imports",
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ mod tests;
|
||||||
|
|
||||||
pub const UNINDENT_COMMENTS: Pass = Pass {
|
pub const UNINDENT_COMMENTS: Pass = Pass {
|
||||||
name: "unindent-comments",
|
name: "unindent-comments",
|
||||||
pass: unindent_comments,
|
run: unindent_comments,
|
||||||
description: "removes excess indentation on comments in order for markdown to like it",
|
description: "removes excess indentation on comments in order for markdown to like it",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1187,11 +1187,6 @@ impl CStr {
|
||||||
/// function will return the corresponding [`&str`] slice. Otherwise,
|
/// function will return the corresponding [`&str`] slice. Otherwise,
|
||||||
/// it will return an error with details of where UTF-8 validation failed.
|
/// 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
|
/// [`&str`]: ../primitive.str.html
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -1220,11 +1215,6 @@ impl CStr {
|
||||||
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
|
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
|
||||||
/// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
|
/// [`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
|
/// [`Cow`]: ../borrow/enum.Cow.html
|
||||||
/// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
|
/// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
|
||||||
/// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
|
/// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
|
||||||
|
|
|
@ -51,24 +51,14 @@ pub use crate::sys_common::fs::remove_dir_all;
|
||||||
|
|
||||||
pub struct File(FileDesc);
|
pub struct File(FileDesc);
|
||||||
|
|
||||||
// FIXME: This should be available on Linux with all `target_arch` and `target_env`.
|
// FIXME: This should be available on Linux with all `target_env`.
|
||||||
// https://github.com/rust-lang/libc/issues/1545
|
// 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 {
|
macro_rules! cfg_has_statx {
|
||||||
({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
|
({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(all(target_os = "linux", target_env = "gnu", any(
|
if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
|
||||||
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",
|
|
||||||
)))] {
|
|
||||||
$($then_tt)*
|
$($then_tt)*
|
||||||
} else {
|
} else {
|
||||||
$($else_tt)*
|
$($else_tt)*
|
||||||
|
@ -76,19 +66,7 @@ macro_rules! cfg_has_statx {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($($block_inner:tt)*) => {
|
($($block_inner:tt)*) => {
|
||||||
#[cfg(all(target_os = "linux", target_env = "gnu", any(
|
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||||
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",
|
|
||||||
)))]
|
|
||||||
{
|
{
|
||||||
$($block_inner)*
|
$($block_inner)*
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,18 +36,10 @@ pub use crate::sys_common::os_str_bytes as os_str;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
// By default, some platforms will send a *signal* when an EPIPE error
|
// ignore SIGPIPE
|
||||||
// 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.
|
|
||||||
unsafe {
|
unsafe {
|
||||||
reset_sigpipe();
|
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn reset_sigpipe() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use libc::signal;
|
pub use libc::signal;
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -54,14 +54,16 @@ where
|
||||||
T: Iterator<Item = &'a Symbol>,
|
T: Iterator<Item = &'a Symbol>,
|
||||||
{
|
{
|
||||||
let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
|
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| {
|
.filter_map(|&name| {
|
||||||
let dist = lev_distance(lookup, &name.as_str());
|
let dist = lev_distance(lookup, &name.as_str());
|
||||||
if dist <= max_dist { Some((name, dist)) } else { None }
|
if dist <= max_dist { Some((name, dist)) } else { None }
|
||||||
})
|
})
|
||||||
// Here we are collecting the next structure:
|
// 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)| {
|
.fold((None, None), |result, (candidate, dist)| {
|
||||||
(
|
(
|
||||||
if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
|
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 {
|
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 {
|
} 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("_")
|
||||||
|
}
|
||||||
|
|
|
@ -46,5 +46,11 @@ fn test_find_best_match_for_name() {
|
||||||
find_best_match_for_name(input.iter(), "aaaa", Some(4)),
|
find_best_match_for_name(input.iter(), "aaaa", Some(4)),
|
||||||
Some(Symbol::intern("AAAA"))
|
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"))
|
||||||
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,42 @@
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![crate_name = "foo"]
|
#![crate_name = "foo"]
|
||||||
#![feature(doc_cfg)]
|
#![feature(doc_cfg)]
|
||||||
|
|
||||||
// @has 'foo/index.html'
|
// @has 'foo/struct.Foo.html'
|
||||||
// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
|
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
|
||||||
// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
|
|
||||||
#[doc(cfg(feature = "sync"))]
|
#[doc(cfg(feature = "sync"))]
|
||||||
#[doc(cfg(feature = "sync"))]
|
#[doc(cfg(feature = "sync"))]
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
|
|
||||||
|
// @has 'foo/bar/struct.Bar.html'
|
||||||
|
// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
|
||||||
#[doc(cfg(feature = "sync"))]
|
#[doc(cfg(feature = "sync"))]
|
||||||
pub mod bar {
|
pub mod bar {
|
||||||
#[doc(cfg(feature = "sync"))]
|
#[doc(cfg(feature = "sync"))]
|
||||||
pub struct Bar;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// compile-flags: --document-private-items
|
|
||||||
|
|
||||||
// @has issue_46380/struct.Hidden.html
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct Hidden;
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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(""));
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
let a_longer_variable_name = 1;
|
||||||
|
println!("{}", a_variable_longer_name); //~ ERROR E0425
|
||||||
|
}
|
|
@ -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`.
|
Loading…
Reference in New Issue