Auto merge of #103629 - matthiaskrgr:rollup-r94tqfa, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #103110 (remove redundant Send impl for references) - #103255 (Clean up hidden type registration) - #103394 (Clarify documentation about the memory layout of `UnsafeCell`) - #103408 (Clean return-position `impl Trait` in traits correctly in rustdoc) - #103505 (rustdoc: parse self-closing tags and attributes in `invalid_html_tags`) - #103524 (rustc_metadata: Add struct and variant constructors to module children at encoding time) - #103544 (Add flag to forbid recovery in the parser) - #103616 (rustdoc: remove CSS workaround for Firefox 29) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
126dbdc9c7
@ -263,13 +263,11 @@ fn infer_opaque_definition_from_instantiation(
|
||||
|
||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||
// the bounds that the function supplies.
|
||||
match infcx.register_hidden_type(
|
||||
OpaqueTypeKey { def_id, substs: id_substs },
|
||||
ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
param_env,
|
||||
definition_ty,
|
||||
origin,
|
||||
) {
|
||||
let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
|
||||
match infcx
|
||||
.at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env)
|
||||
.eq(opaque_ty, definition_ty)
|
||||
{
|
||||
Ok(infer_ok) => {
|
||||
for obligation in infer_ok.obligations {
|
||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||
@ -280,7 +278,7 @@ fn infer_opaque_definition_from_instantiation(
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
|
||||
opaque_ty,
|
||||
definition_ty,
|
||||
err,
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
@ -155,27 +155,16 @@ fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn register_opaque_type(
|
||||
fn register_opaque_type_obligations(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
let param_env = self.param_env();
|
||||
let span = self.span();
|
||||
let def_id = self.type_checker.body.source.def_id().expect_local();
|
||||
let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
self.type_checker
|
||||
.fully_perform_op(
|
||||
self.locations,
|
||||
self.category,
|
||||
InstantiateOpaqueType {
|
||||
obligations: self
|
||||
.type_checker
|
||||
.infcx
|
||||
.handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
|
||||
.obligations,
|
||||
obligations,
|
||||
// These fields are filled in during execution of the operation
|
||||
base_universe: None,
|
||||
region_constraints: None,
|
||||
|
@ -250,6 +250,7 @@ fn expand_macro<'cx>(
|
||||
// hacky, but speeds up the `html5ever` benchmark significantly. (Issue
|
||||
// 68836 suggests a more comprehensive but more complex change to deal with
|
||||
// this situation.)
|
||||
// FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
|
||||
let parser = parser_from_cx(sess, arg.clone());
|
||||
|
||||
// Try each arm's matchers.
|
||||
|
@ -16,8 +16,8 @@
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
|
||||
use crate::traits::query::{Fallible, NoSolution};
|
||||
use crate::traits::TraitEngine;
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use crate::traits::{PredicateObligations, TraitEngine};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_index::vec::IndexVec;
|
||||
@ -509,7 +509,7 @@ fn query_response_substitution_guess<R>(
|
||||
for &(a, b) in &query_response.value.opaque_types {
|
||||
let a = substitute_value(self.tcx, &result_subst, a);
|
||||
let b = substitute_value(self.tcx, &result_subst, b);
|
||||
obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
|
||||
obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations);
|
||||
}
|
||||
|
||||
Ok(InferOk { value: result_subst, obligations })
|
||||
@ -741,17 +741,11 @@ fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn register_opaque_type(
|
||||
fn register_opaque_type_obligations(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
self.obligations.extend(
|
||||
self.infcx
|
||||
.handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
|
||||
.obligations,
|
||||
);
|
||||
self.obligations.extend(obligations);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,9 @@
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{ConstVarValue, ConstVariableValue};
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::PredicateObligation;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
@ -91,11 +93,9 @@ fn push_outlives(
|
||||
);
|
||||
|
||||
fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
|
||||
fn register_opaque_type(
|
||||
fn register_opaque_type_obligations(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Result<(), TypeError<'tcx>>;
|
||||
|
||||
/// Creates a new universe index. Used when instantiating placeholders.
|
||||
@ -414,7 +414,12 @@ fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<
|
||||
(_, &ty::Opaque(..)) => (generalize(a, true)?, b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.delegate.register_opaque_type(a, b, true)?;
|
||||
let cause = ObligationCause::dummy_with_span(self.delegate.span());
|
||||
let obligations = self
|
||||
.infcx
|
||||
.handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
|
||||
.obligations;
|
||||
self.delegate.register_opaque_type_obligations(obligations)?;
|
||||
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
|
||||
Ok(a)
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ pub fn handle_opaque_type(
|
||||
return Ok(InferOk { value: (), obligations: vec![] });
|
||||
}
|
||||
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
|
||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
|
||||
ty::Opaque(def_id, substs) if def_id.is_local() => {
|
||||
let def_id = def_id.expect_local();
|
||||
let origin = match self.defining_use_anchor {
|
||||
@ -169,13 +169,14 @@ pub fn handle_opaque_type(
|
||||
param_env,
|
||||
b,
|
||||
origin,
|
||||
a_is_expected,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(res) = process(a, b) {
|
||||
if let Some(res) = process(a, b, true) {
|
||||
res
|
||||
} else if let Some(res) = process(b, a) {
|
||||
} else if let Some(res) = process(b, a, false) {
|
||||
res
|
||||
} else {
|
||||
let (a, b) = self.resolve_vars_if_possible((a, b));
|
||||
@ -514,13 +515,14 @@ pub fn is_defining(self) -> bool {
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn register_hidden_type(
|
||||
fn register_hidden_type(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
a_is_expected: bool,
|
||||
) -> InferResult<'tcx, ()> {
|
||||
let tcx = self.tcx;
|
||||
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
||||
@ -539,7 +541,8 @@ pub fn register_hidden_type(
|
||||
origin,
|
||||
);
|
||||
if let Some(prev) = prev {
|
||||
obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
|
||||
obligations =
|
||||
self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
|
||||
}
|
||||
|
||||
let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
|
||||
|
@ -2,9 +2,7 @@
|
||||
use super::SubregionOrigin;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::Obligation;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::TyVar;
|
||||
@ -130,39 +128,18 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
|
||||
if self.fields.define_opaque_types && did.is_local() =>
|
||||
{
|
||||
let mut generalize = |ty, ty_is_expected| {
|
||||
let var = infcx.next_ty_var_id_in_universe(
|
||||
TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: self.fields.trace.cause.span,
|
||||
},
|
||||
ty::UniverseIndex::ROOT,
|
||||
);
|
||||
self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
|
||||
Ok(infcx.tcx.mk_ty_var(var))
|
||||
};
|
||||
let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
|
||||
let (ga, gb) = match (a.kind(), b.kind()) {
|
||||
(&ty::Opaque(..), _) => (a, generalize(b, true)?),
|
||||
(_, &ty::Opaque(..)) => (generalize(a, false)?, b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.fields.obligations.extend(
|
||||
infcx
|
||||
.handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env())
|
||||
// Don't leak any generalized type variables out of this
|
||||
// subtyping relation in the case of a type error.
|
||||
.map_err(|err| {
|
||||
let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb));
|
||||
if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb {
|
||||
TypeError::Sorts(ExpectedFound { expected: a, found: b })
|
||||
} else {
|
||||
err
|
||||
}
|
||||
})?
|
||||
.handle_opaque_type(
|
||||
a,
|
||||
b,
|
||||
self.a_is_expected,
|
||||
&self.fields.trace.cause,
|
||||
self.param_env(),
|
||||
)?
|
||||
.obligations,
|
||||
);
|
||||
Ok(ga)
|
||||
Ok(a)
|
||||
}
|
||||
// Optimization of GeneratorWitness relation since we know that all
|
||||
// free regions are replaced with bound regions during construction.
|
||||
|
@ -773,7 +773,15 @@ fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro {
|
||||
}
|
||||
|
||||
fn opt_item_name(self, item_index: DefIndex) -> Option<Symbol> {
|
||||
self.def_key(item_index).disambiguated_data.data.get_opt_name()
|
||||
let def_key = self.def_key(item_index);
|
||||
def_key.disambiguated_data.data.get_opt_name().or_else(|| {
|
||||
if def_key.disambiguated_data.data == DefPathData::Ctor {
|
||||
let parent_index = def_key.parent.expect("no parent for a constructor");
|
||||
self.def_key(parent_index).disambiguated_data.data.get_opt_name()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn item_name(self, item_index: DefIndex) -> Symbol {
|
||||
@ -905,7 +913,13 @@ fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
|
||||
.get(self, item_id)
|
||||
.unwrap_or_else(LazyArray::empty)
|
||||
.decode(self)
|
||||
.map(|index| self.get_variant(&self.def_kind(index), index, did))
|
||||
.filter_map(|index| {
|
||||
let kind = self.def_kind(index);
|
||||
match kind {
|
||||
DefKind::Ctor(..) => None,
|
||||
_ => Some(self.get_variant(&kind, index, did)),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
std::iter::once(self.get_variant(&kind, item_id, did)).collect()
|
||||
@ -1029,50 +1043,27 @@ fn for_each_module_child(
|
||||
|
||||
callback(ModChild { ident, res, vis, span, macro_rules });
|
||||
|
||||
// For non-re-export structs and variants add their constructors to children.
|
||||
// Re-export lists automatically contain constructors when necessary.
|
||||
match kind {
|
||||
DefKind::Struct => {
|
||||
if let Some((ctor_def_id, ctor_kind)) =
|
||||
self.get_ctor_def_id_and_kind(child_index)
|
||||
{
|
||||
let ctor_res =
|
||||
Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
|
||||
let vis = self.get_visibility(ctor_def_id.index);
|
||||
callback(ModChild {
|
||||
ident,
|
||||
res: ctor_res,
|
||||
vis,
|
||||
span,
|
||||
macro_rules: false,
|
||||
});
|
||||
// For non-reexport variants add their fictive constructors to children.
|
||||
// Braced variants, unlike structs, generate unusable names in value namespace,
|
||||
// they are reserved for possible future use. It's ok to use the variant's id as
|
||||
// a ctor id since an error will be reported on any use of such resolution anyway.
|
||||
// Reexport lists automatically contain such constructors when necessary.
|
||||
if kind == DefKind::Variant && self.get_ctor_def_id_and_kind(child_index).is_none()
|
||||
{
|
||||
let ctor_res =
|
||||
Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive), def_id);
|
||||
let mut vis = vis;
|
||||
if vis.is_public() {
|
||||
// For non-exhaustive variants lower the constructor visibility to
|
||||
// within the crate. We only need this for fictive constructors,
|
||||
// for other constructors correct visibilities
|
||||
// were already encoded in metadata.
|
||||
let mut attrs = self.get_item_attrs(def_id.index, sess);
|
||||
if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
|
||||
vis = ty::Visibility::Restricted(self.local_def_id(CRATE_DEF_INDEX));
|
||||
}
|
||||
}
|
||||
DefKind::Variant => {
|
||||
// Braced variants, unlike structs, generate unusable names in
|
||||
// value namespace, they are reserved for possible future use.
|
||||
// It's ok to use the variant's id as a ctor id since an
|
||||
// error will be reported on any use of such resolution anyway.
|
||||
let (ctor_def_id, ctor_kind) = self
|
||||
.get_ctor_def_id_and_kind(child_index)
|
||||
.unwrap_or((def_id, CtorKind::Fictive));
|
||||
let ctor_res =
|
||||
Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
|
||||
let mut vis = self.get_visibility(ctor_def_id.index);
|
||||
if ctor_def_id == def_id && vis.is_public() {
|
||||
// For non-exhaustive variants lower the constructor visibility to
|
||||
// within the crate. We only need this for fictive constructors,
|
||||
// for other constructors correct visibilities
|
||||
// were already encoded in metadata.
|
||||
let mut attrs = self.get_item_attrs(def_id.index, sess);
|
||||
if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
|
||||
let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
|
||||
vis = ty::Visibility::Restricted(crate_def_id);
|
||||
}
|
||||
}
|
||||
callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
|
||||
}
|
||||
_ => {}
|
||||
callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1297,6 +1297,13 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
|
||||
// Only encode named non-reexport children, reexports are encoded
|
||||
// separately and unnamed items are not used by name resolution.
|
||||
hir::ItemKind::ExternCrate(..) => continue,
|
||||
hir::ItemKind::Struct(ref vdata, _) => {
|
||||
yield item_id.def_id.def_id.local_def_index;
|
||||
// Encode constructors which take a separate slot in value namespace.
|
||||
if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
|
||||
yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
|
||||
}
|
||||
}
|
||||
_ if tcx.def_key(item_id.def_id.to_def_id()).get_opt_name().is_some() => {
|
||||
yield item_id.def_id.def_id.local_def_index;
|
||||
}
|
||||
@ -1620,12 +1627,17 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
|
||||
};
|
||||
// FIXME(eddyb) there should be a nicer way to do this.
|
||||
match item.kind {
|
||||
hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
|
||||
self.tcx.adt_def(def_id).variants().iter().map(|v| {
|
||||
assert!(v.def_id.is_local());
|
||||
v.def_id.index
|
||||
})
|
||||
),
|
||||
hir::ItemKind::Enum(..) => {
|
||||
record_array!(self.tables.children[def_id] <- iter::from_generator(||
|
||||
for variant in tcx.adt_def(def_id).variants() {
|
||||
yield variant.def_id.index;
|
||||
// Encode constructors which take a separate slot in value namespace.
|
||||
if let Some(ctor_def_id) = variant.ctor_def_id {
|
||||
yield ctor_def_id.index;
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
|
||||
record_array!(self.tables.children[def_id] <-
|
||||
self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
|
||||
|
@ -2112,6 +2112,8 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
|
||||
// HACK: This is needed so we can detect whether we're inside a macro,
|
||||
// where regular assumptions about what tokens can follow other tokens
|
||||
// don't necessarily apply.
|
||||
&& self.may_recover()
|
||||
// FIXME(Nilstrieb): Remove this check once `may_recover` actually stops recovery
|
||||
&& self.subparser_name.is_none()
|
||||
{
|
||||
// It is likely that the closure body is a block but where the
|
||||
|
@ -115,6 +115,12 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Recovery {
|
||||
Allowed,
|
||||
Forbidden,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Parser<'a> {
|
||||
pub sess: &'a ParseSess,
|
||||
@ -152,12 +158,15 @@ pub struct Parser<'a> {
|
||||
/// This allows us to recover when the user forget to add braces around
|
||||
/// multiple statements in the closure body.
|
||||
pub current_closure: Option<ClosureSpans>,
|
||||
/// Whether the parser is allowed to do recovery.
|
||||
/// This is disabled when parsing macro arguments, see #103534
|
||||
pub recovery: Recovery,
|
||||
}
|
||||
|
||||
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
|
||||
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
|
||||
// it doesn't unintentionally get bigger.
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
rustc_data_structures::static_assert_size!(Parser<'_>, 328);
|
||||
rustc_data_structures::static_assert_size!(Parser<'_>, 336);
|
||||
|
||||
/// Stores span information about a closure.
|
||||
#[derive(Clone)]
|
||||
@ -483,6 +492,7 @@ pub fn new(
|
||||
inner_attr_ranges: Default::default(),
|
||||
},
|
||||
current_closure: None,
|
||||
recovery: Recovery::Allowed,
|
||||
};
|
||||
|
||||
// Make parser point to the first token.
|
||||
@ -491,6 +501,22 @@ pub fn new(
|
||||
parser
|
||||
}
|
||||
|
||||
pub fn forbid_recovery(mut self) -> Self {
|
||||
self.recovery = Recovery::Forbidden;
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether the parser is allowed to recover from broken code.
|
||||
///
|
||||
/// If this returns false, recovering broken code into valid code (especially if this recovery does lookahead)
|
||||
/// is not allowed. All recovery done by the parser must be gated behind this check.
|
||||
///
|
||||
/// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens.
|
||||
/// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold.
|
||||
fn may_recover(&self) -> bool {
|
||||
matches!(self.recovery, Recovery::Allowed)
|
||||
}
|
||||
|
||||
pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
|
||||
match self.expect_one_of(&[], &[]) {
|
||||
Err(e) => Err(e),
|
||||
|
@ -1816,6 +1816,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
///
|
||||
/// [`.get_mut()`]: `UnsafeCell::get_mut`
|
||||
///
|
||||
/// # Memory layout
|
||||
///
|
||||
/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T`. A consequence
|
||||
/// of this guarantee is that it is possible to convert between `T` and `UnsafeCell<T>`.
|
||||
/// Special care has to be taken when converting a nested `T` inside of an `Outer<T>` type
|
||||
@ -1825,35 +1827,44 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
|
||||
/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
|
||||
/// order to avoid its interior mutability property from spreading from `T` into the `Outer` type,
|
||||
/// thus this can cause distortions in the type size in these cases. Furthermore, it is only valid
|
||||
/// to obtain a `*mut T` pointer to the contents of a _shared_ `UnsafeCell<T>` through [`.get()`]
|
||||
/// or [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer or
|
||||
/// by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell<T>`, e.g.:
|
||||
/// thus this can cause distortions in the type size in these cases.
|
||||
///
|
||||
/// Note that the only valid way to obtain a `*mut T` pointer to the contents of a
|
||||
/// _shared_ `UnsafeCell<T>` is through [`.get()`] or [`.raw_get()`]. A `&mut T` reference
|
||||
/// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`]
|
||||
/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
|
||||
/// same memory layout, the following is not allowed and undefined behavior:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use std::cell::UnsafeCell;
|
||||
/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
|
||||
/// let t = ptr as *const UnsafeCell<T> as *mut T;
|
||||
/// // This is undefined behavior, because the `*mut T` pointer
|
||||
/// // was not obtained through `.get()` nor `.raw_get()`:
|
||||
/// unsafe { &mut *t }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Instead, do this:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::cell::UnsafeCell;
|
||||
/// # use std::cell::UnsafeCell;
|
||||
/// // Safety: the caller must ensure that there are no references that
|
||||
/// // point to the *contents* of the `UnsafeCell`.
|
||||
/// unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
|
||||
/// unsafe { &mut *ptr.get() }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
|
||||
/// let shared: &UnsafeCell<u32> = &x;
|
||||
/// // using `.get()` is okay:
|
||||
/// unsafe {
|
||||
/// // SAFETY: there exist no other references to the contents of `x`
|
||||
/// let exclusive: &mut u32 = &mut *shared.get();
|
||||
/// };
|
||||
/// // using `.raw_get()` is also okay:
|
||||
/// unsafe {
|
||||
/// // SAFETY: there exist no other references to the contents of `x` in this scope
|
||||
/// let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _);
|
||||
/// };
|
||||
/// // using `.get_mut()` is always safe:
|
||||
/// let exclusive: &mut u32 = x.get_mut();
|
||||
/// Coverting in the other direction from a `&mut T`
|
||||
/// to an `&UnsafeCell<T>` is allowed:
|
||||
///
|
||||
/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`:
|
||||
/// unsafe {
|
||||
/// // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell<u32>`
|
||||
/// let shared: &UnsafeCell<u32> = &*(exclusive as *mut _ as *const UnsafeCell<u32>);
|
||||
/// // SAFETY: there exist no other *active* references to the contents of `x` in this scope
|
||||
/// let exclusive: &mut u32 = &mut *shared.get();
|
||||
/// ```rust
|
||||
/// # use std::cell::UnsafeCell;
|
||||
/// fn get_shared<T>(ptr: &mut T) -> &UnsafeCell<T> {
|
||||
/// let t = ptr as *mut T as *const UnsafeCell<T>;
|
||||
/// // SAFETY: `T` and `UnsafeCell<T>` have the same memory layout
|
||||
/// unsafe { &*t }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
@ -44,6 +44,12 @@ impl<T: ?Sized> !Send for *const T {}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> !Send for *mut T {}
|
||||
|
||||
// Most instances arise automatically, but this instance is needed to link up `T: Sync` with
|
||||
// `&T: Send` (and it also removes the unsound default instance `T Send` -> `&T: Send` that would
|
||||
// otherwise exist).
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<T: Sync + ?Sized> Send for &T {}
|
||||
|
||||
/// Types with a constant size known at compile time.
|
||||
///
|
||||
/// All type parameters have an implicit bound of `Sized`. The special syntax
|
||||
@ -674,13 +680,6 @@ impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
|
||||
#[unstable(feature = "structural_match", issue = "31434")]
|
||||
impl<T: ?Sized> StructuralEq for PhantomData<T> {}
|
||||
|
||||
mod impls {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<T: Sync + ?Sized> Send for &T {}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<T: Send + ?Sized> Send for &mut T {}
|
||||
}
|
||||
|
||||
/// Compiler-internal trait used to indicate the type of enum discriminants.
|
||||
///
|
||||
/// This trait is automatically implemented for every type and does not add any
|
||||
|
@ -415,6 +415,16 @@ fn clean_projection<'tcx>(
|
||||
cx: &mut DocContext<'tcx>,
|
||||
def_id: Option<DefId>,
|
||||
) -> Type {
|
||||
if cx.tcx.def_kind(ty.item_def_id) == DefKind::ImplTraitPlaceholder {
|
||||
let bounds = cx
|
||||
.tcx
|
||||
.explicit_item_bounds(ty.item_def_id)
|
||||
.iter()
|
||||
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.substs))
|
||||
.collect::<Vec<_>>();
|
||||
return clean_middle_opaque_bounds(cx, bounds);
|
||||
}
|
||||
|
||||
let trait_ = clean_trait_ref_with_bindings(cx, ty.trait_ref(cx.tcx), ThinVec::new());
|
||||
let self_type = clean_middle_ty(ty.self_ty(), cx, None);
|
||||
let self_def_id = if let Some(def_id) = def_id {
|
||||
@ -1720,59 +1730,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
||||
.iter()
|
||||
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
|
||||
.collect::<Vec<_>>();
|
||||
let mut regions = vec![];
|
||||
let mut has_sized = false;
|
||||
let mut bounds = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| {
|
||||
let bound_predicate = bound.kind();
|
||||
let trait_ref = match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
|
||||
if let Some(r) = clean_middle_region(reg) {
|
||||
regions.push(GenericBound::Outlives(r));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if let Some(sized) = cx.tcx.lang_items().sized_trait() {
|
||||
if trait_ref.def_id() == sized {
|
||||
has_sized = true;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let bindings: ThinVec<_> = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| {
|
||||
if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
|
||||
{
|
||||
if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
|
||||
Some(TypeBinding {
|
||||
assoc: projection_to_path_segment(proj.projection_ty, cx),
|
||||
kind: TypeBindingKind::Equality {
|
||||
term: clean_middle_term(proj.term, cx),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
bounds.extend(regions);
|
||||
if !has_sized && !bounds.is_empty() {
|
||||
bounds.insert(0, GenericBound::maybe_sized(cx));
|
||||
}
|
||||
ImplTrait(bounds)
|
||||
clean_middle_opaque_bounds(cx, bounds)
|
||||
}
|
||||
|
||||
ty::Closure(..) => panic!("Closure"),
|
||||
@ -1785,6 +1743,64 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_middle_opaque_bounds<'tcx>(
|
||||
cx: &mut DocContext<'tcx>,
|
||||
bounds: Vec<ty::Predicate<'tcx>>,
|
||||
) -> Type {
|
||||
let mut regions = vec![];
|
||||
let mut has_sized = false;
|
||||
let mut bounds = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| {
|
||||
let bound_predicate = bound.kind();
|
||||
let trait_ref = match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
|
||||
if let Some(r) = clean_middle_region(reg) {
|
||||
regions.push(GenericBound::Outlives(r));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if let Some(sized) = cx.tcx.lang_items().sized_trait() {
|
||||
if trait_ref.def_id() == sized {
|
||||
has_sized = true;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let bindings: ThinVec<_> = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| {
|
||||
if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder() {
|
||||
if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
|
||||
Some(TypeBinding {
|
||||
assoc: projection_to_path_segment(proj.projection_ty, cx),
|
||||
kind: TypeBindingKind::Equality {
|
||||
term: clean_middle_term(proj.term, cx),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
bounds.extend(regions);
|
||||
if !has_sized && !bounds.is_empty() {
|
||||
bounds.insert(0, GenericBound::maybe_sized(cx));
|
||||
}
|
||||
ImplTrait(bounds)
|
||||
}
|
||||
|
||||
pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
|
||||
let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id();
|
||||
clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx)
|
||||
|
@ -857,9 +857,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||
causes rounded corners and no border on iOS Safari. */
|
||||
-webkit-appearance: none;
|
||||
/* Override Normalize.css: we have margins and do
|
||||
not want to overflow - the `moz` attribute is necessary
|
||||
until Firefox 29, too early to drop at this point */
|
||||
-moz-box-sizing: border-box !important;
|
||||
not want to overflow */
|
||||
box-sizing: border-box !important;
|
||||
outline: none;
|
||||
border: 1px solid var(--border-color);
|
||||
|
@ -184,7 +184,60 @@ fn extract_html_tag(
|
||||
}
|
||||
drop_tag(tags, tag_name, r, f);
|
||||
} else {
|
||||
tags.push((tag_name, r));
|
||||
let mut is_self_closing = false;
|
||||
let mut quote_pos = None;
|
||||
if c != '>' {
|
||||
let mut quote = None;
|
||||
let mut after_eq = false;
|
||||
for (i, c) in text[pos..].char_indices() {
|
||||
if !c.is_whitespace() {
|
||||
if let Some(q) = quote {
|
||||
if c == q {
|
||||
quote = None;
|
||||
quote_pos = None;
|
||||
after_eq = false;
|
||||
}
|
||||
} else if c == '>' {
|
||||
break;
|
||||
} else if c == '/' && !after_eq {
|
||||
is_self_closing = true;
|
||||
} else {
|
||||
if is_self_closing {
|
||||
is_self_closing = false;
|
||||
}
|
||||
if (c == '"' || c == '\'') && after_eq {
|
||||
quote = Some(c);
|
||||
quote_pos = Some(pos + i);
|
||||
} else if c == '=' {
|
||||
after_eq = true;
|
||||
}
|
||||
}
|
||||
} else if quote.is_none() {
|
||||
after_eq = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(quote_pos) = quote_pos {
|
||||
let qr = Range { start: quote_pos, end: quote_pos };
|
||||
f(
|
||||
&format!("unclosed quoted HTML attribute on tag `{}`", tag_name),
|
||||
&qr,
|
||||
false,
|
||||
);
|
||||
}
|
||||
if is_self_closing {
|
||||
// https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus
|
||||
let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..])
|
||||
|| tags.iter().take(pos + 1).any(|(at, _)| {
|
||||
let at = at.to_lowercase();
|
||||
at == "svg" || at == "math"
|
||||
});
|
||||
if !valid {
|
||||
f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false);
|
||||
}
|
||||
} else {
|
||||
tags.push((tag_name, r));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
70
src/test/rustdoc-ui/invalid-html-self-closing-tag.rs
Normal file
70
src/test/rustdoc-ui/invalid-html-self-closing-tag.rs
Normal file
@ -0,0 +1,70 @@
|
||||
#![deny(rustdoc::invalid_html_tags)]
|
||||
|
||||
/// <p/>
|
||||
//~^ ERROR invalid self-closing HTML tag `p`
|
||||
pub struct A;
|
||||
|
||||
/// <p style/>
|
||||
//~^ ERROR invalid self-closing HTML tag `p`
|
||||
pub struct B;
|
||||
|
||||
/// <p style=""/>
|
||||
//~^ ERROR invalid self-closing HTML tag `p`
|
||||
pub struct C;
|
||||
|
||||
/// <p style="x"/>
|
||||
//~^ ERROR invalid self-closing HTML tag `p`
|
||||
pub struct D;
|
||||
|
||||
/// <p style="x/></p>
|
||||
//~^ ERROR unclosed quoted HTML attribute
|
||||
pub struct E;
|
||||
|
||||
/// <p style='x/></p>
|
||||
//~^ ERROR unclosed quoted HTML attribute
|
||||
pub struct F;
|
||||
|
||||
/// <p style="x/"></p>
|
||||
pub struct G;
|
||||
|
||||
/// <p style="x/"/>
|
||||
//~^ ERROR invalid self-closing HTML tag `p`
|
||||
pub struct H;
|
||||
|
||||
/// <p / >
|
||||
//~^ ERROR invalid self-closing HTML tag `p`
|
||||
pub struct I;
|
||||
|
||||
/// <br/>
|
||||
pub struct J;
|
||||
|
||||
/// <a href=/></a>
|
||||
pub struct K;
|
||||
|
||||
/// <a href=//></a>
|
||||
pub struct L;
|
||||
|
||||
/// <a href="/"/>
|
||||
//~^ ERROR invalid self-closing HTML tag `a`
|
||||
pub struct M;
|
||||
|
||||
/// <a href=x />
|
||||
//~^ ERROR invalid self-closing HTML tag `a`
|
||||
pub struct N;
|
||||
|
||||
/// <a href= />
|
||||
//~^ ERROR invalid self-closing HTML tag `a`
|
||||
pub struct O;
|
||||
|
||||
/// <a href=x/></a>
|
||||
pub struct P;
|
||||
|
||||
/// <svg><rect width=1 height=1 /></svg>
|
||||
pub struct Q;
|
||||
|
||||
/// <svg><rect width=1 height=/></svg>
|
||||
//~^ ERROR unclosed HTML tag `rect`
|
||||
pub struct R;
|
||||
|
||||
/// <svg / q>
|
||||
pub struct S;
|
80
src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr
Normal file
80
src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr
Normal file
@ -0,0 +1,80 @@
|
||||
error: invalid self-closing HTML tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:3:5
|
||||
|
|
||||
LL | /// <p/>
|
||||
| ^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:1:9
|
||||
|
|
||||
LL | #![deny(rustdoc::invalid_html_tags)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid self-closing HTML tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:7:5
|
||||
|
|
||||
LL | /// <p style/>
|
||||
| ^^
|
||||
|
||||
error: invalid self-closing HTML tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:11:5
|
||||
|
|
||||
LL | /// <p style=""/>
|
||||
| ^^
|
||||
|
||||
error: invalid self-closing HTML tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:15:5
|
||||
|
|
||||
LL | /// <p style="x"/>
|
||||
| ^^
|
||||
|
||||
error: unclosed quoted HTML attribute on tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:19:14
|
||||
|
|
||||
LL | /// <p style="x/></p>
|
||||
| ^
|
||||
|
||||
error: unclosed quoted HTML attribute on tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:23:14
|
||||
|
|
||||
LL | /// <p style='x/></p>
|
||||
| ^
|
||||
|
||||
error: invalid self-closing HTML tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:30:5
|
||||
|
|
||||
LL | /// <p style="x/"/>
|
||||
| ^^
|
||||
|
||||
error: invalid self-closing HTML tag `p`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:34:5
|
||||
|
|
||||
LL | /// <p / >
|
||||
| ^^
|
||||
|
||||
error: invalid self-closing HTML tag `a`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:47:5
|
||||
|
|
||||
LL | /// <a href="/"/>
|
||||
| ^^
|
||||
|
||||
error: invalid self-closing HTML tag `a`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:51:5
|
||||
|
|
||||
LL | /// <a href=x />
|
||||
| ^^
|
||||
|
||||
error: invalid self-closing HTML tag `a`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:55:5
|
||||
|
|
||||
LL | /// <a href= />
|
||||
| ^^
|
||||
|
||||
error: unclosed HTML tag `rect`
|
||||
--> $DIR/invalid-html-self-closing-tag.rs:65:10
|
||||
|
|
||||
LL | /// <svg><rect width=1 height=/></svg>
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
16
src/test/rustdoc/async-trait.rs
Normal file
16
src/test/rustdoc/async-trait.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// aux-build:async-trait-dep.rs
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
extern crate async_trait_dep;
|
||||
|
||||
pub struct Oink {}
|
||||
|
||||
// @has 'async_trait/struct.Oink.html' '//h4[@class="code-header"]' "async fn woof()"
|
||||
impl async_trait_dep::Meow for Oink {
|
||||
async fn woof() {
|
||||
todo!()
|
||||
}
|
||||
}
|
9
src/test/rustdoc/auxiliary/async-trait-dep.rs
Normal file
9
src/test/rustdoc/auxiliary/async-trait-dep.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub trait Meow {
|
||||
/// Who's a good dog?
|
||||
async fn woof();
|
||||
}
|
@ -27,7 +27,7 @@ error: future cannot be sent between threads safely
|
||||
LL | assert_send(non_sync_with_method_call());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
||||
|
|
||||
= help: the trait `Send` is not implemented for `dyn std::fmt::Write`
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/async-fn-nonsend.rs:46:14
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user