Auto merge of #77606 - JohnTitor:rollup-7rgahdt, r=JohnTitor

Rollup of 13 pull requests

Successful merges:

 - #76388 (Add a note about the panic behavior of math operations on time objects)
 - #76855 (Revamp rustdoc docs about documentation using `cfg`)
 - #76995 (Reduce boilerplate with the matches! macro)
 - #77228 (Add missing examples for MaybeUninit)
 - #77528 (Avoid unchecked casts in net parser)
 - #77534 (Disallow overriding forbid in same scope)
 - #77555 (Allow anyone to set regression labels)
 - #77558 (Rename bootstrap/defaults/{config.toml.PROFILE => config.PROFILE.toml})
 - #77559 (Fix rustdoc warnings about invalid Rust syntax)
 - #77560 (Fix LitKind's byte buffer to use refcounted slice)
 - #77573 (Hint doc use convert::identity relative link)
 - #77587 (Fix span for unicode escape suggestion.)
 - #77591 (Record `expansion_that_defined` into crate metadata)

Failed merges:

r? `@ghost`
This commit is contained in:
bors 2020-10-06 08:05:27 +00:00
commit 5ded394553
55 changed files with 512 additions and 386 deletions

View File

@ -1606,7 +1606,7 @@ pub enum LitKind {
/// A string literal (`"foo"`).
Str(Symbol, StrStyle),
/// A byte string (`b"foo"`).
ByteStr(Lrc<Vec<u8>>),
ByteStr(Lrc<[u8]>),
/// A byte char (`b'f'`).
Byte(u8),
/// A character literal (`'a'`).

View File

@ -4,7 +4,6 @@ use crate::ast::{self, Lit, LitKind};
use crate::token::{self, Token};
use crate::tokenstream::TokenTree;
use rustc_data_structures::sync::Lrc;
use rustc_lexer::unescape::{unescape_byte, unescape_char};
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
use rustc_span::symbol::{kw, sym, Symbol};
@ -108,7 +107,7 @@ impl LitKind {
});
error?;
buf.shrink_to_fit();
LitKind::ByteStr(Lrc::new(buf))
LitKind::ByteStr(buf.into())
}
token::ByteStrRaw(_) => {
let s = symbol.as_str();
@ -128,7 +127,7 @@ impl LitKind {
symbol.to_string().into_bytes()
};
LitKind::ByteStr(Lrc::new(bytes))
LitKind::ByteStr(bytes.into())
}
token::Err => LitKind::Err(symbol),
})

View File

@ -13,8 +13,6 @@ use rustc_span::{self, Pos, Span};
use smallvec::SmallVec;
use std::rc::Rc;
use rustc_data_structures::sync::Lrc;
// These macros all relate to the file system; they either return
// the column/row/filename of the expression, or they include
// a given file into the current one.
@ -216,7 +214,7 @@ pub fn expand_include_bytes(
}
};
match cx.source_map().load_binary_file(&file) {
Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes)))),
Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(bytes.into()))),
Err(e) => {
cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp)

View File

