mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #116492 - matthiaskrgr:rollup-xzfhmq1, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #114564 (Attempt to describe the intent behind the `From` trait further) - #116297 (add some docs to hooks/mod.rs) - #116423 (Fix typo in attrs.rs) - #116466 (`rustc_transmute` cleanups) - #116474 (Assorted small cleanups) - #116481 (Reuse existing `Some`s in `Option::(x)or`) - #116484 (Minor doc clarification in Once::call_once) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
960754090a
@ -4335,7 +4335,6 @@ dependencies = [
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
@ -4441,7 +4440,6 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_interface",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"stable_mir",
|
||||
|
@ -353,28 +353,28 @@ pub fn find_body_stability(
|
||||
body_stab
|
||||
}
|
||||
|
||||
fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {
|
||||
if item.is_some() {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
meta.span,
|
||||
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
|
||||
);
|
||||
None
|
||||
} else if let Some(v) = meta.value_str() {
|
||||
*item = Some(v);
|
||||
Some(())
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
|
||||
/// its stability information.
|
||||
fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
|
||||
let meta = attr.meta()?;
|
||||
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
|
||||
let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||
if item.is_some() {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
meta.span,
|
||||
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if let Some(v) = meta.value_str() {
|
||||
*item = Some(v);
|
||||
true
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let mut feature = None;
|
||||
let mut since = None;
|
||||
@ -389,16 +389,8 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
};
|
||||
|
||||
match mi.name_or_empty() {
|
||||
sym::feature => {
|
||||
if !insert_or_error(mi, &mut feature) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
sym::since => {
|
||||
if !insert_or_error(mi, &mut since) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
sym::feature => insert_or_error(sess, mi, &mut feature)?,
|
||||
sym::since => insert_or_error(sess, mi, &mut since)?,
|
||||
_ => {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
@ -438,23 +430,6 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
|
||||
let meta = attr.meta()?;
|
||||
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
|
||||
let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||
if item.is_some() {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
meta.span,
|
||||
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if let Some(v) = meta.value_str() {
|
||||
*item = Some(v);
|
||||
true
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let mut feature = None;
|
||||
let mut reason = None;
|
||||
@ -473,20 +448,10 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
};
|
||||
|
||||
match mi.name_or_empty() {
|
||||
sym::feature => {
|
||||
if !insert_or_error(mi, &mut feature) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
sym::reason => {
|
||||
if !insert_or_error(mi, &mut reason) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
sym::feature => insert_or_error(sess, mi, &mut feature)?,
|
||||
sym::reason => insert_or_error(sess, mi, &mut reason)?,
|
||||
sym::issue => {
|
||||
if !insert_or_error(mi, &mut issue) {
|
||||
return None;
|
||||
}
|
||||
insert_or_error(sess, mi, &mut issue)?;
|
||||
|
||||
// These unwraps are safe because `insert_or_error` ensures the meta item
|
||||
// is a name/value pair string literal.
|
||||
@ -515,11 +480,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
}
|
||||
is_soft = true;
|
||||
}
|
||||
sym::implied_by => {
|
||||
if !insert_or_error(mi, &mut implied_by) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?,
|
||||
_ => {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
|
@ -1,3 +1,8 @@
|
||||
//! "Hooks" provide a way for `tcx` functionality to be provided by some downstream crate without
|
||||
//! everything in rustc having to depend on that crate. This is somewhat similar to queries, but
|
||||
//! queries come with a lot of machinery for caching and incremental compilation, whereas hooks are
|
||||
//! just plain function pointers without any of the query magic.
|
||||
|
||||
use crate::mir;
|
||||
use crate::query::TyCtxtAt;
|
||||
use crate::ty::{Ty, TyCtxt};
|
||||
|
@ -13,7 +13,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
|
@ -813,7 +813,6 @@ impl Input {
|
||||
FileName::Anon(_) => None,
|
||||
FileName::MacroExpansion(_) => None,
|
||||
FileName::ProcMacroSourceCode(_) => None,
|
||||
FileName::CfgSpec(_) => None,
|
||||
FileName::CliCrateAttr(_) => None,
|
||||
FileName::Custom(_) => None,
|
||||
FileName::DocTest(path, _) => Some(path),
|
||||
|
@ -4,14 +4,13 @@ version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rustc_driver = { path = "../rustc_driver" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_interface = { path = "../rustc_interface" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_driver = { path = "../rustc_driver" }
|
||||
rustc_interface = { path = "../rustc_interface" }
|
||||
rustc_session = {path = "../rustc_session" }
|
||||
tracing = "0.1"
|
||||
stable_mir = {path = "../stable_mir" }
|
||||
tracing = "0.1"
|
||||
|
||||
[features]
|
||||
|
@ -10,10 +10,6 @@
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
|
||||
test(attr(allow(unused_variables), deny(warnings)))
|
||||
)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(type_alias_impl_trait)] // Used to define opaque types.
|
||||
#![feature(intra_doc_pointers)]
|
||||
|
||||
pub mod rustc_internal;
|
||||
|
||||
|
@ -11,7 +11,7 @@ use rustc_driver::{Callbacks, Compilation, RunCompiler};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_middle::mir::interpret::AllocId;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
pub use rustc_span::def_id::{CrateNum, DefId};
|
||||
use rustc_span::def_id::{CrateNum, DefId};
|
||||
use rustc_span::Span;
|
||||
use stable_mir::CompilerError;
|
||||
|
||||
|
@ -280,8 +280,7 @@ impl RealFileName {
|
||||
}
|
||||
|
||||
/// Differentiates between real files and common virtual files.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
|
||||
#[derive(Decodable, Encodable)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)]
|
||||
pub enum FileName {
|
||||
Real(RealFileName),
|
||||
/// Call to `quote!`.
|
||||
@ -292,8 +291,6 @@ pub enum FileName {
|
||||
// FIXME(jseyfried)
|
||||
MacroExpansion(Hash64),
|
||||
ProcMacroSourceCode(Hash64),
|
||||
/// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
|
||||
CfgSpec(Hash64),
|
||||
/// Strings provided as crate attributes in the CLI.
|
||||
CliCrateAttr(Hash64),
|
||||
/// Custom sources for explicit parser calls from plugins and drivers.
|
||||
@ -338,7 +335,6 @@ impl fmt::Display for FileNameDisplay<'_> {
|
||||
MacroExpansion(_) => write!(fmt, "<macro expansion>"),
|
||||
Anon(_) => write!(fmt, "<anon>"),
|
||||
ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
|
||||
CfgSpec(_) => write!(fmt, "<cfgspec>"),
|
||||
CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
|
||||
Custom(ref s) => write!(fmt, "<{s}>"),
|
||||
DocTest(ref path, _) => write!(fmt, "{}", path.display()),
|
||||
@ -364,7 +360,6 @@ impl FileName {
|
||||
Anon(_)
|
||||
| MacroExpansion(_)
|
||||
| ProcMacroSourceCode(_)
|
||||
| CfgSpec(_)
|
||||
| CliCrateAttr(_)
|
||||
| Custom(_)
|
||||
| QuoteExpansion(_)
|
||||
|
@ -9,7 +9,7 @@ extern crate tracing;
|
||||
pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
|
||||
|
||||
pub mod layout;
|
||||
pub(crate) mod maybe_transmutable;
|
||||
mod maybe_transmutable;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Assume {
|
||||
@ -19,7 +19,7 @@ pub struct Assume {
|
||||
pub validity: bool,
|
||||
}
|
||||
|
||||
/// Either we have an error, transmutation is allowed, or we have an optional
|
||||
/// Either transmutation is allowed, we have an error, or we have an optional
|
||||
/// Condition that must hold.
|
||||
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
|
||||
pub enum Answer<R> {
|
||||
|
@ -32,26 +32,6 @@ where
|
||||
) -> Self {
|
||||
Self { src, dst, scope, assume, context }
|
||||
}
|
||||
|
||||
// FIXME(bryangarza): Delete this when all usages are removed
|
||||
pub(crate) fn map_layouts<F, M>(
|
||||
self,
|
||||
f: F,
|
||||
) -> Result<MaybeTransmutableQuery<M, C>, Answer<<C as QueryContext>::Ref>>
|
||||
where
|
||||
F: FnOnce(
|
||||
L,
|
||||
L,
|
||||
<C as QueryContext>::Scope,
|
||||
&C,
|
||||
) -> Result<(M, M), Answer<<C as QueryContext>::Ref>>,
|
||||
{
|
||||
let Self { src, dst, scope, assume, context } = self;
|
||||
|
||||
let (src, dst) = f(src, dst, scope, &context)?;
|
||||
|
||||
Ok(MaybeTransmutableQuery { src, dst, scope, assume, context })
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Nix this cfg, so we can write unit tests independently of rustc
|
||||
@ -107,42 +87,42 @@ where
|
||||
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
|
||||
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
||||
let assume_visibility = self.assume.safety;
|
||||
// FIXME(bryangarza): Refactor this code to get rid of `map_layouts`
|
||||
let query_or_answer = self.map_layouts(|src, dst, scope, context| {
|
||||
// Remove all `Def` nodes from `src`, without checking their visibility.
|
||||
let src = src.prune(&|def| true);
|
||||
|
||||
trace!(?src, "pruned src");
|
||||
let Self { src, dst, scope, assume, context } = self;
|
||||
|
||||
// Remove all `Def` nodes from `dst`, additionally...
|
||||
let dst = if assume_visibility {
|
||||
// ...if visibility is assumed, don't check their visibility.
|
||||
dst.prune(&|def| true)
|
||||
} else {
|
||||
// ...otherwise, prune away all unreachable paths through the `Dst` layout.
|
||||
dst.prune(&|def| context.is_accessible_from(def, scope))
|
||||
};
|
||||
// Remove all `Def` nodes from `src`, without checking their visibility.
|
||||
let src = src.prune(&|def| true);
|
||||
|
||||
trace!(?dst, "pruned dst");
|
||||
trace!(?src, "pruned src");
|
||||
|
||||
// Convert `src` from a tree-based representation to an NFA-based representation.
|
||||
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
|
||||
// is acceptable, because instances of the `src` type do not exist.
|
||||
let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?;
|
||||
// Remove all `Def` nodes from `dst`, additionally...
|
||||
let dst = if assume_visibility {
|
||||
// ...if visibility is assumed, don't check their visibility.
|
||||
dst.prune(&|def| true)
|
||||
} else {
|
||||
// ...otherwise, prune away all unreachable paths through the `Dst` layout.
|
||||
dst.prune(&|def| context.is_accessible_from(def, scope))
|
||||
};
|
||||
|
||||
// Convert `dst` from a tree-based representation to an NFA-based representation.
|
||||
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
|
||||
// is unacceptable, because instances of the `dst` type do not exist.
|
||||
let dst =
|
||||
Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?;
|
||||
trace!(?dst, "pruned dst");
|
||||
|
||||
Ok((src, dst))
|
||||
});
|
||||
// Convert `src` from a tree-based representation to an NFA-based representation.
|
||||
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
|
||||
// is acceptable, because instances of the `src` type do not exist.
|
||||
let src = match Nfa::from_tree(src) {
|
||||
Ok(src) => src,
|
||||
Err(Uninhabited) => return Answer::Yes,
|
||||
};
|
||||
|
||||
match query_or_answer {
|
||||
Ok(query) => query.answer(),
|
||||
Err(answer) => answer,
|
||||
}
|
||||
// Convert `dst` from a tree-based representation to an NFA-based representation.
|
||||
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
|
||||
// is unacceptable, because instances of the `dst` type do not exist.
|
||||
let dst = match Nfa::from_tree(dst) {
|
||||
Ok(dst) => dst,
|
||||
Err(Uninhabited) => return Answer::No(Reason::DstIsPrivate),
|
||||
};
|
||||
|
||||
MaybeTransmutableQuery { src, dst, scope, assume, context }.answer()
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,14 +136,10 @@ where
|
||||
#[inline(always)]
|
||||
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
|
||||
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
||||
// FIXME(bryangarza): Refactor this code to get rid of `map_layouts`
|
||||
let query_or_answer = self
|
||||
.map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst))));
|
||||
|
||||
match query_or_answer {
|
||||
Ok(query) => query.answer(),
|
||||
Err(answer) => answer,
|
||||
}
|
||||
let Self { src, dst, scope, assume, context } = self;
|
||||
let src = Dfa::from_nfa(src);
|
||||
let dst = Dfa::from_nfa(dst);
|
||||
MaybeTransmutableQuery { src, dst, scope, assume, context }.answer()
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,26 +147,8 @@ impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
|
||||
where
|
||||
C: QueryContext,
|
||||
{
|
||||
/// Answers whether a `Nfa` is transmutable into another `Nfa`.
|
||||
///
|
||||
/// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
|
||||
/// Answers whether a `Dfa` is transmutable into another `Dfa`.
|
||||
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
||||
MaybeTransmutableQuery {
|
||||
src: &self.src,
|
||||
dst: &self.dst,
|
||||
scope: self.scope,
|
||||
assume: self.assume,
|
||||
context: self.context,
|
||||
}
|
||||
.answer()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l, C> MaybeTransmutableQuery<&'l Dfa<<C as QueryContext>::Ref>, C>
|
||||
where
|
||||
C: QueryContext,
|
||||
{
|
||||
pub(crate) fn answer(&mut self) -> Answer<<C as QueryContext>::Ref> {
|
||||
self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
|
||||
}
|
||||
|
||||
|
@ -479,6 +479,46 @@ pub trait Into<T>: Sized {
|
||||
/// - `From<T> for U` implies [`Into`]`<U> for T`
|
||||
/// - `From` is reflexive, which means that `From<T> for T` is implemented
|
||||
///
|
||||
/// # When to implement `From`
|
||||
///
|
||||
/// While there's no technical restrictions on which conversions can be done using
|
||||
/// a `From` implementation, the general expectation is that the conversions
|
||||
/// should typically be restricted as follows:
|
||||
///
|
||||
/// * The conversion is *infallible*: if the conversion can fail, use [`TryFrom`]
|
||||
/// instead; don't provide a `From` impl that panics.
|
||||
///
|
||||
/// * The conversion is *lossless*: semantically, it should not lose or discard
|
||||
/// information. For example, `i32: From<u16>` exists, where the original
|
||||
/// value can be recovered using `u16: TryFrom<i32>`. And `String: From<&str>`
|
||||
/// exists, where you can get something equivalent to the original value via
|
||||
/// `Deref`. But `From` cannot be used to convert from `u32` to `u16`, since
|
||||
/// that cannot succeed in a lossless way. (There's some wiggle room here for
|
||||
/// information not considered semantically relevant. For example,
|
||||
/// `Box<[T]>: From<Vec<T>>` exists even though it might not preserve capacity,
|
||||
/// like how two vectors can be equal despite differing capacities.)
|
||||
///
|
||||
/// * The conversion is *value-preserving*: the conceptual kind and meaning of
|
||||
/// the resulting value is the same, even though the Rust type and technical
|
||||
/// representation might be different. For example `-1_i8 as u8` is *lossless*,
|
||||
/// since `as` casting back can recover the original value, but that conversion
|
||||
/// is *not* available via `From` because `-1` and `255` are different conceptual
|
||||
/// values (despite being identical bit patterns technically). But
|
||||
/// `f32: From<i16>` *is* available because `1_i16` and `1.0_f32` are conceptually
|
||||
/// the same real number (despite having very different bit patterns technically).
|
||||
/// `String: From<char>` is available because they're both *text*, but
|
||||
/// `String: From<u32>` is *not* available, since `1` (a number) and `"1"`
|
||||
/// (text) are too different. (Converting values to text is instead covered
|
||||
/// by the [`Display`](crate::fmt::Display) trait.)
|
||||
///
|
||||
/// * The conversion is *obvious*: it's the only reasonable conversion between
|
||||
/// the two types. Otherwise it's better to have it be a named method or
|
||||
/// constructor, like how [`str::as_bytes`] is a method and how integers have
|
||||
/// methods like [`u32::from_ne_bytes`], [`u32::from_le_bytes`], and
|
||||
/// [`u32::from_be_bytes`], none of which are `From` implementations. Whereas
|
||||
/// there's only one reasonable way to wrap an [`Ipv6Addr`](crate::net::Ipv6Addr)
|
||||
/// into an [`IpAddr`](crate::net::IpAddr), thus `IpAddr: From<Ipv6Addr>` exists.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`String`] implements `From<&str>`:
|
||||
|
@ -1475,7 +1475,7 @@ impl<T> Option<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn or(self, optb: Option<T>) -> Option<T> {
|
||||
match self {
|
||||
Some(x) => Some(x),
|
||||
x @ Some(_) => x,
|
||||
None => optb,
|
||||
}
|
||||
}
|
||||
@ -1500,7 +1500,7 @@ impl<T> Option<T> {
|
||||
F: FnOnce() -> Option<T>,
|
||||
{
|
||||
match self {
|
||||
Some(x) => Some(x),
|
||||
x @ Some(_) => x,
|
||||
None => f(),
|
||||
}
|
||||
}
|
||||
@ -1530,8 +1530,8 @@ impl<T> Option<T> {
|
||||
#[stable(feature = "option_xor", since = "1.37.0")]
|
||||
pub fn xor(self, optb: Option<T>) -> Option<T> {
|
||||
match (self, optb) {
|
||||
(Some(a), None) => Some(a),
|
||||
(None, Some(b)) => Some(b),
|
||||
(a @ Some(_), None) => a,
|
||||
(None, b @ Some(_)) => b,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ impl Once {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The closure `f` will only be executed once if this is called
|
||||
/// The closure `f` will only be executed once even if this is called
|
||||
/// concurrently amongst many threads. If that closure panics, however, then
|
||||
/// it will *poison* this [`Once`] instance, causing all future invocations of
|
||||
/// `call_once` to also panic.
|
||||
|
@ -183,7 +183,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for empty lines after documenation comments.
|
||||
/// Checks for empty lines after documentation comments.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The documentation comment was most likely meant to be an inner attribute or regular comment.
|
||||
@ -795,7 +795,7 @@ impl EarlyLintPass for EarlyAttributes {
|
||||
|
||||
/// Check for empty lines after outer attributes.
|
||||
///
|
||||
/// Attributes and documenation comments are both considered outer attributes
|
||||
/// Attributes and documentation comments are both considered outer attributes
|
||||
/// by the AST. However, the average user likely considers them to be different.
|
||||
/// Checking for empty lines after each of these attributes is split into two different
|
||||
/// lints but can share the same logic.
|
||||
|
Loading…
Reference in New Issue
Block a user