@ -10,6 +10,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::LevelSource;
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
use rustc_middle::ty::query::Providers;
@ -95,6 +96,44 @@ impl<'s> LintLevelsBuilder<'s> {
self.sets.list.push(LintSet::CommandLine { specs });
}
/// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
/// (e.g. if a forbid was already inserted on the same scope), then emits a
/// diagnostic with no change to `specs`.
fn insert_spec(
&mut self,
specs: &mut FxHashMap<LintId, LevelSource>,
id: LintId,
(level, src): LevelSource,
) {
if let Some((old_level, old_src)) = specs.get(&id) {
if old_level == &Level::Forbid && level != Level::Forbid {
let mut diag_builder = struct_span_err!(
self.sess,
src.span(),
E0453,
"{}({}) incompatible with previous forbid in same scope",
level.as_str(),
src.name(),
);
match *old_src {
LintSource::Default => {}
LintSource::Node(_, forbid_source_span, reason) => {
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
if let Some(rationale) = reason {
diag_builder.note(&rationale.as_str());
}
}
LintSource::CommandLine(_) => {
diag_builder.note("`forbid` lint level was set on command line");
}
}
diag_builder.emit();
return;
}
}
specs.insert(id, (level, src));
}
/// Pushes a list of AST lint attributes onto this context.
///
/// This function will return a `BuilderPush` object which should be passed
@ -109,7 +148,7 @@ impl<'s> LintLevelsBuilder<'s> {
/// `#[allow]`
///
/// Don't forget to call `pop`!
pub fn push(
pub(crate) fn push(
&mut self,
attrs: &[ast::Attribute],
store: &LintStore,
@ -221,7 +260,7 @@ impl<'s> LintLevelsBuilder<'s> {
let src = LintSource::Node(name, li.span(), reason);
for &id in ids {
self.check_gated_lint(id, attr.span);
specs.insert(id, (level, src));
self.insert_spec(&mut specs, id, (level, src));
}
}
@ -235,7 +274,7 @@ impl<'s> LintLevelsBuilder<'s> {
reason,
);
for id in ids {
specs.insert(*id, (level, src));
self.insert_spec(&mut specs, *id, (level, src));
}
}
Err((Some(ids), new_lint_name)) => {
@ -272,7 +311,7 @@ impl<'s> LintLevelsBuilder<'s> {
reason,
);
for id in ids {
specs.insert(*id, (level, src));
self.insert_spec(&mut specs, *id, (level, src));
}
}
Err((None, _)) => {

View File

@ -1011,6 +1011,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
}
fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId {
self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
}
/// Iterates over all the stability attributes in the given crate.
fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
// FIXME: For a proc macro crate, not sure whether we should return the "host"

View File

@ -238,6 +238,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
}
crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
}
pub fn provide(providers: &mut Providers) {

View File

@ -747,6 +747,7 @@ impl EncodeContext<'a, 'tcx> {
ty::Visibility::from_hir(enum_vis, enum_id, self.tcx));
record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
record!(self.tables.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
assert!(f.did.is_local());
f.did.index
@ -883,6 +884,7 @@ impl EncodeContext<'a, 'tcx> {
record!(self.tables.visibility[def_id] <- field.vis);
record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
record!(self.tables.attributes[def_id] <- variant_data.fields()[field_index].attrs);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
self.encode_ident_span(def_id, field.ident);
self.encode_stability(def_id);
self.encode_deprecation(def_id);
@ -924,6 +926,7 @@ impl EncodeContext<'a, 'tcx> {
record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
record!(self.tables.visibility[def_id] <- ctor_vis);
record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
self.encode_stability(def_id);
self.encode_deprecation(def_id);
self.encode_item_type(def_id);
@ -1339,6 +1342,7 @@ impl EncodeContext<'a, 'tcx> {
ty::Visibility::from_hir(&item.vis, item.hir_id, tcx));
record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
record!(self.tables.attributes[def_id] <- item.attrs);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
// FIXME(eddyb) there should be a nicer way to do this.
match item.kind {
hir::ItemKind::ForeignMod(ref fm) => record!(self.tables.children[def_id] <-

View File

@ -294,6 +294,7 @@ define_tables! {
variances: Table<DefIndex, Lazy<[ty::Variance]>>,
generics: Table<DefIndex, Lazy<ty::Generics>>,
explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
// FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
// doesn't handle shorthands in its own (de)serialization impls,
// as it's an `enum` for which we want to derive (de)serialization,

View File

@ -535,15 +535,15 @@ impl<'hir> Map<'hir> {
Some(Node::Binding(_)) => (),
_ => return false,
}
match self.find(self.get_parent_node(id)) {
matches!(
self.find(self.get_parent_node(id)),
Some(
Node::Item(_)
| Node::TraitItem(_)
| Node::ImplItem(_)
| Node::Expr(Expr { kind: ExprKind::Closure(..), .. }),
) => true,
_ => false,
}
)
)
}
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
@ -554,10 +554,10 @@ impl<'hir> Map<'hir> {
/// Whether `hir_id` corresponds to a `mod` or a crate.
pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
match self.get_entry(hir_id).node {
Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..) => true,
_ => false,
}
matches!(
self.get_entry(hir_id).node,
Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
)
}
/// Retrieves the `HirId` for `id`'s enclosing method, unless there's a

View File

@ -9,7 +9,7 @@ use rustc_session::lint::{builtin, Level, Lint, LintId};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::{Span, Symbol};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
@ -25,6 +25,24 @@ pub enum LintSource {
CommandLine(Symbol),
}
impl LintSource {
pub fn name(&self) -> Symbol {
match *self {
LintSource::Default => symbol::kw::Default,
LintSource::Node(name, _, _) => name,
LintSource::CommandLine(name) => name,
}
}
pub fn span(&self) -> Span {
match *self {
LintSource::Default => DUMMY_SP,
LintSource::Node(_, span, _) => span,
LintSource::CommandLine(_) => DUMMY_SP,
}
}
}
pub type LevelSource = (Level, LintSource);
pub struct LintLevelSets {

View File

@ -486,10 +486,10 @@ impl<'tcx> TyCtxt<'tcx> {
// `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
// However, formatting code relies on function identity (see #58320), so we only do
// this for generic functions. Lifetime parameters are ignored.
let is_generic = instance.substs.into_iter().any(|kind| match kind.unpack() {
GenericArgKind::Lifetime(_) => false,
_ => true,
});
let is_generic = instance
.substs
.into_iter()
.any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
if is_generic {
// Get a fresh ID.
let mut alloc_map = self.alloc_map.lock();

View File

@ -445,19 +445,13 @@ impl<'tcx, Tag> Scalar<Tag> {
/// Do not call this method! Dispatch based on the type instead.
#[inline]
pub fn is_bits(self) -> bool {
match self {
Scalar::Raw { .. } => true,
_ => false,
}
matches!(self, Scalar::Raw { .. })
}
/// Do not call this method! Dispatch based on the type instead.
#[inline]
pub fn is_ptr(self) -> bool {
match self {
Scalar::Ptr(_) => true,
_ => false,
}
matches!(self, Scalar::Ptr(_))
}
pub fn to_bool(self) -> InterpResult<'tcx, bool> {

View File

@ -971,67 +971,59 @@ impl<'tcx> LocalDecl<'tcx> {
/// - `let x = ...`,
/// - or `match ... { C(x) => ... }`
pub fn can_be_made_mutable(&self) -> bool {
match self.local_info {
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
})))) => true,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
ImplicitSelfKind::Imm,
)))) => true,
_ => false,
}
matches!(
self.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(
BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
})
| BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
)))
)
}
/// Returns `true` if local is definitely not a `ref ident` or
/// `ref mut ident` binding. (Such bindings cannot be made into
/// mutable bindings, but the inverse does not necessarily hold).
pub fn is_nonref_binding(&self) -> bool {
match self.local_info {
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
})))) => true,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_)))) => true,
_ => false,
}
matches!(
self.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(
BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
})
| BindingForm::ImplicitSelf(_),
)))
)
}
/// Returns `true` if this variable is a named variable or function
/// parameter declared by the user.
#[inline]
pub fn is_user_variable(&self) -> bool {
match self.local_info {
Some(box LocalInfo::User(_)) => true,
_ => false,
}
matches!(self.local_info, Some(box LocalInfo::User(_)))
}
/// Returns `true` if this is a reference to a variable bound in a `match`
/// expression that is used to access said variable for the guard of the
/// match arm.
pub fn is_ref_for_guard(&self) -> bool {
match self.local_info {
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) => true,
_ => false,
}
matches!(
self.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)))
)
}
/// Returns `Some` if this is a reference to a static item that is used to
/// access that static
pub fn is_ref_to_static(&self) -> bool {
match self.local_info {
Some(box LocalInfo::StaticRef { .. }) => true,
_ => false,
}
matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
}
/// Returns `Some` if this is a reference to a static item that is used to
@ -2164,10 +2156,7 @@ pub enum BinOp {
impl BinOp {
pub fn is_checkable(self) -> bool {
use self::BinOp::*;
match self {
Add | Sub | Mul | Shl | Shr => true,
_ => false,
}
matches!(self, Add | Sub | Mul | Shl | Shr)
}
}

View File

@ -1164,82 +1164,63 @@ pub enum PlaceContext {
impl PlaceContext {
/// Returns `true` if this place context represents a drop.
pub fn is_drop(&self) -> bool {
match *self {
PlaceContext::MutatingUse(MutatingUseContext::Drop) => true,
_ => false,
}
matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
}
/// Returns `true` if this place context represents a borrow.
pub fn is_borrow(&self) -> bool {
match *self {
matches!(
self,
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::UniqueBorrow,
)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => true,
_ => false,
}
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::UniqueBorrow
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
)
}
/// Returns `true` if this place context represents a storage live or storage dead marker.
pub fn is_storage_marker(&self) -> bool {
match *self {
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => true,
_ => false,
}
matches!(
self,
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
)
}
/// Returns `true` if this place context represents a storage live marker.
pub fn is_storage_live_marker(&self) -> bool {
match *self {
PlaceContext::NonUse(NonUseContext::StorageLive) => true,
_ => false,
}
matches!(self, PlaceContext::NonUse(NonUseContext::StorageLive))
}
/// Returns `true` if this place context represents a storage dead marker.
pub fn is_storage_dead_marker(&self) -> bool {
match *self {
PlaceContext::NonUse(NonUseContext::StorageDead) => true,
_ => false,
}
matches!(self, PlaceContext::NonUse(NonUseContext::StorageDead))
}
/// Returns `true` if this place context represents a use that potentially changes the value.
pub fn is_mutating_use(&self) -> bool {
match *self {
PlaceContext::MutatingUse(..) => true,
_ => false,
}
matches!(self, PlaceContext::MutatingUse(..))
}
/// Returns `true` if this place context represents a use that does not change the value.
pub fn is_nonmutating_use(&self) -> bool {
match *self {
PlaceContext::NonMutatingUse(..) => true,
_ => false,
}
matches!(self, PlaceContext::NonMutatingUse(..))
}
/// Returns `true` if this place context represents a use.
pub fn is_use(&self) -> bool {
match *self {
PlaceContext::NonUse(..) => false,
_ => true,
}
!matches!(self, PlaceContext::NonUse(..))
}
/// Returns `true` if this place context represents an assignment statement.
pub fn is_place_assignment(&self) -> bool {
match *self {
matches!(
self,
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Call
| MutatingUseContext::AsmOutput,
) => true,
_ => false,
}
| MutatingUseContext::Call
| MutatingUseContext::AsmOutput,
)
)
}
}

View File

@ -191,6 +191,11 @@ rustc_queries! {
eval_always
desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// Internal helper query. Use `tcx.expansion_that_defined` instead
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
}
}
Codegen {

View File

@ -79,10 +79,7 @@ pub enum Node {
impl<'tcx> Node {
pub fn is_from_trait(&self) -> bool {
match *self {
Node::Trait(..) => true,
_ => false,
}
matches!(self, Node::Trait(..))
}
/// Iterate over the items defined directly by the given (impl or trait) node.

View File

@ -85,10 +85,7 @@ pub struct Adjustment<'tcx> {
impl Adjustment<'tcx> {
pub fn is_region_borrow(&self) -> bool {
match self.kind {
Adjust::Borrow(AutoBorrow::Ref(..)) => true,
_ => false,
}
matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
}
}

View File

@ -588,10 +588,7 @@ impl<'tcx> TypeckResults<'tcx> {
return false;
}
match self.type_dependent_defs().get(expr.hir_id) {
Some(Ok((DefKind::AssocFn, _))) => true,
_ => false,
}
matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
}
pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {

View File

@ -11,21 +11,16 @@ use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
impl<'tcx> TyS<'tcx> {
/// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
pub fn is_primitive_ty(&self) -> bool {
match self.kind() {
Bool
| Char
| Str
| Int(_)
| Uint(_)
| Float(_)
matches!(
self.kind(),
Bool | Char | Str | Int(_) | Uint(_) | Float(_)
| Infer(
InferTy::IntVar(_)
| InferTy::FloatVar(_)
| InferTy::FreshIntTy(_)
| InferTy::FreshFloatTy(_),
) => true,
_ => false,
}
| InferTy::FreshFloatTy(_)
)
)
}
/// Whether the type is succinctly representable as a type instead of just referred to with a
@ -64,11 +59,16 @@ impl<'tcx> TyS<'tcx> {
/// Whether the type can be safely suggested during error recovery.
pub fn is_suggestable(&self) -> bool {
match self.kind() {
Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..)
| Projection(..) => false,
_ => true,
}
!matches!(
self.kind(),
Opaque(..)
| FnDef(..)
| FnPtr(..)
| Dynamic(..)
| Closure(..)
| Infer(..)
| Projection(..)
)
}
}

View File

@ -184,10 +184,10 @@ impl<'tcx> InstanceDef<'tcx> {
ty::InstanceDef::DropGlue(_, Some(_)) => return false,
_ => return true,
};
match tcx.def_key(def_id).disambiguated_data.data {
DefPathData::Ctor | DefPathData::ClosureExpr => true,
_ => false,
}
matches!(
tcx.def_key(def_id).disambiguated_data.data,
DefPathData::Ctor | DefPathData::ClosureExpr
)
}
/// Returns `true` if the machine code for this instance is instantiated in

View File

@ -2610,10 +2610,7 @@ where
target.target_os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
let linux_powerpc_gnu_like =
target.target_os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
let rust_abi = match sig.abi {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
_ => false,
};
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
// Handle safe Rust thin and fat pointers.
let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,

View File

@ -2681,15 +2681,15 @@ impl<'tcx> ClosureKind {
/// Returns `true` if a type that impls this closure kind
/// must also implement `other`.
pub fn extends(self, other: ty::ClosureKind) -> bool {
match (self, other) {
(ClosureKind::Fn, ClosureKind::Fn) => true,
(ClosureKind::Fn, ClosureKind::FnMut) => true,
(ClosureKind::Fn, ClosureKind::FnOnce) => true,
(ClosureKind::FnMut, ClosureKind::FnMut) => true,
(ClosureKind::FnMut, ClosureKind::FnOnce) => true,
(ClosureKind::FnOnce, ClosureKind::FnOnce) => true,
_ => false,
}
matches!(
(self, other),
(ClosureKind::Fn, ClosureKind::Fn)
| (ClosureKind::Fn, ClosureKind::FnMut)
| (ClosureKind::Fn, ClosureKind::FnOnce)
| (ClosureKind::FnMut, ClosureKind::FnMut)
| (ClosureKind::FnMut, ClosureKind::FnOnce)
| (ClosureKind::FnOnce, ClosureKind::FnOnce)
)
}
/// Returns the representative scalar type for this closure kind.
@ -2815,15 +2815,15 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
let is_associated_item = if let Some(def_id) = def_id.as_local() {
match self.hir().get(self.hir().local_def_id_to_hir_id(def_id)) {
Node::TraitItem(_) | Node::ImplItem(_) => true,
_ => false,
}
matches!(
self.hir().get(self.hir().local_def_id_to_hir_id(def_id)),
Node::TraitItem(_) | Node::ImplItem(_)
)
} else {
match self.def_kind(def_id) {
DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true,
_ => false,
}
matches!(
self.def_kind(def_id),
DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy
)
};
is_associated_item.then(|| self.associated_item(def_id))
@ -3034,10 +3034,12 @@ impl<'tcx> TyCtxt<'tcx> {
.hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
}
fn expansion_that_defined(self, scope: DefId) -> ExpnId {
pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
match scope.as_local() {
// Parsing and expansion aren't incremental, so we don't
// need to go through a query for the same-crate case.
Some(scope) => self.hir().definitions().expansion_that_defined(scope),
None => ExpnId::root(),
None => self.expn_that_defined(scope),
}
}

View File

@ -1763,10 +1763,7 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_never(&self) -> bool {
match self.kind() {
Never => true,
_ => false,
}
matches!(self.kind(), Never)
}
/// Checks whether a type is definitely uninhabited. This is
@ -1823,34 +1820,22 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_adt(&self) -> bool {
match self.kind() {
Adt(..) => true,
_ => false,
}
matches!(self.kind(), Adt(..))
}
#[inline]
pub fn is_ref(&self) -> bool {
match self.kind() {
Ref(..) => true,
_ => false,
}
matches!(self.kind(), Ref(..))
}
#[inline]
pub fn is_ty_var(&self) -> bool {
match self.kind() {
Infer(TyVar(_)) => true,
_ => false,
}
matches!(self.kind(), Infer(TyVar(_)))
}
#[inline]
pub fn is_ty_infer(&self) -> bool {
match self.kind() {
Infer(_) => true,
_ => false,
}
matches!(self.kind(), Infer(_))
}
#[inline]
@ -1880,20 +1865,14 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_slice(&self) -> bool {
match self.kind() {
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind() {
Slice(_) | Str => true,
_ => false,
},
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str),
_ => false,
}
}
#[inline]
pub fn is_array(&self) -> bool {
match self.kind() {
Array(..) => true,
_ => false,
}
matches!(self.kind(), Array(..))
}
#[inline]
@ -1940,27 +1919,21 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_region_ptr(&self) -> bool {
match self.kind() {
Ref(..) => true,
_ => false,
}
matches!(self.kind(), Ref(..))
}
#[inline]
pub fn is_mutable_ptr(&self) -> bool {
match self.kind() {
matches!(
self.kind(),
RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
| Ref(_, _, hir::Mutability::Mut) => true,
_ => false,
}
| Ref(_, _, hir::Mutability::Mut)
)
}
#[inline]
pub fn is_unsafe_ptr(&self) -> bool {
match self.kind() {
RawPtr(_) => true,
_ => false,
}
matches!(self.kind(), RawPtr(_))
}
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
@ -1990,35 +1963,22 @@ impl<'tcx> TyS<'tcx> {
/// contents are abstract to rustc.)
#[inline]
pub fn is_scalar(&self) -> bool {
match self.kind() {
Bool
| Char
| Int(_)
| Float(_)
| Uint(_)
matches!(
self.kind(),
Bool | Char | Int(_) | Float(_) | Uint(_) | FnDef(..) | FnPtr(_) | RawPtr(_)
| Infer(IntVar(_) | FloatVar(_))
| FnDef(..)
| FnPtr(_)
| RawPtr(_) => true,
_ => false,
}
)
}
/// Returns `true` if this type is a floating point type.
#[inline]
pub fn is_floating_point(&self) -> bool {
match self.kind() {
Float(_) | Infer(FloatVar(_)) => true,
_ => false,
}
matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
}
#[inline]
pub fn is_trait(&self) -> bool {
match self.kind() {
Dynamic(..) => true,
_ => false,
}
matches!(self.kind(), Dynamic(..))
}
#[inline]
@ -2031,52 +1991,32 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_closure(&self) -> bool {
match self.kind() {
Closure(..) => true,
_ => false,
}
matches!(self.kind(), Closure(..))
}
#[inline]
pub fn is_generator(&self) -> bool {
match self.kind() {
Generator(..) => true,
_ => false,
}
matches!(self.kind(), Generator(..))
}
#[inline]
pub fn is_integral(&self) -> bool {
match self.kind() {
Infer(IntVar(_)) | Int(_) | Uint(_) => true,
_ => false,
}
matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
}
#[inline]
pub fn is_fresh_ty(&self) -> bool {
match self.kind() {
Infer(FreshTy(_)) => true,
_ => false,
}
matches!(self.kind(), Infer(FreshTy(_)))
}
#[inline]
pub fn is_fresh(&self) -> bool {
match self.kind() {
Infer(FreshTy(_)) => true,
Infer(FreshIntTy(_)) => true,
Infer(FreshFloatTy(_)) => true,
_ => false,
}
matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
}
#[inline]
pub fn is_char(&self) -> bool {
match self.kind() {
Char => true,
_ => false,
}
matches!(self.kind(), Char)
}
#[inline]
@ -2086,34 +2026,22 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_signed(&self) -> bool {
match self.kind() {
Int(_) => true,
_ => false,
}
matches!(self.kind(), Int(_))
}
#[inline]
pub fn is_ptr_sized_integral(&self) -> bool {
match self.kind() {
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
_ => false,
}
matches!(self.kind(), Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize))
}
#[inline]
pub fn is_machine(&self) -> bool {
match self.kind() {
Int(..) | Uint(..) | Float(..) => true,
_ => false,
}
matches!(self.kind(), Int(..) | Uint(..) | Float(..))
}
#[inline]
pub fn has_concrete_skeleton(&self) -> bool {
match self.kind() {
Param(_) | Infer(_) | Error(_) => false,
_ => true,
}
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
}
/// Returns the type and mutability of `*ty`.
@ -2156,26 +2084,17 @@ impl<'tcx> TyS<'tcx> {
#[inline]
pub fn is_fn(&self) -> bool {
match self.kind() {
FnDef(..) | FnPtr(_) => true,
_ => false,
}
matches!(self.kind(), FnDef(..) | FnPtr(_))
}
#[inline]
pub fn is_fn_ptr(&self) -> bool {
match self.kind() {
FnPtr(_) => true,
_ => false,
}
matches!(self.kind(), FnPtr(_))
}
#[inline]
pub fn is_impl_trait(&self) -> bool {
match self.kind() {
Opaque(..) => true,
_ => false,
}
matches!(self.kind(), Opaque(..))
}
#[inline]

View File

@ -1225,7 +1225,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// it. However, it works pretty well in practice. In particular,
/// this is needed to deal with projection outlives bounds like
///
/// <T as Foo<'0>>::Item: '1
/// ```ignore (internal compiler representation so lifetime syntax is invalid)
/// <T as Foo<'0>>::Item: '1
/// ```
///
/// In particular, this routine winds up being important when
/// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the

View File

@ -671,7 +671,8 @@ pub fn write_allocations<'tcx>(
/// Dumps the size and metadata and content of an allocation to the given writer.
/// The expectation is that the caller first prints other relevant metadata, so the exact
/// format of this function is (*without* leading or trailing newline):
/// ```
///
/// ```text
/// size: {}, align: {}) {
/// <bytes>
/// }

View File

@ -31,7 +31,7 @@ crate fn lit_to_const<'tcx>(
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_byte_aligned_bytes(data as &Vec<u8>);
let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}

View File

@ -181,10 +181,9 @@ pub(crate) fn emit_unescape_error(
if suggestion_len > 0 {
suggestion.push('}');
let lo = char_span.lo();
let hi = lo + BytePos(suggestion_len as u32);
let hi = char_span.lo() + BytePos(suggestion_len as u32);
diag.span_suggestion(
span.with_lo(lo).with_hi(hi),
span.with_hi(hi),
"format of unicode escape sequences uses braces",
suggestion,
Applicability::MaybeIncorrect,

View File

@ -38,13 +38,13 @@ pub struct OpaqueTypeDecl<'tcx> {
/// then `substs` would be `['a, T]`.
pub substs: SubstsRef<'tcx>,
/// The span of this particular definition of the opaque type. So
/// The span of this particular definition of the opaque type. So
/// for example:
///
/// ```
/// ```ignore (incomplete snippet)
/// type Foo = impl Baz;
/// fn bar() -> Foo {
/// ^^^ This is the span we are looking for!
/// // ^^^ This is the span we are looking for!
/// ```
///
/// In cases where the fn returns `(impl Trait, impl Trait)` or

View File

@ -1275,7 +1275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Report an error for a struct field expression when there are fields which aren't provided.
///
/// ```ignore (diagnostic)
/// ```text
/// error: missing field `you_can_use_this_field` in initializer of `foo::Foo`
/// --> src/main.rs:8:5
/// |
@ -1327,7 +1327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Report an error for a struct field expression when there are no visible fields.
///
/// ```ignore (diagnostic)
/// ```text
/// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
/// --> src/main.rs:8:5
/// |

View File

@ -1381,7 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
/// inaccessible fields.
///
/// ```ignore (diagnostic)
/// ```text
/// error: pattern requires `..` due to inaccessible fields
/// --> src/main.rs:10:9
/// |
@ -1431,7 +1431,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Returns a diagnostic reporting a struct pattern which does not mention some fields.
///
/// ```ignore (diagnostic)
/// ```text
/// error[E0027]: pattern does not mention field `you_cant_use_this_field`
/// --> src/main.rs:15:9
/// |

View File

@ -98,8 +98,6 @@ pub fn spin_loop() {
/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
@ -108,6 +106,8 @@ pub fn spin_loop() {
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: crate::convert::identity
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "test", issue = "50297")]

View File

@ -246,6 +246,14 @@ impl<T> MaybeUninit<T> {
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
///
/// # Example
///
/// ```
/// use std::mem::MaybeUninit;
///
/// let v: MaybeUninit<Vec<u8>> = MaybeUninit::new(vec![42]);
/// ```
///
/// [`assume_init`]: MaybeUninit::assume_init
#[stable(feature = "maybe_uninit", since = "1.36.0")]
#[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
@ -259,9 +267,15 @@ impl<T> MaybeUninit<T> {
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
///
/// See the [type-level documentation][type] for some examples.
/// See the [type-level documentation][MaybeUninit] for some examples.
///
/// [type]: union.MaybeUninit.html
/// # Example
///
/// ```
/// use std::mem::MaybeUninit;
///
/// let v: MaybeUninit<String> = MaybeUninit::uninit();
/// ```
#[stable(feature = "maybe_uninit", since = "1.36.0")]
#[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
#[inline(always)]

View File

@ -6,11 +6,34 @@
#[cfg(test)]
mod tests;
use crate::convert::TryInto as _;
use crate::error::Error;
use crate::fmt;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::str::FromStr;
trait ReadNumberHelper: crate::marker::Sized {
const ZERO: Self;
fn checked_mul(&self, other: u32) -> Option<Self>;
fn checked_add(&self, other: u32) -> Option<Self>;
}
macro_rules! impl_helper {
($($t:ty)*) => ($(impl ReadNumberHelper for $t {
const ZERO: Self = 0;
#[inline]
fn checked_mul(&self, other: u32) -> Option<Self> {
Self::checked_mul(*self, other.try_into().ok()?)
}
#[inline]
fn checked_add(&self, other: u32) -> Option<Self> {
Self::checked_add(*self, other.try_into().ok()?)
}
})*)
}
impl_helper! { u8 u16 }
struct Parser<'a> {
// parsing as ASCII, so can use byte array
state: &'a [u8],
@ -21,10 +44,6 @@ impl<'a> Parser<'a> {
Parser { state: input.as_bytes() }
}
fn is_eof(&self) -> bool {
self.state.is_empty()
}
/// Run a parser, and restore the pre-parse state if it fails
fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
where
@ -40,26 +59,19 @@ impl<'a> Parser<'a> {
/// Run a parser, but fail if the entire input wasn't consumed.
/// Doesn't run atomically.
fn read_till_eof<T, F>(&mut self, inner: F) -> Option<T>
where
F: FnOnce(&mut Parser<'_>) -> Option<T>,
{
inner(self).filter(|_| self.is_eof())
}
/// Same as read_till_eof, but returns a Result<AddrParseError> on failure
fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
where
F: FnOnce(&mut Parser<'_>) -> Option<T>,
{
self.read_till_eof(inner).ok_or(AddrParseError(()))
let result = inner(self);
if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
}
/// Read the next character from the input
fn read_char(&mut self) -> Option<char> {
self.state.split_first().map(|(&b, tail)| {
self.state = tail;
b as char
char::from(b)
})
}
@ -84,25 +96,26 @@ impl<'a> Parser<'a> {
})
}
// Read a single digit in the given radix. For instance, 0-9 in radix 10;
// 0-9A-F in radix 16.
fn read_digit(&mut self, radix: u32) -> Option<u32> {
self.read_atomically(move |p| p.read_char()?.to_digit(radix))
}
// Read a number off the front of the input in the given radix, stopping
// at the first non-digit character or eof. Fails if the number has more
// digits than max_digits, or the value is >= upto, or if there is no number.
fn read_number(&mut self, radix: u32, max_digits: u32, upto: u32) -> Option<u32> {
// digits than max_digits or if there is no number.
fn read_number<T: ReadNumberHelper>(
&mut self,
radix: u32,
max_digits: Option<usize>,
) -> Option<T> {
self.read_atomically(move |p| {
let mut result = 0;
let mut result = T::ZERO;
let mut digit_count = 0;
while let Some(digit) = p.read_digit(radix) {
result = (result * radix) + digit;
while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
result = result.checked_mul(radix)?;
result = result.checked_add(digit)?;
digit_count += 1;
if digit_count > max_digits || result >= upto {
return None;
if let Some(max_digits) = max_digits {
if digit_count > max_digits {
return None;
}
}
}
@ -116,7 +129,7 @@ impl<'a> Parser<'a> {
let mut groups = [0; 4];
for (i, slot) in groups.iter_mut().enumerate() {
*slot = p.read_separator('.', i, |p| p.read_number(10, 3, 0x100))? as u8;
*slot = p.read_separator('.', i, |p| p.read_number(10, None))?;
}
Some(groups.into())
@ -140,17 +153,17 @@ impl<'a> Parser<'a> {
let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
if let Some(v4_addr) = ipv4 {
let octets = v4_addr.octets();
groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
let [one, two, three, four] = v4_addr.octets();
groups[i + 0] = u16::from_be_bytes([one, two]);
groups[i + 1] = u16::from_be_bytes([three, four]);
return (i + 2, true);
}
}
let group = p.read_separator(':', i, |p| p.read_number(16, 4, 0x10000));
let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));
match group {
Some(g) => *slot = g as u16,
Some(g) => *slot = g,
None => return (i, false),
}
}
@ -195,12 +208,11 @@ impl<'a> Parser<'a> {
self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6))
}
/// Read a : followed by a port in base 10
/// Read a : followed by a port in base 10.
fn read_port(&mut self) -> Option<u16> {
self.read_atomically(|p| {
let _ = p.read_given_char(':')?;
let port = p.read_number(10, 5, 0x10000)?;
Some(port as u16)
p.read_number(10, None)
})
}

View File

@ -100,6 +100,11 @@ pub use core::time::Duration;
/// [clock_time_get (Monotonic Clock)]: https://nuxi.nl/cloudabi/#clock_time_get
///
/// **Disclaimer:** These system calls might change over time.
///
/// > Note: mathematical operations like [`add`] may panic if the underlying
/// > structure cannot represent the new point in time.
///
/// [`add`]: Instant::add
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct Instant(time::Instant);
@ -174,6 +179,11 @@ pub struct Instant(time::Instant);
/// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime
///
/// **Disclaimer:** These system calls might change over time.
///
/// > Note: mathematical operations like [`add`] may panic if the underlying
/// > structure cannot represent the new point in time.
///
/// [`add`]: SystemTime::add
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct SystemTime(time::SystemTime);

View File

@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Non-breaking changes since the last major version]
- `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
- The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558)
## [Version 2] - 2020-09-25

View File

@ -574,7 +574,7 @@ impl Config {
include_path.push("src");
include_path.push("bootstrap");
include_path.push("defaults");
include_path.push(format!("config.toml.{}", include));
include_path.push(format!("config.{}.toml", include));
let included_toml = get_toml(&include_path);
toml.merge(included_toml);
}

View File

@ -20,7 +20,7 @@ pub fn setup(src_path: &Path, include_name: &str) {
file.display()
);
println!(
"note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
"note: this will use the configuration in {}/src/bootstrap/defaults/config.{}.toml",
src_path.display(),
include_name
);
@ -36,7 +36,7 @@ pub fn setup(src_path: &Path, include_name: &str) {
t!(fs::write(path, settings));
let include_path =
format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name);
format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), include_name);
println!("`x.py` will now use the configuration at {}", include_path);
let suggestions = match include_name {

View File

@ -2,7 +2,7 @@
The features listed on this page fall outside the rest of the main categories.
## `#[cfg(doc)]`: Documenting platform-/feature-specific information
## `#[cfg(doc)]`: Documenting platform-specific or feature-specific information
For conditional compilation, Rustdoc treats your crate the same way the compiler does. Only things
from the host target are available (or from the given `--target` if present), and everything else is
@ -17,7 +17,7 @@ with other `#[cfg]` filters on it, you can write something like `#[cfg(any(windo
This will preserve the item either when built normally on Windows, or when being documented
anywhere.
Please note that this feature is not passed to doctests.
Please note that this `cfg` is not passed to doctests.
Example:
@ -33,6 +33,40 @@ pub struct UnixToken;
Here, the respective tokens can only be used by dependent crates on their respective platforms, but
they will both appear in documentation.
### Interactions between platform-specific docs
Rustdoc does not have a magic way to compile documentation 'as-if' you'd run it once for each
platform (such a magic wand has been called the ['holy grail of rustdoc'][#1998]). Instead,
it sees *all* of your code at once, the same way the Rust compiler would if you passed it
`--cfg doc`. However, Rustdoc has a trick up its sleeve to handle platform-specific code if it
*does* receive it.
To document your crate, Rustdoc only needs to know the public signature of your functions.
In particular, it doesn't have to know how any of your functions are implemented, so it ignores
all type errors and name resolution errors with function bodies. Note that this does *not*
work for anything outside a function body: since Rustdoc documents your types, it has to
know what those types are! For example, this code will work regardless of the platform:
<!-- `ignore` because doc-tests are run with `rustc`, not `rustdoc` -->
```ignore
pub fn f() {
use std::os::windows::ffi::OsStrExt;
}
```
but this will not, because the unknown type is part of the function signature:
```ignore
pub fn f() -> std::os::windows::ffi::EncodeWide<'static> {
unimplemented!()
}
```
For a more realistic example of code this allows, see [the rustdoc test suite][realistic-async].
[#1998]: https://github.com/rust-lang/rust/issues/1998
[realistic-async]: https://github.com/rust-lang/rust/blob/b146000e910ccd60bdcde89363cb6aa14ecc0d95/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
## Add aliases for an item in documentation search
This feature allows you to add alias(es) to an item when using the `rustdoc` search through the

View File

@ -43,28 +43,16 @@ plain text.
These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler
and enabled with a `#![feature(...)]` attribute in your crate.
### Documenting platform-/feature-specific information
### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
Because of the way Rustdoc documents a crate, the documentation it creates is specific to the target
rustc compiles for. Anything that's specific to any other target is dropped via `#[cfg]` attribute
processing early in the compilation process. However, Rustdoc has a trick up its sleeve to handle
platform-specific code if it *does* receive it.
You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
This has two effects:
Because Rustdoc doesn't need to fully compile a crate to binary, it replaces function bodies with
`loop {}` to prevent having to process more than necessary. This means that any code within a
function that requires platform-specific pieces is ignored. Combined with a special attribute,
`#[doc(cfg(...))]`, you can tell Rustdoc exactly which platform something is supposed to run on,
ensuring that doctests are only run on the appropriate platforms.
The `#[doc(cfg(...))]` attribute has another effect: When Rustdoc renders documentation for that
item, it will be accompanied by a banner explaining that the item is only available on certain
platforms.
For Rustdoc to document an item, it needs to see it, regardless of what platform it's currently
running on. To aid this, Rustdoc sets the flag `#[cfg(doc)]` when running on your crate.
Combining this with the target platform of a given item allows it to appear when building your crate
normally on that platform, as well as when building documentation anywhere.
1. doctests will only run on the appropriate platforms, and
2. When Rustdoc renders documentation for that item, it will be accompanied by a banner explaining
that the item is only available on certain platforms.
`#[doc(cfg)]` is intended to be used alongside [`#[cfg(doc)]`][cfg-doc].
For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the
documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that
the item is supposed to be used on Windows. For example:
@ -81,6 +69,12 @@ pub struct WindowsToken;
#[cfg(any(unix, doc))]
#[doc(cfg(unix))]
pub struct UnixToken;
/// Token struct that is only available with the `serde` feature
#[cfg(feature = "serde")]
#[doc(cfg(feature = "serde"))]
#[derive(serde::Deserialize)]
pub struct SerdeToken;
```
In this sample, the tokens will only appear on their respective platforms, but they will both appear
@ -90,6 +84,7 @@ in documentation.
`#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
[cfg-doc]: ./advanced-features.md
[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781

View File

@ -2,9 +2,7 @@ error: incorrect unicode escape sequence
--> $DIR/format-string-error-2.rs:77:20
|
LL | println!("\x7B}\u8 {", 1);
| ^^-
| |
| help: format of unicode escape sequences uses braces: `\u{8}`
| ^^^ help: format of unicode escape sequences uses braces: `\u{8}`
error: invalid format string: expected `'}'`, found `'a'`
--> $DIR/format-string-error-2.rs:5:5

View File

@ -0,0 +1,7 @@
// edition:2018
extern crate opaque_hygiene;
pub async fn serve() {
opaque_hygiene::make_it!();
}

View File

@ -0,0 +1,21 @@
// force-host
// no-prefer-dynamic
#![feature(proc_macro_quote)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::{TokenStream, quote};
#[proc_macro]
pub fn make_it(input: TokenStream) -> TokenStream {
// `quote!` applies def-site hygiene
quote! {
trait Foo {
fn my_fn(&self) {}
}
impl<T> Foo for T {}
"a".my_fn();
}
}

View File

@ -0,0 +1,19 @@
// build-pass
// aux-build:opaque-hygiene.rs
// aux-build:def-site-async-await.rs
// Regression test for issue #77523
// Tests that we don't ICE when an unusual combination
// of def-site hygiene and cross-crate monomorphization occurs.
extern crate def_site_async_await;
use std::future::Future;
fn mk_ctxt() -> std::task::Context<'static> {
panic!()
}
fn main() {
Box::pin(def_site_async_await::serve()).as_mut().poll(&mut mk_ctxt());
}

View File

@ -0,0 +1,49 @@
// This test is checking that you cannot override a `forbid` by adding in other
// attributes later in the same scope. (We already ensure that you cannot
// override it in nested scopes).
// If you turn off deduplicate diagnostics (which rustc turns on by default but
// compiletest turns off when it runs ui tests), then the errors are
// (unfortunately) repeated here because the checking is done as we read in the
// errors, and curretly that happens two or three different times, depending on
// compiler flags.
//
// I decided avoiding the redundant output was not worth the time in engineering
// effort for bug like this, which 1. end users are unlikely to run into in the
// first place, and 2. they won't see the redundant output anyway.
// compile-flags: -Z deduplicate-diagnostics=yes
fn forbid_first(num: i32) -> i32 {
#![forbid(unused)]
#![deny(unused)]
//~^ ERROR: deny(unused) incompatible with previous forbid in same scope [E0453]
#![warn(unused)]
//~^ ERROR: warn(unused) incompatible with previous forbid in same scope [E0453]
#![allow(unused)]
//~^ ERROR: allow(unused) incompatible with previous forbid in same scope [E0453]
num * num
}
fn forbid_last(num: i32) -> i32 {
#![deny(unused)]
#![warn(unused)]
#![allow(unused)]
#![forbid(unused)]
num * num
}
fn forbid_multiple(num: i32) -> i32 {
#![forbid(unused)]
#![forbid(unused)]
num * num
}
fn main() {
forbid_first(10);
forbid_last(10);
forbid_multiple(10);
}

View File

@ -0,0 +1,29 @@
error[E0453]: deny(unused) incompatible with previous forbid in same scope
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13
|
LL | #![forbid(unused)]
| ------ `forbid` level set here
LL | #![deny(unused)]
| ^^^^^^
error[E0453]: warn(unused) incompatible with previous forbid in same scope
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13
|
LL | #![forbid(unused)]
| ------ `forbid` level set here
...
LL | #![warn(unused)]
| ^^^^^^
error[E0453]: allow(unused) incompatible with previous forbid in same scope
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14
|
LL | #![forbid(unused)]
| ------ `forbid` level set here
...
LL | #![allow(unused)]
| ^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0453`.

View File

@ -80,9 +80,9 @@ error: incorrect unicode escape sequence
--> $DIR/issue-23620-invalid-escapes.rs:32:14
|
LL | let _ = "\u8f";
| ^^--
| |
| help: format of unicode escape sequences uses braces: `\u{8f}`
| ^^^-
| |
| help: format of unicode escape sequences uses braces: `\u{8f}`
error: aborting due to 13 previous errors

View File

@ -8,8 +8,8 @@ extern "C" {
#[allow(unused_mut)] a: i32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))] c: i32,
#[deny(unused_mut)] d: i32,
#[forbid(unused_mut)] #[warn(unused_mut)] ...
#[forbid(unused_mut)] d: i32,
#[deny(unused_mut)] #[warn(unused_mut)] ...
);
}
@ -17,16 +17,16 @@ type FnType = fn(
#[allow(unused_mut)] a: i32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))] c: i32,
#[deny(unused_mut)] d: i32,
#[forbid(unused_mut)] #[warn(unused_mut)] e: i32
#[forbid(unused_mut)] d: i32,
#[deny(unused_mut)] #[warn(unused_mut)] e: i32
);
pub fn foo(
#[allow(unused_mut)] a: i32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))] c: i32,
#[deny(unused_mut)] d: i32,
#[forbid(unused_mut)] #[warn(unused_mut)] _e: i32
#[forbid(unused_mut)] d: i32,
#[deny(unused_mut)] #[warn(unused_mut)] _e: i32
) {}
// self

View File

@ -155,7 +155,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)),
LitKind::ByteStr(ref s) => Constant::Binary(Lrc::from(s.as_slice())),
LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
LitKind::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n),
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {

View File

@ -3,7 +3,6 @@
// Test that the whole restriction group is not enabled
#![warn(clippy::restriction)]
#![deny(clippy::restriction)]
#![forbid(clippy::restriction)]
#![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
#[inline(always)]

View File

@ -1,5 +1,5 @@
error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
--> $DIR/attrs.rs:9:1
--> $DIR/attrs.rs:8:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
@ -7,7 +7,7 @@ LL | #[inline(always)]
= note: `-D clippy::inline-always` implied by `-D warnings`
error: the since field must contain a semver-compliant version
--> $DIR/attrs.rs:29:14
--> $DIR/attrs.rs:28:14
|
LL | #[deprecated(since = "forever")]
| ^^^^^^^^^^^^^^^^^
@ -15,7 +15,7 @@ LL | #[deprecated(since = "forever")]
= note: `-D clippy::deprecated-semver` implied by `-D warnings`
error: the since field must contain a semver-compliant version
--> $DIR/attrs.rs:32:14
--> $DIR/attrs.rs:31:14
|
LL | #[deprecated(since = "1")]
| ^^^^^^^^^^^
@ -37,13 +37,5 @@ LL | #![deny(clippy::restriction)]
|
= help: try enabling only the lints you really need
error: restriction lints are not meant to be all enabled
--> $DIR/attrs.rs:6:11
|
LL | #![forbid(clippy::restriction)]
| ^^^^^^^^^^^^^^^^^^^
|
= help: try enabling only the lints you really need
error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

View File

@ -3,6 +3,7 @@ allow-unauthenticated = [
"C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
"D-*",
"requires-nightly",
"regression-*",
# I-* without I-nominated
"I-*", "!I-nominated",
"AsyncAwait-OnDeck",