Merge from rustc
This commit is contained in:
commit
b8ee38d3e8
322 changed files with 5569 additions and 3047 deletions
|
|
@ -954,8 +954,14 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
|
|||
|
||||
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||
match kind {
|
||||
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
|
||||
FnKind::Fn(
|
||||
_ctxt,
|
||||
_ident,
|
||||
_vis,
|
||||
Fn { defaultness, generics, body, sig: FnSig { header, decl, span } },
|
||||
) => {
|
||||
// Identifier and visibility are visited as a part of the item.
|
||||
visit_defaultness(vis, defaultness);
|
||||
vis.visit_fn_header(header);
|
||||
vis.visit_generics(generics);
|
||||
vis.visit_fn_decl(decl);
|
||||
|
|
@ -1205,13 +1211,8 @@ impl WalkItemKind for ItemKind {
|
|||
ItemKind::Const(item) => {
|
||||
visit_const_item(item, vis);
|
||||
}
|
||||
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(vis, defaultness);
|
||||
vis.visit_fn(
|
||||
FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
|
||||
span,
|
||||
id,
|
||||
);
|
||||
ItemKind::Fn(func) => {
|
||||
vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id);
|
||||
}
|
||||
ItemKind::Mod(safety, mod_kind) => {
|
||||
visit_safety(vis, safety);
|
||||
|
|
@ -1329,10 +1330,9 @@ impl WalkItemKind for AssocItemKind {
|
|||
AssocItemKind::Const(item) => {
|
||||
visit_const_item(item, visitor);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(visitor, defaultness);
|
||||
AssocItemKind::Fn(func) => {
|
||||
visitor.visit_fn(
|
||||
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
|
||||
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, visibility, &mut *func),
|
||||
span,
|
||||
id,
|
||||
);
|
||||
|
|
@ -1476,10 +1476,9 @@ impl WalkItemKind for ForeignItemKind {
|
|||
visitor.visit_ty(ty);
|
||||
visit_opt(expr, |expr| visitor.visit_expr(expr));
|
||||
}
|
||||
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(visitor, defaultness);
|
||||
ForeignItemKind::Fn(func) => {
|
||||
visitor.visit_fn(
|
||||
FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
|
||||
FnKind::Fn(FnCtxt::Foreign, ident, visibility, &mut *func),
|
||||
span,
|
||||
id,
|
||||
);
|
||||
|
|
@ -1965,14 +1964,7 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
|
|||
#[derive(Debug)]
|
||||
pub enum FnKind<'a> {
|
||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||
Fn(
|
||||
FnCtxt,
|
||||
&'a mut Ident,
|
||||
&'a mut FnSig,
|
||||
&'a mut Visibility,
|
||||
&'a mut Generics,
|
||||
&'a mut Option<P<Block>>,
|
||||
),
|
||||
Fn(FnCtxt, &'a mut Ident, &'a mut Visibility, &'a mut Fn),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl BoundKind {
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum FnKind<'a> {
|
||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||
Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
|
||||
Fn(FnCtxt, &'a Ident, &'a Visibility, &'a Fn),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
||||
|
|
@ -74,7 +74,7 @@ pub enum FnKind<'a> {
|
|||
impl<'a> FnKind<'a> {
|
||||
pub fn header(&self) -> Option<&'a FnHeader> {
|
||||
match *self {
|
||||
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
|
||||
FnKind::Fn(_, _, _, Fn { sig, .. }) => Some(&sig.header),
|
||||
FnKind::Closure(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ impl<'a> FnKind<'a> {
|
|||
|
||||
pub fn decl(&self) -> &'a FnDecl {
|
||||
match self {
|
||||
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
|
||||
FnKind::Fn(_, _, _, Fn { sig, .. }) => &sig.decl,
|
||||
FnKind::Closure(_, _, decl, _) => decl,
|
||||
}
|
||||
}
|
||||
|
|
@ -374,8 +374,8 @@ impl WalkItemKind for ItemKind {
|
|||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
|
||||
ItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func);
|
||||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||
|
|
@ -715,8 +715,8 @@ impl WalkItemKind for ForeignItemKind {
|
|||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
|
||||
ForeignItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func);
|
||||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
|
|
@ -858,7 +858,12 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(
|
|||
|
||||
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result {
|
||||
match kind {
|
||||
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => {
|
||||
FnKind::Fn(
|
||||
_ctxt,
|
||||
_ident,
|
||||
_vis,
|
||||
Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, body },
|
||||
) => {
|
||||
// Identifier and visibility are visited as a part of the item.
|
||||
try_visit!(visitor.visit_fn_header(header));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
|
|
@ -892,8 +897,8 @@ impl WalkItemKind for AssocItemKind {
|
|||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
|
||||
AssocItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func);
|
||||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
AssocItemKind::Type(box TyAlias {
|
||||
|
|
|
|||
|
|
@ -1391,7 +1391,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
None,
|
||||
);
|
||||
// Destructure like a unit struct.
|
||||
let unit_struct_pat = hir::PatKind::Path(qpath);
|
||||
let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
|
||||
kind: hir::PatExprKind::Path(qpath),
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(lhs.span),
|
||||
}));
|
||||
return self.pat_without_dbm(lhs.span, unit_struct_pat);
|
||||
}
|
||||
}
|
||||
|
|
@ -2125,7 +2129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc(self.expr_call_mut(span, e, args))
|
||||
}
|
||||
|
||||
fn expr_call_lang_item_fn_mut(
|
||||
pub(super) fn expr_call_lang_item_fn_mut(
|
||||
&mut self,
|
||||
span: Span,
|
||||
lang_item: hir::LangItem,
|
||||
|
|
@ -2135,7 +2139,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr_call_mut(span, path, args)
|
||||
}
|
||||
|
||||
fn expr_call_lang_item_fn(
|
||||
pub(super) fn expr_call_lang_item_fn(
|
||||
&mut self,
|
||||
span: Span,
|
||||
lang_item: hir::LangItem,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
break hir::PatKind::Path(qpath);
|
||||
let kind = hir::PatExprKind::Path(qpath);
|
||||
let span = self.lower_span(pattern.span);
|
||||
let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind };
|
||||
let expr = self.arena.alloc(expr);
|
||||
return hir::Pat {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::PatKind::Expr(expr),
|
||||
span,
|
||||
default_binding_modes: true,
|
||||
};
|
||||
}
|
||||
PatKind::Struct(qself, path, fields, etc) => {
|
||||
let qpath = self.lower_qpath(
|
||||
|
|
@ -304,16 +313,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}
|
||||
Some(res) => {
|
||||
let hir_id = self.next_id();
|
||||
let res = self.lower_res(res);
|
||||
hir::PatKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span: self.lower_span(ident.span),
|
||||
res,
|
||||
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
|
||||
}),
|
||||
))
|
||||
let span = self.lower_span(ident.span);
|
||||
hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
|
||||
kind: hir::PatExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span,
|
||||
res,
|
||||
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)],
|
||||
}),
|
||||
)),
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -917,7 +917,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return; // Avoid visiting again.
|
||||
}
|
||||
ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
|
||||
ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, body }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
||||
let is_intrinsic =
|
||||
|
|
@ -947,7 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(&item.ident);
|
||||
let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
|
||||
let kind = FnKind::Fn(FnCtxt::Free, &item.ident, &item.vis, &*func);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return; // Avoid visiting again.
|
||||
|
|
@ -1348,19 +1348,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
if let FnKind::Fn(
|
||||
_,
|
||||
_,
|
||||
FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
Fn {
|
||||
sig: FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },
|
||||
..
|
||||
},
|
||||
) = fk
|
||||
{
|
||||
self.maybe_lint_missing_abi(*extern_span, id);
|
||||
}
|
||||
|
||||
// Functions without bodies cannot have patterns.
|
||||
if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
|
||||
if let FnKind::Fn(ctxt, _, _, Fn { body: None, sig, .. }) = fk {
|
||||
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
|
||||
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
|
||||
if let Some(ident) = ident {
|
||||
|
|
@ -1394,7 +1395,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
.is_some();
|
||||
|
||||
let disallowed = (!tilde_const_allowed).then(|| match fk {
|
||||
FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
|
||||
FnKind::Fn(_, ident, _, _) => TildeConstReason::Function { ident: ident.span },
|
||||
FnKind::Closure(..) => TildeConstReason::Closure,
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
||||
|
|
@ -1470,15 +1471,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
|
||||
|
||||
match &item.kind {
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
|
||||
AssocItemKind::Fn(func)
|
||||
if parent_is_const
|
||||
|| ctxt == AssocCtxt::Trait
|
||||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
|| matches!(func.sig.header.constness, Const::Yes(_)) =>
|
||||
{
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(&item.ident);
|
||||
let kind =
|
||||
FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, &item.vis, &*func);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ impl<'a> State<'a> {
|
|||
self.maybe_print_comment(span.lo());
|
||||
self.print_outer_attributes(attrs);
|
||||
match kind {
|
||||
ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
ast::ForeignItemKind::Fn(func) => {
|
||||
self.print_fn_full(ident, vis, attrs, &*func);
|
||||
}
|
||||
ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -199,16 +199,8 @@ impl<'a> State<'a> {
|
|||
*defaultness,
|
||||
);
|
||||
}
|
||||
ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(
|
||||
sig,
|
||||
item.ident,
|
||||
generics,
|
||||
&item.vis,
|
||||
*defaultness,
|
||||
body.as_deref(),
|
||||
&item.attrs,
|
||||
);
|
||||
ast::ItemKind::Fn(func) => {
|
||||
self.print_fn_full(item.ident, &item.vis, &item.attrs, &*func);
|
||||
}
|
||||
ast::ItemKind::Mod(safety, mod_kind) => {
|
||||
self.head(Self::to_string(|s| {
|
||||
|
|
@ -542,8 +534,8 @@ impl<'a> State<'a> {
|
|||
self.maybe_print_comment(span.lo());
|
||||
self.print_outer_attributes(attrs);
|
||||
match kind {
|
||||
ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
ast::AssocItemKind::Fn(func) => {
|
||||
self.print_fn_full(ident, vis, attrs, &*func);
|
||||
}
|
||||
ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -653,19 +645,17 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_fn_full(
|
||||
&mut self,
|
||||
sig: &ast::FnSig,
|
||||
name: Ident,
|
||||
generics: &ast::Generics,
|
||||
vis: &ast::Visibility,
|
||||
defaultness: ast::Defaultness,
|
||||
body: Option<&ast::Block>,
|
||||
attrs: &[ast::Attribute],
|
||||
func: &ast::Fn,
|
||||
) {
|
||||
let ast::Fn { defaultness, generics, sig, body } = func;
|
||||
if body.is_some() {
|
||||
self.head("");
|
||||
}
|
||||
self.print_visibility(vis);
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_defaultness(*defaultness);
|
||||
self.print_fn(&sig.decl, sig.header, Some(name), generics);
|
||||
if let Some(body) = body {
|
||||
self.nbsp();
|
||||
|
|
|
|||
|
|
@ -1140,10 +1140,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
let amp_mut_sugg = match *local_decl.local_info() {
|
||||
LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
|
||||
let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
|
||||
let additional =
|
||||
local_trait.map(|span| (span, suggest_ampmut_self(self.infcx.tcx, span)));
|
||||
Some(AmpMutSugg { has_sugg: true, span: decl_span, suggestion, additional })
|
||||
let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
|
||||
let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
|
||||
Some(AmpMutSugg { has_sugg: true, span, suggestion, additional })
|
||||
}
|
||||
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
|
|
@ -1202,10 +1201,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
opt_ty_info: None,
|
||||
..
|
||||
})) => {
|
||||
let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span);
|
||||
let (span, sugg) =
|
||||
suggest_ampmut_self(self.infcx.tcx, decl_span);
|
||||
Some(AmpMutSugg {
|
||||
has_sugg: true,
|
||||
span: decl_span,
|
||||
span,
|
||||
suggestion: sugg,
|
||||
additional: None,
|
||||
})
|
||||
|
|
@ -1461,17 +1461,12 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
|
||||
fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
|
||||
match tcx.sess.source_map().span_to_snippet(span) {
|
||||
Ok(snippet) => {
|
||||
let lt_pos = snippet.find('\'');
|
||||
if let Some(lt_pos) = lt_pos {
|
||||
format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
|
||||
} else {
|
||||
"&mut self".to_string()
|
||||
}
|
||||
Ok(snippet) if snippet.ends_with("self") => {
|
||||
(span.with_hi(span.hi() - BytePos(4)).shrink_to_hi(), "mut ".to_string())
|
||||
}
|
||||
_ => "&mut self".to_string(),
|
||||
_ => (span, "&mut self".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
use std::io;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::pretty::{
|
||||
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
|
||||
};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowckInferCtxt, RegionInferenceContext};
|
||||
|
||||
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
|
||||
|
|
@ -50,6 +56,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
/// - the NLL MIR
|
||||
/// - the list of polonius localized constraints
|
||||
/// - a mermaid graph of the CFG
|
||||
/// - a mermaid graph of the NLL regions and the constraints between them
|
||||
/// - a mermaid graph of the NLL SCCs and the constraints between them
|
||||
fn emit_polonius_dump<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
|
|
@ -68,25 +76,54 @@ fn emit_polonius_dump<'tcx>(
|
|||
// Section 1: the NLL + Polonius MIR.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Raw MIR dump")?;
|
||||
writeln!(out, "<code><pre>")?;
|
||||
writeln!(out, "<pre><code>")?;
|
||||
emit_html_mir(
|
||||
tcx,
|
||||
body,
|
||||
regioncx,
|
||||
borrow_set,
|
||||
localized_outlives_constraints,
|
||||
&localized_outlives_constraints,
|
||||
closure_region_requirements,
|
||||
out,
|
||||
)?;
|
||||
writeln!(out, "</pre></code>")?;
|
||||
writeln!(out, "</code></pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 2: mermaid visualization of the CFG.
|
||||
// Section 2: mermaid visualization of the polonius constraint graph.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Polonius constraint graph")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
let edge_count = emit_mermaid_constraint_graph(
|
||||
borrow_set,
|
||||
regioncx.liveness_constraints(),
|
||||
&localized_outlives_constraints,
|
||||
out,
|
||||
)?;
|
||||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 3: mermaid visualization of the CFG.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Control-flow graph")?;
|
||||
writeln!(out, "<code><pre class='mermaid'>")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
emit_mermaid_cfg(body, out)?;
|
||||
writeln!(out, "</pre></code>")?;
|
||||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 4: mermaid visualization of the NLL region graph.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "NLL regions")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
emit_mermaid_nll_regions(regioncx, out)?;
|
||||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 5: mermaid visualization of the NLL SCC graph.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "NLL SCCs")?;
|
||||
writeln!(out, "<pre class='mermaid'>")?;
|
||||
emit_mermaid_nll_sccs(regioncx, out)?;
|
||||
writeln!(out, "</pre>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Finalize the dump with the HTML epilogue.
|
||||
|
|
@ -95,7 +132,11 @@ fn emit_polonius_dump<'tcx>(
|
|||
"<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
|
||||
)?;
|
||||
writeln!(out, "<script>")?;
|
||||
writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?;
|
||||
writeln!(
|
||||
out,
|
||||
"mermaid.initialize({{ startOnLoad: false, maxEdges: {} }});",
|
||||
edge_count.max(100),
|
||||
)?;
|
||||
writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?;
|
||||
writeln!(out, "</script>")?;
|
||||
writeln!(out, "</body>")?;
|
||||
|
|
@ -110,7 +151,7 @@ fn emit_html_mir<'tcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
|
|
@ -138,7 +179,7 @@ fn emit_html_mir<'tcx>(
|
|||
regioncx,
|
||||
closure_region_requirements,
|
||||
borrow_set,
|
||||
&localized_outlives_constraints,
|
||||
localized_outlives_constraints,
|
||||
pass_where,
|
||||
out,
|
||||
)
|
||||
|
|
@ -261,3 +302,185 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()>
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a region's label: index, universe, external name.
|
||||
fn render_region(
|
||||
region: RegionVid,
|
||||
regioncx: &RegionInferenceContext<'_>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
let def = regioncx.region_definition(region);
|
||||
let universe = def.universe;
|
||||
|
||||
write!(out, "'{}", region.as_usize())?;
|
||||
if !universe.is_root() {
|
||||
write!(out, "/{universe:?}")?;
|
||||
}
|
||||
if let Some(name) = def.external_name.and_then(|e| e.get_name()) {
|
||||
write!(out, " ({name})")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar
|
||||
/// to the graphviz version.
|
||||
fn emit_mermaid_nll_regions<'tcx>(
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
// The mermaid chart type: a top-down flowchart.
|
||||
writeln!(out, "flowchart TD")?;
|
||||
|
||||
// Emit the region nodes.
|
||||
for region in regioncx.var_infos.indices() {
|
||||
write!(out, "{}[\"", region.as_usize())?;
|
||||
render_region(region, regioncx, out)?;
|
||||
writeln!(out, "\"]")?;
|
||||
}
|
||||
|
||||
// Get a set of edges to check for the reverse edge being present.
|
||||
let edges: FxHashSet<_> = regioncx.outlives_constraints().map(|c| (c.sup, c.sub)).collect();
|
||||
|
||||
// Order (and deduplicate) edges for traversal, to display them in a generally increasing order.
|
||||
let constraint_key = |c: &OutlivesConstraint<'_>| {
|
||||
let min = c.sup.min(c.sub);
|
||||
let max = c.sup.max(c.sub);
|
||||
(min, max)
|
||||
};
|
||||
let mut ordered_edges: Vec<_> = regioncx.outlives_constraints().collect();
|
||||
ordered_edges.sort_by_key(|c| constraint_key(c));
|
||||
ordered_edges.dedup_by_key(|c| constraint_key(c));
|
||||
|
||||
for outlives in ordered_edges {
|
||||
// Source node.
|
||||
write!(out, "{} ", outlives.sup.as_usize())?;
|
||||
|
||||
// The kind of arrow: bidirectional if the opposite edge exists in the set.
|
||||
if edges.contains(&(outlives.sub, outlives.sup)) {
|
||||
write!(out, "<")?;
|
||||
}
|
||||
write!(out, "-- ")?;
|
||||
|
||||
// Edge label from its `Locations`.
|
||||
match outlives.locations {
|
||||
Locations::All(_) => write!(out, "All")?,
|
||||
Locations::Single(location) => write!(out, "{:?}", location)?,
|
||||
}
|
||||
|
||||
// Target node.
|
||||
writeln!(out, " --> {}", outlives.sub.as_usize())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar
|
||||
/// to the graphviz version.
|
||||
fn emit_mermaid_nll_sccs<'tcx>(
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
// The mermaid chart type: a top-down flowchart.
|
||||
writeln!(out, "flowchart TD")?;
|
||||
|
||||
// Gather and emit the SCC nodes.
|
||||
let mut nodes_per_scc: IndexVec<_, _> =
|
||||
regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
|
||||
for region in regioncx.var_infos.indices() {
|
||||
let scc = regioncx.constraint_sccs().scc(region);
|
||||
nodes_per_scc[scc].push(region);
|
||||
}
|
||||
for (scc, regions) in nodes_per_scc.iter_enumerated() {
|
||||
// The node label: the regions contained in the SCC.
|
||||
write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?;
|
||||
for (idx, ®ion) in regions.iter().enumerate() {
|
||||
render_region(region, regioncx, out)?;
|
||||
if idx < regions.len() - 1 {
|
||||
write!(out, ",")?;
|
||||
}
|
||||
}
|
||||
writeln!(out, "}}\"]")?;
|
||||
}
|
||||
|
||||
// Emit the edges between SCCs.
|
||||
let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| {
|
||||
regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target))
|
||||
});
|
||||
for (source, target) in edges {
|
||||
writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a mermaid flowchart of the polonius localized outlives constraints, with subgraphs per
|
||||
/// region, and loan introductions.
|
||||
fn emit_mermaid_constraint_graph<'tcx>(
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<usize> {
|
||||
let location_name = |location: Location| {
|
||||
// A MIR location looks like `bb5[2]`. As that is not a syntactically valid mermaid node id,
|
||||
// transform it into `BB5_2`.
|
||||
format!("BB{}_{}", location.block.index(), location.statement_index)
|
||||
};
|
||||
let region_name = |region: RegionVid| format!("'{}", region.index());
|
||||
let node_name = |region: RegionVid, point: PointIndex| {
|
||||
let location = liveness.location_from_point(point);
|
||||
format!("{}_{}", region_name(region), location_name(location))
|
||||
};
|
||||
|
||||
// The mermaid chart type: a top-down flowchart, which supports subgraphs.
|
||||
writeln!(out, "flowchart TD")?;
|
||||
|
||||
// The loans subgraph: a node per loan.
|
||||
writeln!(out, " subgraph \"Loans\"")?;
|
||||
for loan_idx in 0..borrow_set.len() {
|
||||
writeln!(out, " L{loan_idx}")?;
|
||||
}
|
||||
writeln!(out, " end\n")?;
|
||||
|
||||
// And an edge from that loan node to where it enters the constraint graph.
|
||||
for (loan_idx, loan) in borrow_set.iter_enumerated() {
|
||||
writeln!(
|
||||
out,
|
||||
" L{} --> {}_{}",
|
||||
loan_idx.index(),
|
||||
region_name(loan.region),
|
||||
location_name(loan.reserve_location),
|
||||
)?;
|
||||
}
|
||||
writeln!(out, "")?;
|
||||
|
||||
// The regions subgraphs containing the region/point nodes.
|
||||
let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
|
||||
FxIndexMap::default();
|
||||
for constraint in &localized_outlives_constraints.outlives {
|
||||
points_per_region.entry(constraint.source).or_default().insert(constraint.from);
|
||||
points_per_region.entry(constraint.target).or_default().insert(constraint.to);
|
||||
}
|
||||
for (region, points) in points_per_region {
|
||||
writeln!(out, " subgraph \"{}\"", region_name(region))?;
|
||||
for point in points {
|
||||
writeln!(out, " {}", node_name(region, point))?;
|
||||
}
|
||||
writeln!(out, " end\n")?;
|
||||
}
|
||||
|
||||
// The constraint graph edges.
|
||||
for constraint in &localized_outlives_constraints.outlives {
|
||||
// FIXME: add killed loans and constraint kind as edge labels.
|
||||
writeln!(
|
||||
out,
|
||||
" {} --> {}",
|
||||
node_name(constraint.source, constraint.from),
|
||||
node_name(constraint.target, constraint.to),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Return the number of edges: this is the biggest graph in the dump and its edge count will be
|
||||
// mermaid's max edge count to support.
|
||||
let edge_count = borrow_set.len() + localized_outlives_constraints.outlives.len();
|
||||
Ok(edge_count)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ fn expand_preparsed_asm(
|
|||
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
|
||||
for piece in unverified_pieces {
|
||||
match piece {
|
||||
parse::Piece::String(s) => {
|
||||
parse::Piece::Lit(s) => {
|
||||
template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into()))
|
||||
}
|
||||
parse::Piece::NextArgument(arg) => {
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ fn make_format_args(
|
|||
|
||||
for piece in &pieces {
|
||||
match *piece {
|
||||
parse::Piece::String(s) => {
|
||||
parse::Piece::Lit(s) => {
|
||||
unfinished_literal.push_str(s);
|
||||
}
|
||||
parse::Piece::NextArgument(box parse::Argument { position, position_span, format }) => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use std::iter::FromIterator;
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::Context;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
|
|
@ -45,12 +43,6 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
let known_features = sess.target.rust_target_features();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||
// are disabled.
|
||||
let abi_feature_constraints = sess.target.abi_required_features();
|
||||
let abi_incompatible_set =
|
||||
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
|
||||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
|
|
@ -117,51 +109,11 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||
if enable {
|
||||
if abi_incompatible_set.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "enabled",
|
||||
reason: "this feature is incompatible with the target ABI",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// FIXME: we have to request implied features here since
|
||||
// negative features do not handle implied features above.
|
||||
for &required in abi_feature_constraints.required.iter() {
|
||||
let implied = sess.target.implied_target_features(std::iter::once(required));
|
||||
if implied.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "disabled",
|
||||
reason: "this feature is required by the target ABI",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
// To be sure the ABI-relevant features are all in the right state, we explicitly
|
||||
// (un)set them here. This means if the target spec sets those features wrong,
|
||||
// we will silently correct them rather than silently producing wrong code.
|
||||
// (The target sanity check tries to catch this, but we can't know which features are
|
||||
// enabled in GCC by default so we can't be fully sure about that check.)
|
||||
// We add these at the beginning of the list so that `-Ctarget-features` can
|
||||
// still override it... that's unsound, but more compatible with past behavior.
|
||||
all_rust_features.splice(
|
||||
0..0,
|
||||
abi_feature_constraints
|
||||
.required
|
||||
.iter()
|
||||
.map(|&f| (true, f))
|
||||
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
|
||||
);
|
||||
|
||||
// Translate this into GCC features.
|
||||
let feats =
|
||||
all_rust_features.iter().flat_map(|&(enable, feature)| {
|
||||
|
|
|
|||
|
|
@ -493,9 +493,10 @@ fn target_features_cfg(
|
|||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|&&(_, gate, _)| gate.in_cfg())
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
|
||||
if allow_unstable
|
||||
|| (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||
{
|
||||
Some(feature)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -319,7 +319,6 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
|
|||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.in_cfg())
|
||||
.filter(|(feature, _, _)| {
|
||||
// skip checking special features, as LLVM may not understand them
|
||||
if RUSTC_SPECIAL_FEATURES.contains(feature) {
|
||||
|
|
@ -388,9 +387,13 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
|
|||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.in_cfg())
|
||||
.filter_map(|(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
|
||||
// The `allow_unstable` set is used by rustc internally to determined which target
|
||||
// features are truly available, so we want to return even perma-unstable "forbidden"
|
||||
// features.
|
||||
if allow_unstable
|
||||
|| (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||
{
|
||||
Some(*feature)
|
||||
} else {
|
||||
None
|
||||
|
|
@ -670,12 +673,6 @@ pub(crate) fn global_llvm_features(
|
|||
// Will only be filled when `diagnostics` is set!
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||
// are disabled.
|
||||
let abi_feature_constraints = sess.target.abi_required_features();
|
||||
let abi_incompatible_set =
|
||||
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
|
||||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
|
|
@ -746,52 +743,11 @@ pub(crate) fn global_llvm_features(
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||
if enable {
|
||||
if abi_incompatible_set.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "enabled",
|
||||
reason: "this feature is incompatible with the target ABI",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// FIXME: we have to request implied features here since
|
||||
// negative features do not handle implied features above.
|
||||
for &required in abi_feature_constraints.required.iter() {
|
||||
let implied =
|
||||
sess.target.implied_target_features(std::iter::once(required));
|
||||
if implied.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "disabled",
|
||||
reason: "this feature is required by the target ABI",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
// To be sure the ABI-relevant features are all in the right state, we explicitly
|
||||
// (un)set them here. This means if the target spec sets those features wrong,
|
||||
// we will silently correct them rather than silently producing wrong code.
|
||||
// (The target sanity check tries to catch this, but we can't know which features are
|
||||
// enabled in LLVM by default so we can't be fully sure about that check.)
|
||||
// We add these at the beginning of the list so that `-Ctarget-features` can
|
||||
// still override it... that's unsound, but more compatible with past behavior.
|
||||
all_rust_features.splice(
|
||||
0..0,
|
||||
abi_feature_constraints
|
||||
.required
|
||||
.iter()
|
||||
.map(|&f| (true, f))
|
||||
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
|
||||
);
|
||||
|
||||
// Translate this into LLVM features.
|
||||
let feats = all_rust_features
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ use super::error::*;
|
|||
use crate::errors::{LongRunning, LongRunningWarn};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::interpret::{
|
||||
self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
|
||||
InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, compile_time_machine, interp_ok,
|
||||
throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar,
|
||||
compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom,
|
||||
throw_unsup, throw_unsup_format,
|
||||
};
|
||||
|
||||
/// When hitting this many interpreted terminators we emit a deny by default lint
|
||||
|
|
@ -420,6 +421,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
Size::from_bytes(size),
|
||||
align,
|
||||
interpret::MemoryKind::Machine(MemoryKind::Heap),
|
||||
AllocInit::Uninit,
|
||||
)?;
|
||||
ecx.write_pointer(ptr, dest)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
|||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::{
|
||||
AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
|
||||
CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
|
||||
PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub,
|
||||
throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg,
|
||||
CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
|
||||
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
|
||||
err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
|
|
@ -230,11 +230,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
size: Size,
|
||||
align: Align,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
init: AllocInit,
|
||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||
let alloc = if M::PANIC_ON_ALLOC_FAIL {
|
||||
Allocation::uninit(size, align)
|
||||
Allocation::new(size, align, init)
|
||||
} else {
|
||||
Allocation::try_uninit(size, align)?
|
||||
Allocation::try_new(size, align, init)?
|
||||
};
|
||||
self.insert_allocation(alloc, kind)
|
||||
}
|
||||
|
|
@ -270,6 +271,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
|
||||
}
|
||||
|
||||
/// If this grows the allocation, `init_growth` determines
|
||||
/// whether the additional space will be initialized.
|
||||
pub fn reallocate_ptr(
|
||||
&mut self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
|
|
@ -277,6 +280,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
new_size: Size,
|
||||
new_align: Align,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
init_growth: AllocInit,
|
||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||
let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
|
||||
if offset.bytes() != 0 {
|
||||
|
|
@ -289,7 +293,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
// For simplicities' sake, we implement reallocate as "alloc, copy, dealloc".
|
||||
// This happens so rarely, the perf advantage is outweighed by the maintenance cost.
|
||||
let new_ptr = self.allocate_ptr(new_size, new_align, kind)?;
|
||||
// If requested, we zero-init the entire allocation, to ensure that a growing
|
||||
// allocation has its new bytes properly set. For the part that is copied,
|
||||
// `mem_copy` below will de-initialize things as necessary.
|
||||
let new_ptr = self.allocate_ptr(new_size, new_align, kind, init_growth)?;
|
||||
let old_size = match old_size_and_align {
|
||||
Some((size, _align)) => size,
|
||||
None => self.get_alloc_raw(alloc_id)?.size(),
|
||||
|
|
@ -830,9 +837,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
/// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is
|
||||
/// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics.
|
||||
pub fn is_alloc_live(&self, id: AllocId) -> bool {
|
||||
self.tcx.try_get_global_alloc(id).is_some()
|
||||
|| self.memory.alloc_map.contains_key_ref(&id)
|
||||
self.memory.alloc_map.contains_key_ref(&id)
|
||||
|| self.memory.extra_fn_ptr_map.contains_key(&id)
|
||||
// We check `tcx` last as that has to acquire a lock in `many-seeds` mode.
|
||||
// This also matches the order in `get_alloc_info`.
|
||||
|| self.tcx.try_get_global_alloc(id).is_some()
|
||||
}
|
||||
|
||||
/// Obtain the size and alignment of an allocation, even if that allocation has
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ use rustc_middle::{bug, mir, span_bug};
|
|||
use tracing::{instrument, trace};
|
||||
|
||||
use super::{
|
||||
AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult,
|
||||
Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance,
|
||||
Scalar, alloc_range, interp_ok, mir_assign_valid_types,
|
||||
AllocInit, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx,
|
||||
InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer,
|
||||
Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
|
||||
|
|
@ -983,7 +983,7 @@ where
|
|||
let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
|
||||
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
|
||||
};
|
||||
let ptr = self.allocate_ptr(size, align, kind)?;
|
||||
let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?;
|
||||
interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::ops::ControlFlow;
|
|||
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
|
||||
use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
|
|
@ -76,7 +76,7 @@ pub(crate) fn create_static_alloc<'tcx>(
|
|||
static_def_id: LocalDefId,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
|
||||
let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?;
|
||||
let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?;
|
||||
let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
|
||||
assert_eq!(ecx.machine.static_root_ids, None);
|
||||
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ pub trait Callbacks {
|
|||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
_queries: &ast::Crate,
|
||||
_krate: &mut ast::Crate,
|
||||
) -> Compilation {
|
||||
Compilation::Continue
|
||||
}
|
||||
|
|
@ -311,7 +311,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
|
|||
|
||||
// Parse the crate root source code (doesn't parse submodules yet)
|
||||
// Everything else is parsed during macro expansion.
|
||||
let krate = passes::parse(sess);
|
||||
let mut krate = passes::parse(sess);
|
||||
|
||||
// If pretty printing is requested: Figure out the representation, print it and exit
|
||||
if let Some(pp_mode) = sess.opts.pretty {
|
||||
|
|
@ -328,7 +328,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
if callbacks.after_crate_root_parsing(compiler, &krate) == Compilation::Stop {
|
||||
if callbacks.after_crate_root_parsing(compiler, &mut krate) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1437,7 +1437,7 @@ impl<'hir> Pat<'hir> {
|
|||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
|
|
@ -1464,7 +1464,7 @@ impl<'hir> Pat<'hir> {
|
|||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
|
|
@ -1618,9 +1618,6 @@ pub enum PatKind<'hir> {
|
|||
/// A never pattern `!`.
|
||||
Never,
|
||||
|
||||
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
|
||||
Path(QPath<'hir>),
|
||||
|
||||
/// A tuple pattern (e.g., `(a, b)`).
|
||||
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
|
||||
/// `0 <= position <= subpats.len()`
|
||||
|
|
|
|||
|
|
@ -709,9 +709,6 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
|||
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
|
||||
walk_list!(visitor, visit_pat, children);
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
|
||||
}
|
||||
PatKind::Struct(ref qpath, fields, _) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
|
||||
walk_list!(visitor, visit_pat_field, fields);
|
||||
|
|
|
|||
|
|
@ -105,7 +105,10 @@ impl hir::Pat<'_> {
|
|||
let mut variants = vec![];
|
||||
self.walk(|p| match &p.kind {
|
||||
PatKind::Or(_) => false,
|
||||
PatKind::Path(hir::QPath::Resolved(_, path))
|
||||
PatKind::Expr(hir::PatExpr {
|
||||
kind: hir::PatExprKind::Path(hir::QPath::Resolved(_, path)),
|
||||
..
|
||||
})
|
||||
| PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
|
||||
| PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
|
||||
if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ fn fn_sig_suggestion<'tcx>(
|
|||
|
||||
let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
|
||||
output = if let ty::Alias(_, alias_ty) = *output.kind() {
|
||||
tcx.explicit_item_super_predicates(alias_ty.def_id)
|
||||
tcx.explicit_item_self_bounds(alias_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, alias_ty.args)
|
||||
.find_map(|(bound, _)| {
|
||||
bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
|
||||
|
|
|
|||
|
|
@ -703,7 +703,6 @@ fn resolve_local<'tcx>(
|
|||
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(_, _, _)
|
||||
| PatKind::Err(_) => false,
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ pub fn provide(providers: &mut Providers) {
|
|||
type_alias_is_lazy: type_of::type_alias_is_lazy,
|
||||
item_bounds: item_bounds::item_bounds,
|
||||
explicit_item_bounds: item_bounds::explicit_item_bounds,
|
||||
item_super_predicates: item_bounds::item_super_predicates,
|
||||
explicit_item_super_predicates: item_bounds::explicit_item_super_predicates,
|
||||
item_non_self_assumptions: item_bounds::item_non_self_assumptions,
|
||||
item_self_bounds: item_bounds::item_self_bounds,
|
||||
explicit_item_self_bounds: item_bounds::explicit_item_self_bounds,
|
||||
item_non_self_bounds: item_bounds::item_non_self_bounds,
|
||||
impl_super_outlives: item_bounds::impl_super_outlives,
|
||||
generics_of: generics_of::generics_of,
|
||||
predicates_of: predicates_of::predicates_of,
|
||||
|
|
@ -328,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
|||
self.tcx.ensure().generics_of(def_id);
|
||||
self.tcx.ensure().predicates_of(def_id);
|
||||
self.tcx.ensure().explicit_item_bounds(def_id);
|
||||
self.tcx.ensure().explicit_item_super_predicates(def_id);
|
||||
self.tcx.ensure().explicit_item_self_bounds(def_id);
|
||||
self.tcx.ensure().item_bounds(def_id);
|
||||
self.tcx.ensure().item_super_predicates(def_id);
|
||||
self.tcx.ensure().item_self_bounds(def_id);
|
||||
if self.tcx.is_conditionally_const(def_id) {
|
||||
self.tcx.ensure().explicit_implied_const_bounds(def_id);
|
||||
self.tcx.ensure().const_conditions(def_id);
|
||||
|
|
@ -822,7 +822,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
|||
|
||||
hir::TraitItemKind::Type(_, Some(_)) => {
|
||||
tcx.ensure().item_bounds(def_id);
|
||||
tcx.ensure().item_super_predicates(def_id);
|
||||
tcx.ensure().item_self_bounds(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
// Account for `type T = _;`.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
|
|
@ -839,7 +839,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
|||
|
||||
hir::TraitItemKind::Type(_, None) => {
|
||||
tcx.ensure().item_bounds(def_id);
|
||||
tcx.ensure().item_super_predicates(def_id);
|
||||
tcx.ensure().item_self_bounds(def_id);
|
||||
// #74612: Visit and try to find bad placeholders
|
||||
// even if there is no concrete type.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ pub(super) fn explicit_item_bounds(
|
|||
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
|
||||
}
|
||||
|
||||
pub(super) fn explicit_item_super_predicates(
|
||||
pub(super) fn explicit_item_self_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
|
||||
|
|
@ -434,11 +434,11 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_,
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn item_super_predicates(
|
||||
pub(super) fn item_self_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
|
||||
tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
|
||||
tcx.explicit_item_self_bounds(def_id).map_bound(|bounds| {
|
||||
tcx.mk_clauses_from_iter(
|
||||
util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
|
||||
)
|
||||
|
|
@ -447,13 +447,12 @@ pub(super) fn item_super_predicates(
|
|||
|
||||
/// This exists as an optimization to compute only the item bounds of the item
|
||||
/// that are not `Self` bounds.
|
||||
pub(super) fn item_non_self_assumptions(
|
||||
pub(super) fn item_non_self_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
|
||||
let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
|
||||
let own_bounds: FxIndexSet<_> =
|
||||
tcx.item_super_predicates(def_id).skip_binder().iter().collect();
|
||||
let own_bounds: FxIndexSet<_> = tcx.item_self_bounds(def_id).skip_binder().iter().collect();
|
||||
if all_bounds.len() == own_bounds.len() {
|
||||
ty::EarlyBinder::bind(ty::ListWithCachedTypeInfo::empty())
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
|
||||
..
|
||||
})
|
||||
| hir::Node::Pat(hir::Pat {
|
||||
kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)),
|
||||
| hir::Node::PatExpr(hir::PatExpr {
|
||||
kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
|
||||
..
|
||||
}) if qself.hir_id == self_ty.hir_id => true,
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -1906,9 +1906,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
self.print_qpath(qpath, true);
|
||||
}
|
||||
PatKind::Struct(ref qpath, fields, etc) => {
|
||||
self.print_qpath(qpath, true);
|
||||
self.nbsp();
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected_ty,
|
||||
closure_kind,
|
||||
self.tcx
|
||||
.explicit_item_super_predicates(def_id)
|
||||
.explicit_item_self_bounds(def_id)
|
||||
.iter_instantiated_copied(self.tcx, args)
|
||||
.map(|(c, s)| (c.as_predicate(), s)),
|
||||
),
|
||||
|
|
@ -1019,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
||||
.tcx
|
||||
.explicit_item_super_predicates(def_id)
|
||||
.explicit_item_self_bounds(def_id)
|
||||
.iter_instantiated_copied(self.tcx, args)
|
||||
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
|
||||
ty::Error(_) => return Some(ret_ty),
|
||||
|
|
|
|||
|
|
@ -1847,30 +1847,26 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
fcx.probe(|_| {
|
||||
let ocx = ObligationCtxt::new(fcx);
|
||||
ocx.register_obligations(
|
||||
fcx.tcx.item_super_predicates(rpit_def_id).iter_identity().filter_map(
|
||||
|clause| {
|
||||
let predicate = clause
|
||||
.kind()
|
||||
.map_bound(|clause| match clause {
|
||||
ty::ClauseKind::Trait(trait_pred) => Some(
|
||||
ty::ClauseKind::Trait(trait_pred.with_self_ty(fcx.tcx, ty)),
|
||||
),
|
||||
ty::ClauseKind::Projection(proj_pred) => {
|
||||
Some(ty::ClauseKind::Projection(
|
||||
proj_pred.with_self_ty(fcx.tcx, ty),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.transpose()?;
|
||||
Some(Obligation::new(
|
||||
fcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
fcx.param_env,
|
||||
predicate,
|
||||
))
|
||||
},
|
||||
),
|
||||
fcx.tcx.item_self_bounds(rpit_def_id).iter_identity().filter_map(|clause| {
|
||||
let predicate = clause
|
||||
.kind()
|
||||
.map_bound(|clause| match clause {
|
||||
ty::ClauseKind::Trait(trait_pred) => Some(ty::ClauseKind::Trait(
|
||||
trait_pred.with_self_ty(fcx.tcx, ty),
|
||||
)),
|
||||
ty::ClauseKind::Projection(proj_pred) => Some(
|
||||
ty::ClauseKind::Projection(proj_pred.with_self_ty(fcx.tcx, ty)),
|
||||
),
|
||||
_ => None,
|
||||
})
|
||||
.transpose()?;
|
||||
Some(Obligation::new(
|
||||
fcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
fcx.param_env,
|
||||
predicate,
|
||||
))
|
||||
}),
|
||||
);
|
||||
ocx.select_where_possible().is_empty()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -480,7 +480,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir::PatKind::Binding(_, _, _, _)
|
||||
| hir::PatKind::Struct(_, _, _)
|
||||
| hir::PatKind::TupleStruct(_, _, _)
|
||||
| hir::PatKind::Path(_)
|
||||
| hir::PatKind::Tuple(_, _)
|
||||
| hir::PatKind::Box(_)
|
||||
| hir::PatKind::Ref(_, _)
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ use hir::def::DefKind;
|
|||
use hir::pat_util::EnumerateAndAdjustIterator as _;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::{HirId, PatKind};
|
||||
use rustc_hir::{self as hir, HirId, PatExpr, PatExprKind, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::place::ProjectionKind;
|
||||
// Export these here so that Clippy can use them.
|
||||
|
|
@ -564,11 +563,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// FIXME(never_patterns): does this do what I expect?
|
||||
needs_to_be_read = true;
|
||||
}
|
||||
PatKind::Path(qpath) => {
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
|
||||
// A `Path` pattern is just a name like `Foo`. This is either a
|
||||
// named constant or else it refers to an ADT variant
|
||||
|
||||
let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id);
|
||||
let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
|
||||
match res {
|
||||
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
|
||||
// Named constants have to be equated with the value
|
||||
|
|
@ -581,7 +580,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// Otherwise, this is a struct/enum variant, and so it's
|
||||
// only a read if we need to read the discriminant.
|
||||
needs_to_be_read |=
|
||||
self.is_multivariant_adt(place.place.ty(), pat.span);
|
||||
self.is_multivariant_adt(place.place.ty(), *span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1801,8 +1800,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
PatKind::Path(_)
|
||||
| PatKind::Binding(.., None)
|
||||
PatKind::Binding(.., None)
|
||||
| PatKind::Expr(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Never
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ use hir::def_id::LocalDefId;
|
|||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
|
||||
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens,
|
||||
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
|
||||
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
|
||||
WherePredicateKind, expr_needs_parens,
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
|
|
@ -1422,8 +1422,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// since the user probably just misunderstood how `let else`
|
||||
// and `&&` work together.
|
||||
if let Some((_, hir::Node::LetStmt(local))) = cond_parent
|
||||
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
|
||||
&local.pat.kind
|
||||
&& let hir::PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
|
||||
| hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
|
||||
&& let hir::QPath::Resolved(None, path) = qpath
|
||||
&& let Some(did) = path
|
||||
.res
|
||||
|
|
|
|||
|
|
@ -177,8 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
})
|
||||
| hir::Node::Pat(&hir::Pat {
|
||||
kind:
|
||||
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
|
||||
| hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
|
||||
hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
|
||||
| hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..),
|
||||
span,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ use rustc_errors::{
|
|||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::{
|
||||
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind,
|
||||
expr_needs_parens,
|
||||
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
|
||||
PatExprKind, PatKind, expr_needs_parens,
|
||||
};
|
||||
use rustc_infer::infer;
|
||||
use rustc_middle::traits::PatternOriginExpr;
|
||||
|
|
@ -312,9 +312,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
|
||||
let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
|
||||
|
||||
let path_res = match &pat.kind {
|
||||
PatKind::Path(qpath) => {
|
||||
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
|
||||
let path_res = match pat.kind {
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
|
||||
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
|
@ -333,6 +333,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::Wild | PatKind::Err(_) => expected,
|
||||
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||
PatKind::Never => expected,
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
|
||||
let ty = self.check_pat_path(
|
||||
*hir_id,
|
||||
pat.hir_id,
|
||||
*span,
|
||||
qpath,
|
||||
path_res.unwrap(),
|
||||
expected,
|
||||
ti,
|
||||
);
|
||||
self.write_ty(*hir_id, ty);
|
||||
ty
|
||||
}
|
||||
PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||
PatKind::Binding(ba, var_id, ident, sub) => {
|
||||
|
|
@ -341,9 +354,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
|
||||
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
|
||||
}
|
||||
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
||||
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
||||
}
|
||||
|
|
@ -456,16 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| PatKind::Slice(..) => AdjustMode::Peel,
|
||||
// A never pattern behaves somewhat like a literal or unit variant.
|
||||
PatKind::Never => AdjustMode::Peel,
|
||||
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
||||
// All other literals result in non-reference types.
|
||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
|
||||
//
|
||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
|
||||
ty::Ref(..) => AdjustMode::Pass,
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
PatKind::Path(_) => match opt_path_res.unwrap() {
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() {
|
||||
// These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
|
||||
// Peeling the reference types too early will cause type checking failures.
|
||||
// Although it would be possible to *also* peel the types of the constants too.
|
||||
|
|
@ -476,6 +477,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// a reference type wherefore peeling doesn't give up any expressiveness.
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
|
||||
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
||||
// All other literals result in non-reference types.
|
||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
|
||||
//
|
||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
|
||||
ty::Ref(..) => AdjustMode::Pass,
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
|
||||
// Ref patterns are complicated, we handle them in `check_pat_ref`.
|
||||
PatKind::Ref(..) => AdjustMode::Pass,
|
||||
// A `_` pattern works with any expected type, so there's no need to do anything.
|
||||
|
|
@ -1001,7 +1013,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Binding(..)
|
||||
| PatKind::Path(..)
|
||||
| PatKind::Box(..)
|
||||
| PatKind::Deref(_)
|
||||
| PatKind::Ref(..)
|
||||
|
|
@ -1139,7 +1150,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn check_pat_path(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
path_id: HirId,
|
||||
pat_id_for_diag: HirId,
|
||||
span: Span,
|
||||
qpath: &hir::QPath<'_>,
|
||||
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
||||
|
|
@ -1193,11 +1205,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Type-check the path.
|
||||
let (pat_ty, pat_res) =
|
||||
self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
|
||||
self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
|
||||
if let Err(err) =
|
||||
self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
|
||||
{
|
||||
self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
|
||||
self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments);
|
||||
}
|
||||
pat_ty
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir_analysis::autoderef::Autoderef;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::traits::{Obligation, ObligationCauseCode};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::adjustment::{
|
||||
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, OverloadedDeref,
|
||||
|
|
@ -136,8 +137,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut self_ty = adjusted_ty;
|
||||
if unsize {
|
||||
// We only unsize arrays here.
|
||||
if let ty::Array(element_ty, _) = adjusted_ty.kind() {
|
||||
self_ty = Ty::new_slice(self.tcx, *element_ty);
|
||||
if let ty::Array(element_ty, ct) = *adjusted_ty.kind() {
|
||||
self.register_predicate(Obligation::new(
|
||||
self.tcx,
|
||||
self.cause(base_expr.span, ObligationCauseCode::ArrayLen(adjusted_ty)),
|
||||
self.param_env,
|
||||
ty::ClauseKind::ConstArgHasType(ct, self.tcx.types.usize),
|
||||
));
|
||||
self_ty = Ty::new_slice(self.tcx, element_ty);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
alias_ty: ty::AliasTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let bounds = tcx.item_super_predicates(alias_ty.def_id);
|
||||
let bounds = tcx.item_self_bounds(alias_ty.def_id);
|
||||
trace!("{:#?}", bounds.skip_binder());
|
||||
bounds
|
||||
.iter_instantiated(tcx, alias_ty.args)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
interface_abi_required_feature =
|
||||
target feature `{$feature}` must be {$enabled} to ensure that the ABI of the current target can be implemented correctly
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
interface_abi_required_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
interface_cant_emit_mir =
|
||||
could not emit MIR: {$error}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,3 +103,12 @@ pub struct IgnoringOutDir;
|
|||
#[derive(Diagnostic)]
|
||||
#[diag(interface_multiple_output_types_to_stdout)]
|
||||
pub struct MultipleOutputTypesToStdout;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(interface_abi_required_feature)]
|
||||
#[note]
|
||||
#[note(interface_abi_required_feature_issue)]
|
||||
pub(crate) struct AbiRequiredTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -492,6 +492,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
}
|
||||
sess.lint_store = Some(Lrc::new(lint_store));
|
||||
|
||||
util::check_abi_required_features(&sess);
|
||||
|
||||
let compiler = Compiler {
|
||||
sess,
|
||||
codegen_backend,
|
||||
|
|
|
|||
|
|
@ -18,21 +18,25 @@ use rustc_session::{EarlyDiagCtxt, Session, filesearch};
|
|||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::SourceMapInputs;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_target::spec::Target;
|
||||
use tracing::info;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
/// Function pointer type that constructs a new CodegenBackend.
|
||||
pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
|
||||
type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
|
||||
|
||||
/// Adds `target_feature = "..."` cfgs for a variety of platform
|
||||
/// specific features (SSE, NEON etc.).
|
||||
///
|
||||
/// This is performed by checking whether a set of permitted features
|
||||
/// is available on the target machine, by querying the codegen backend.
|
||||
pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
|
||||
pub(crate) fn add_configuration(
|
||||
cfg: &mut Cfg,
|
||||
sess: &mut Session,
|
||||
codegen_backend: &dyn CodegenBackend,
|
||||
) {
|
||||
let tf = sym::target_feature;
|
||||
|
||||
let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
|
||||
|
|
@ -48,6 +52,34 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
|
|||
}
|
||||
}
|
||||
|
||||
/// Ensures that all target features required by the ABI are present.
|
||||
/// Must be called after `unstable_target_features` has been populated!
|
||||
pub(crate) fn check_abi_required_features(sess: &Session) {
|
||||
let abi_feature_constraints = sess.target.abi_required_features();
|
||||
// We check this against `unstable_target_features` as that is conveniently already
|
||||
// back-translated to rustc feature names, taking into account `-Ctarget-cpu` and `-Ctarget-feature`.
|
||||
// Just double-check that the features we care about are actually on our list.
|
||||
for feature in
|
||||
abi_feature_constraints.required.iter().chain(abi_feature_constraints.incompatible.iter())
|
||||
{
|
||||
assert!(
|
||||
sess.target.rust_target_features().iter().any(|(name, ..)| feature == name),
|
||||
"target feature {feature} is required/incompatible for the current ABI but not a recognized feature for this target"
|
||||
);
|
||||
}
|
||||
|
||||
for feature in abi_feature_constraints.required {
|
||||
if !sess.unstable_target_features.contains(&Symbol::intern(feature)) {
|
||||
sess.dcx().emit_warn(errors::AbiRequiredTargetFeature { feature, enabled: "enabled" });
|
||||
}
|
||||
}
|
||||
for feature in abi_feature_constraints.incompatible {
|
||||
if sess.unstable_target_features.contains(&Symbol::intern(feature)) {
|
||||
sess.dcx().emit_warn(errors::AbiRequiredTargetFeature { feature, enabled: "disabled" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
|
||||
pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
|
|
|
|||
|
|
@ -330,10 +330,12 @@ impl EarlyLintPass for UnsafeCode {
|
|||
if let FnKind::Fn(
|
||||
ctxt,
|
||||
_,
|
||||
ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
|
||||
_,
|
||||
_,
|
||||
body,
|
||||
ast::Fn {
|
||||
sig: ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
|
||||
body,
|
||||
..
|
||||
},
|
||||
) = fk
|
||||
{
|
||||
let decorator = match ctxt {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_hir::def::Res;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{
|
||||
AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
|
||||
PatKind, Path, PathSegment, QPath, Ty, TyKind,
|
||||
PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Ty, TyKind,
|
||||
};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
|
@ -164,11 +164,9 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
|
|||
TyKind::Path(QPath::Resolved(_, path)) => {
|
||||
if lint_ty_kind_usage(cx, &path.res) {
|
||||
let span = match cx.tcx.parent_hir_node(ty.hir_id) {
|
||||
Node::Pat(Pat {
|
||||
kind:
|
||||
PatKind::Path(qpath)
|
||||
| PatKind::TupleStruct(qpath, ..)
|
||||
| PatKind::Struct(qpath, ..),
|
||||
Node::PatExpr(PatExpr { kind: PatExprKind::Path(qpath), .. })
|
||||
| Node::Pat(Pat {
|
||||
kind: PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..),
|
||||
..
|
||||
})
|
||||
| Node::Expr(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatKind};
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
|
|
@ -527,7 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
|
|||
|
||||
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
|
||||
// Lint for constants that look like binding identifiers (#7526)
|
||||
if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
|
||||
if let PatKind::Expr(hir::PatExpr {
|
||||
kind: PatExprKind::Path(hir::QPath::Resolved(None, path)),
|
||||
..
|
||||
}) = p.kind
|
||||
{
|
||||
if let Res::Def(DefKind::Const, _) = path.res {
|
||||
if let [segment] = path.segments {
|
||||
NonUpperCaseGlobals::check_upper_case(
|
||||
|
|
|
|||
|
|
@ -289,25 +289,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|||
}
|
||||
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
|
||||
ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
|
||||
elaborate(
|
||||
cx.tcx,
|
||||
cx.tcx.explicit_item_super_predicates(def).iter_identity_copied(),
|
||||
)
|
||||
// We only care about self bounds for the impl-trait
|
||||
.filter_only_self()
|
||||
.find_map(|(pred, _span)| {
|
||||
// We only look at the `DefId`, so it is safe to skip the binder here.
|
||||
if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
|
||||
pred.kind().skip_binder()
|
||||
{
|
||||
let def_id = poly_trait_predicate.trait_ref.def_id;
|
||||
elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied())
|
||||
// We only care about self bounds for the impl-trait
|
||||
.filter_only_self()
|
||||
.find_map(|(pred, _span)| {
|
||||
// We only look at the `DefId`, so it is safe to skip the binder here.
|
||||
if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
|
||||
pred.kind().skip_binder()
|
||||
{
|
||||
let def_id = poly_trait_predicate.trait_ref.def_id;
|
||||
|
||||
is_def_must_use(cx, def_id, span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
|
||||
is_def_must_use(cx, def_id, span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
|
||||
}
|
||||
ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
|
||||
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) {
|
|||
|
||||
provide! { tcx, def_id, other, cdata,
|
||||
explicit_item_bounds => { table_defaulted_array }
|
||||
explicit_item_super_predicates => { table_defaulted_array }
|
||||
explicit_item_self_bounds => { table_defaulted_array }
|
||||
explicit_predicates_of => { table }
|
||||
generics_of => { table }
|
||||
inferred_outlives_of => { table_defaulted_array }
|
||||
|
|
|
|||
|
|
@ -1554,7 +1554,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
if let DefKind::OpaqueTy = def_kind {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
self.encode_explicit_item_super_predicates(def_id);
|
||||
self.encode_explicit_item_self_bounds(def_id);
|
||||
record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id));
|
||||
self.encode_precise_capturing_args(def_id);
|
||||
if tcx.is_conditionally_const(def_id) {
|
||||
|
|
@ -1667,10 +1667,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
|
||||
}
|
||||
|
||||
fn encode_explicit_item_super_predicates(&mut self, def_id: DefId) {
|
||||
debug!("EncodeContext::encode_explicit_item_super_predicates({:?})", def_id);
|
||||
let bounds = self.tcx.explicit_item_super_predicates(def_id).skip_binder();
|
||||
record_defaulted_array!(self.tables.explicit_item_super_predicates[def_id] <- bounds);
|
||||
fn encode_explicit_item_self_bounds(&mut self, def_id: DefId) {
|
||||
debug!("EncodeContext::encode_explicit_item_self_bounds({:?})", def_id);
|
||||
let bounds = self.tcx.explicit_item_self_bounds(def_id).skip_binder();
|
||||
record_defaulted_array!(self.tables.explicit_item_self_bounds[def_id] <- bounds);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -1685,7 +1685,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
AssocItemContainer::Trait => {
|
||||
if let ty::AssocKind::Type = item.kind {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
self.encode_explicit_item_super_predicates(def_id);
|
||||
self.encode_explicit_item_self_bounds(def_id);
|
||||
if tcx.is_conditionally_const(def_id) {
|
||||
record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
|
||||
<- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ define_tables! {
|
|||
// corresponding DefPathHash.
|
||||
def_path_hashes: Table<DefIndex, u64>,
|
||||
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_item_self_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
|
|
|
|||
|
|
@ -270,6 +270,12 @@ impl AllocRange {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether a new allocation should be initialized with zero-bytes.
|
||||
pub enum AllocInit {
|
||||
Uninit,
|
||||
Zero,
|
||||
}
|
||||
|
||||
// The constructors are all without extra; the extra gets added by a machine hook later.
|
||||
impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||
/// Creates an allocation initialized by the given bytes
|
||||
|
|
@ -294,7 +300,12 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
|||
Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
|
||||
}
|
||||
|
||||
fn uninit_inner<R>(size: Size, align: Align, fail: impl FnOnce() -> R) -> Result<Self, R> {
|
||||
fn new_inner<R>(
|
||||
size: Size,
|
||||
align: Align,
|
||||
init: AllocInit,
|
||||
fail: impl FnOnce() -> R,
|
||||
) -> Result<Self, R> {
|
||||
// We raise an error if we cannot create the allocation on the host.
|
||||
// This results in an error that can happen non-deterministically, since the memory
|
||||
// available to the compiler can change between runs. Normally queries are always
|
||||
|
|
@ -306,7 +317,10 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
|||
Ok(Allocation {
|
||||
bytes,
|
||||
provenance: ProvenanceMap::new(),
|
||||
init_mask: InitMask::new(size, false),
|
||||
init_mask: InitMask::new(size, match init {
|
||||
AllocInit::Uninit => false,
|
||||
AllocInit::Zero => true,
|
||||
}),
|
||||
align,
|
||||
mutability: Mutability::Mut,
|
||||
extra: (),
|
||||
|
|
@ -315,8 +329,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
|||
|
||||
/// Try to create an Allocation of `size` bytes, failing if there is not enough memory
|
||||
/// available to the compiler to do so.
|
||||
pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> {
|
||||
Self::uninit_inner(size, align, || {
|
||||
pub fn try_new<'tcx>(size: Size, align: Align, init: AllocInit) -> InterpResult<'tcx, Self> {
|
||||
Self::new_inner(size, align, init, || {
|
||||
ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
|
||||
InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
|
||||
})
|
||||
|
|
@ -328,8 +342,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
|||
///
|
||||
/// Example use case: To obtain an Allocation filled with specific data,
|
||||
/// first call this function and then call write_scalar to fill in the right data.
|
||||
pub fn uninit(size: Size, align: Align) -> Self {
|
||||
match Self::uninit_inner(size, align, || {
|
||||
pub fn new(size: Size, align: Align, init: AllocInit) -> Self {
|
||||
match Self::new_inner(size, align, init, || {
|
||||
panic!(
|
||||
"interpreter ran out of memory: cannot create allocation of {} bytes",
|
||||
size.bytes()
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ pub use {
|
|||
};
|
||||
|
||||
pub use self::allocation::{
|
||||
AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk,
|
||||
InitChunkIter, alloc_range,
|
||||
AllocBytes, AllocError, AllocInit, AllocRange, AllocResult, Allocation, ConstAllocation,
|
||||
InitChunk, InitChunkIter, alloc_range,
|
||||
};
|
||||
pub use self::error::{
|
||||
BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ rustc_queries! {
|
|||
/// like closure signature deduction.
|
||||
///
|
||||
/// [explicit item bounds]: Self::explicit_item_bounds
|
||||
query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
query explicit_item_self_bounds(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
|
||||
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -427,11 +427,11 @@ rustc_queries! {
|
|||
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
query item_self_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
query item_non_self_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
|
||||
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
/// A slice or array is WF only if `T: Sized`.
|
||||
SliceOrArrayElem,
|
||||
|
||||
/// An array `[T; N]` can only be indexed (and is only well-formed if) `N` has type usize.
|
||||
ArrayLen(Ty<'tcx>),
|
||||
|
||||
/// A tuple is WF only if its middle elements are `Sized`.
|
||||
TupleElem,
|
||||
|
||||
|
|
|
|||
|
|
@ -345,6 +345,20 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn item_self_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_self_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn item_non_self_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_non_self_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
|
|
@ -2577,7 +2591,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
|
||||
let future_trait = self.require_lang_item(LangItem::Future, None);
|
||||
|
||||
self.explicit_item_super_predicates(def_id).skip_binder().iter().any(|&(predicate, _)| {
|
||||
self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
|
||||
let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
|
||||
return false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1740,6 +1740,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
" as ",
|
||||
)?;
|
||||
}
|
||||
ty::Pat(base_ty, pat) => {
|
||||
self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?;
|
||||
p!(write(" is {pat:?}"));
|
||||
}
|
||||
// Nontrivial types with scalar bit representation
|
||||
_ => {
|
||||
let print = |this: &mut Self| {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
let mut bounds: Vec<_> = self
|
||||
.item_super_predicates(def_id)
|
||||
.item_self_bounds(def_id)
|
||||
.iter_instantiated(self, args)
|
||||
.filter_map(|clause| {
|
||||
clause
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use rustc_ast::Mutability;
|
|||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::elaborate;
|
||||
|
||||
use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range};
|
||||
use crate::mir::interpret::{
|
||||
AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range,
|
||||
};
|
||||
use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, HashStable)]
|
||||
|
|
@ -108,7 +110,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
|||
let ptr_align = tcx.data_layout.pointer_align.abi;
|
||||
|
||||
let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
|
||||
let mut vtable = Allocation::uninit(vtable_size, ptr_align);
|
||||
let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit);
|
||||
|
||||
// No need to do any alignment checks on the memory accesses below, because we know the
|
||||
// allocation is correctly aligned as we created it above. Also we're only offsetting by
|
||||
|
|
|
|||
|
|
@ -141,43 +141,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
||||
}
|
||||
|
||||
TestKind::Eq { value, ty } => {
|
||||
TestKind::Eq { value, mut ty } => {
|
||||
let tcx = self.tcx;
|
||||
let success_block = target_block(TestBranch::Success);
|
||||
let fail_block = target_block(TestBranch::Failure);
|
||||
if let ty::Adt(def, _) = ty.kind()
|
||||
&& tcx.is_lang_item(def.did(), LangItem::String)
|
||||
{
|
||||
if !tcx.features().string_deref_patterns() {
|
||||
span_bug!(
|
||||
|
||||
let expect_ty = value.ty();
|
||||
let expect = self.literal_operand(test.span, value);
|
||||
|
||||
let mut place = place;
|
||||
let mut block = block;
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
|
||||
if !tcx.features().string_deref_patterns() {
|
||||
span_bug!(
|
||||
test.span,
|
||||
"matching on `String` went through without enabling string_deref_patterns"
|
||||
);
|
||||
}
|
||||
let re_erased = tcx.lifetimes.re_erased;
|
||||
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
|
||||
let ref_str = self.temp(ref_str_ty, test.span);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
// `let ref_str: &str = <String as Deref>::deref(&place);`
|
||||
self.call_deref(
|
||||
block,
|
||||
eq_block,
|
||||
place,
|
||||
Mutability::Not,
|
||||
ty,
|
||||
ref_str,
|
||||
test.span,
|
||||
"matching on `String` went through without enabling string_deref_patterns"
|
||||
);
|
||||
// Since we generated a `ref_str = <String as Deref>::deref(&place) -> eq_block` terminator,
|
||||
// we need to add all further statements to `eq_block`.
|
||||
// Similarly, the normal test code should be generated for the `&str`, instead of the `String`.
|
||||
block = eq_block;
|
||||
place = ref_str;
|
||||
ty = ref_str_ty;
|
||||
}
|
||||
let re_erased = tcx.lifetimes.re_erased;
|
||||
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
|
||||
let ref_str = self.temp(ref_str_ty, test.span);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
// `let ref_str: &str = <String as Deref>::deref(&place);`
|
||||
self.call_deref(
|
||||
block,
|
||||
eq_block,
|
||||
place,
|
||||
Mutability::Not,
|
||||
ty,
|
||||
ref_str,
|
||||
test.span,
|
||||
);
|
||||
self.non_scalar_compare(
|
||||
eq_block,
|
||||
success_block,
|
||||
fail_block,
|
||||
source_info,
|
||||
value,
|
||||
ref_str,
|
||||
ref_str_ty,
|
||||
);
|
||||
} else if !ty.is_scalar() {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !ty.is_scalar() {
|
||||
// Use `PartialEq::eq` instead of `BinOp::Eq`
|
||||
// (the binop can only handle primitives)
|
||||
self.non_scalar_compare(
|
||||
|
|
@ -185,14 +191,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
success_block,
|
||||
fail_block,
|
||||
source_info,
|
||||
value,
|
||||
place,
|
||||
expect,
|
||||
expect_ty,
|
||||
Operand::Copy(place),
|
||||
ty,
|
||||
);
|
||||
} else {
|
||||
assert_eq!(value.ty(), ty);
|
||||
let expect = self.literal_operand(test.span, value);
|
||||
let val = Operand::Copy(place);
|
||||
assert_eq!(expect_ty, ty);
|
||||
self.compare(
|
||||
block,
|
||||
success_block,
|
||||
|
|
@ -200,7 +205,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
source_info,
|
||||
BinOp::Eq,
|
||||
expect,
|
||||
val,
|
||||
Operand::Copy(place),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -371,12 +376,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
success_block: BasicBlock,
|
||||
fail_block: BasicBlock,
|
||||
source_info: SourceInfo,
|
||||
value: Const<'tcx>,
|
||||
mut val: Place<'tcx>,
|
||||
mut expect: Operand<'tcx>,
|
||||
expect_ty: Ty<'tcx>,
|
||||
mut val: Operand<'tcx>,
|
||||
mut ty: Ty<'tcx>,
|
||||
) {
|
||||
let mut expect = self.literal_operand(source_info.span, value);
|
||||
|
||||
// If we're using `b"..."` as a pattern, we need to insert an
|
||||
// unsizing coercion, as the byte string has the type `&[u8; N]`.
|
||||
//
|
||||
|
|
@ -391,7 +395,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
_ => None,
|
||||
};
|
||||
let opt_ref_ty = unsize(ty);
|
||||
let opt_ref_test_ty = unsize(value.ty());
|
||||
let opt_ref_test_ty = unsize(expect_ty);
|
||||
match (opt_ref_ty, opt_ref_test_ty) {
|
||||
// nothing to do, neither is an array
|
||||
(None, None) => {}
|
||||
|
|
@ -410,11 +414,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
PointerCoercion::Unsize,
|
||||
CoercionSource::Implicit,
|
||||
),
|
||||
Operand::Copy(val),
|
||||
val,
|
||||
ty,
|
||||
),
|
||||
);
|
||||
val = temp;
|
||||
val = Operand::Copy(temp);
|
||||
}
|
||||
if opt_ref_test_ty.is_some() {
|
||||
let slice = self.temp(ty, source_info.span);
|
||||
|
|
@ -470,11 +474,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
const_: method,
|
||||
})),
|
||||
args: [Spanned { node: Operand::Copy(val), span: DUMMY_SP }, Spanned {
|
||||
node: expect,
|
||||
span: DUMMY_SP,
|
||||
}]
|
||||
.into(),
|
||||
args: [Spanned { node: val, span: DUMMY_SP }, Spanned { node: expect, span: DUMMY_SP }]
|
||||
.into(),
|
||||
destination: eq_result,
|
||||
target: Some(eq_block),
|
||||
unwind: UnwindAction::Continue,
|
||||
|
|
|
|||
|
|
@ -332,10 +332,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
.unwrap_or_else(PatKind::Error)
|
||||
}
|
||||
|
||||
hir::PatKind::Path(ref qpath) => {
|
||||
return self.lower_path(qpath, pat.hir_id, pat.span);
|
||||
}
|
||||
|
||||
hir::PatKind::Deref(subpattern) => {
|
||||
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
|
||||
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||
|
|
|
|||
|
|
@ -1454,11 +1454,14 @@ impl<'v> RootCollector<'_, 'v> {
|
|||
self.output.push(dummy_spanned(MonoItem::Static(def_id)));
|
||||
}
|
||||
DefKind::Const => {
|
||||
// const items only generate mono items if they are
|
||||
// actually used somewhere. Just declaring them is insufficient.
|
||||
// Const items only generate mono items if they are actually used somewhere.
|
||||
// Just declaring them is insufficient.
|
||||
|
||||
// but even just declaring them must collect the items they refer to
|
||||
if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) {
|
||||
// But even just declaring them must collect the items they refer to
|
||||
// unless their generics require monomorphization.
|
||||
if !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx)
|
||||
&& let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
|
||||
{
|
||||
collect_const_value(self.tcx, val, self.output);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ use crate::solve::{
|
|||
MaybeCause, NoSolution, QueryResult,
|
||||
};
|
||||
|
||||
enum AliasBoundKind {
|
||||
SelfBounds,
|
||||
NonSelfBounds,
|
||||
}
|
||||
|
||||
/// A candidate is a possible way to prove a goal.
|
||||
///
|
||||
/// It consists of both the `source`, which describes how that goal would be proven,
|
||||
|
|
@ -510,7 +515,12 @@ where
|
|||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
|
||||
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
|
||||
ecx.assemble_alias_bound_candidates_recur(
|
||||
goal.predicate.self_ty(),
|
||||
goal,
|
||||
candidates,
|
||||
AliasBoundKind::SelfBounds,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -528,6 +538,7 @@ where
|
|||
self_ty: I::Ty,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
consider_self_bounds: AliasBoundKind,
|
||||
) {
|
||||
let (kind, alias_ty) = match self_ty.kind() {
|
||||
ty::Bool
|
||||
|
|
@ -580,16 +591,37 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
for assumption in
|
||||
self.cx().item_bounds(alias_ty.def_id).iter_instantiated(self.cx(), alias_ty.args)
|
||||
{
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
CandidateSource::AliasBound,
|
||||
goal,
|
||||
assumption,
|
||||
[],
|
||||
));
|
||||
match consider_self_bounds {
|
||||
AliasBoundKind::SelfBounds => {
|
||||
for assumption in self
|
||||
.cx()
|
||||
.item_self_bounds(alias_ty.def_id)
|
||||
.iter_instantiated(self.cx(), alias_ty.args)
|
||||
{
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
CandidateSource::AliasBound,
|
||||
goal,
|
||||
assumption,
|
||||
[],
|
||||
));
|
||||
}
|
||||
}
|
||||
AliasBoundKind::NonSelfBounds => {
|
||||
for assumption in self
|
||||
.cx()
|
||||
.item_non_self_bounds(alias_ty.def_id)
|
||||
.iter_instantiated(self.cx(), alias_ty.args)
|
||||
{
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
CandidateSource::AliasBound,
|
||||
goal,
|
||||
assumption,
|
||||
[],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
|
||||
|
|
@ -600,9 +632,12 @@ where
|
|||
|
||||
// Recurse on the self type of the projection.
|
||||
match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
|
||||
Ok(next_self_ty) => {
|
||||
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates)
|
||||
}
|
||||
Ok(next_self_ty) => self.assemble_alias_bound_candidates_recur(
|
||||
next_self_ty,
|
||||
goal,
|
||||
candidates,
|
||||
AliasBoundKind::NonSelfBounds,
|
||||
),
|
||||
Err(NoSolution) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,8 @@
|
|||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::{iter, str, string};
|
||||
|
||||
pub use Alignment::*;
|
||||
pub use Count::*;
|
||||
pub use Piece::*;
|
||||
pub use Position::*;
|
||||
use rustc_lexer::unescape;
|
||||
|
||||
|
|
@ -86,7 +83,7 @@ impl InnerOffset {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Piece<'a> {
|
||||
/// A literal string which should directly be emitted
|
||||
String(&'a str),
|
||||
Lit(&'a str),
|
||||
/// This describes that formatting should process the next argument (as
|
||||
/// specified inside) for emission.
|
||||
NextArgument(Box<Argument<'a>>),
|
||||
|
|
@ -205,11 +202,11 @@ pub enum Count<'a> {
|
|||
}
|
||||
|
||||
pub struct ParseError {
|
||||
pub description: string::String,
|
||||
pub note: Option<string::String>,
|
||||
pub label: string::String,
|
||||
pub description: String,
|
||||
pub note: Option<String>,
|
||||
pub label: String,
|
||||
pub span: InnerSpan,
|
||||
pub secondary_label: Option<(string::String, InnerSpan)>,
|
||||
pub secondary_label: Option<(String, InnerSpan)>,
|
||||
pub suggestion: Suggestion,
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +222,7 @@ pub enum Suggestion {
|
|||
/// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
|
||||
/// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
|
||||
/// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
|
||||
ReorderFormatParameter(InnerSpan, string::String),
|
||||
ReorderFormatParameter(InnerSpan, String),
|
||||
}
|
||||
|
||||
/// The parser structure for interpreting the input format string. This is
|
||||
|
|
@ -237,7 +234,7 @@ pub enum Suggestion {
|
|||
pub struct Parser<'a> {
|
||||
mode: ParseMode,
|
||||
input: &'a str,
|
||||
cur: iter::Peekable<str::CharIndices<'a>>,
|
||||
cur: std::iter::Peekable<std::str::CharIndices<'a>>,
|
||||
/// Error messages accumulated during parsing
|
||||
pub errors: Vec<ParseError>,
|
||||
/// Current position of implicit positional argument pointer
|
||||
|
|
@ -278,7 +275,7 @@ impl<'a> Iterator for Parser<'a> {
|
|||
if self.consume('{') {
|
||||
self.last_opening_brace = curr_last_brace;
|
||||
|
||||
Some(String(self.string(pos + 1)))
|
||||
Some(Piece::Lit(self.string(pos + 1)))
|
||||
} else {
|
||||
let arg = self.argument(lbrace_end);
|
||||
if let Some(rbrace_pos) = self.consume_closing_brace(&arg) {
|
||||
|
|
@ -299,13 +296,13 @@ impl<'a> Iterator for Parser<'a> {
|
|||
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
|
||||
}
|
||||
}
|
||||
Some(NextArgument(Box::new(arg)))
|
||||
Some(Piece::NextArgument(Box::new(arg)))
|
||||
}
|
||||
}
|
||||
'}' => {
|
||||
self.cur.next();
|
||||
if self.consume('}') {
|
||||
Some(String(self.string(pos + 1)))
|
||||
Some(Piece::Lit(self.string(pos + 1)))
|
||||
} else {
|
||||
let err_pos = self.to_span_index(pos);
|
||||
self.err_with_note(
|
||||
|
|
@ -317,7 +314,7 @@ impl<'a> Iterator for Parser<'a> {
|
|||
None
|
||||
}
|
||||
}
|
||||
_ => Some(String(self.string(pos))),
|
||||
_ => Some(Piece::Lit(self.string(pos))),
|
||||
}
|
||||
} else {
|
||||
if self.is_source_literal {
|
||||
|
|
@ -336,7 +333,7 @@ impl<'a> Parser<'a> {
|
|||
pub fn new(
|
||||
s: &'a str,
|
||||
style: Option<usize>,
|
||||
snippet: Option<string::String>,
|
||||
snippet: Option<String>,
|
||||
append_newline: bool,
|
||||
mode: ParseMode,
|
||||
) -> Parser<'a> {
|
||||
|
|
@ -366,7 +363,7 @@ impl<'a> Parser<'a> {
|
|||
/// Notifies of an error. The message doesn't actually need to be of type
|
||||
/// String, but I think it does when this eventually uses conditions so it
|
||||
/// might as well start using it now.
|
||||
fn err<S1: Into<string::String>, S2: Into<string::String>>(
|
||||
fn err<S1: Into<String>, S2: Into<String>>(
|
||||
&mut self,
|
||||
description: S1,
|
||||
label: S2,
|
||||
|
|
@ -385,11 +382,7 @@ impl<'a> Parser<'a> {
|
|||
/// Notifies of an error. The message doesn't actually need to be of type
|
||||
/// String, but I think it does when this eventually uses conditions so it
|
||||
/// might as well start using it now.
|
||||
fn err_with_note<
|
||||
S1: Into<string::String>,
|
||||
S2: Into<string::String>,
|
||||
S3: Into<string::String>,
|
||||
>(
|
||||
fn err_with_note<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
||||
&mut self,
|
||||
description: S1,
|
||||
label: S2,
|
||||
|
|
@ -968,7 +961,7 @@ impl<'a> Parser<'a> {
|
|||
/// in order to properly synthesise the intra-string `Span`s for error diagnostics.
|
||||
fn find_width_map_from_snippet(
|
||||
input: &str,
|
||||
snippet: Option<string::String>,
|
||||
snippet: Option<String>,
|
||||
str_style: Option<usize>,
|
||||
) -> InputStringKind {
|
||||
let snippet = match snippet {
|
||||
|
|
@ -1083,8 +1076,8 @@ fn find_width_map_from_snippet(
|
|||
InputStringKind::Literal { width_mappings }
|
||||
}
|
||||
|
||||
fn unescape_string(string: &str) -> Option<string::String> {
|
||||
let mut buf = string::String::new();
|
||||
fn unescape_string(string: &str) -> Option<String> {
|
||||
let mut buf = String::new();
|
||||
let mut ok = true;
|
||||
unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| {
|
||||
match unescaped_char {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use Piece::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[track_caller]
|
||||
|
|
@ -32,12 +34,12 @@ fn musterr(s: &str) {
|
|||
|
||||
#[test]
|
||||
fn simple() {
|
||||
same("asdf", &[String("asdf")]);
|
||||
same("a{{b", &[String("a"), String("{b")]);
|
||||
same("a}}b", &[String("a"), String("}b")]);
|
||||
same("a}}", &[String("a"), String("}")]);
|
||||
same("}}", &[String("}")]);
|
||||
same("\\}}", &[String("\\"), String("}")]);
|
||||
same("asdf", &[Lit("asdf")]);
|
||||
same("a{{b", &[Lit("a"), Lit("{b")]);
|
||||
same("a}}b", &[Lit("a"), Lit("}b")]);
|
||||
same("a}}", &[Lit("a"), Lit("}")]);
|
||||
same("}}", &[Lit("}")]);
|
||||
same("\\}}", &[Lit("\\"), Lit("}")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -370,7 +372,7 @@ fn format_flags() {
|
|||
#[test]
|
||||
fn format_mixture() {
|
||||
same("abcd {3:x} efg", &[
|
||||
String("abcd "),
|
||||
Lit("abcd "),
|
||||
NextArgument(Box::new(Argument {
|
||||
position: ArgumentIs(3),
|
||||
position_span: InnerSpan { start: 7, end: 8 },
|
||||
|
|
@ -390,7 +392,7 @@ fn format_mixture() {
|
|||
ty_span: None,
|
||||
},
|
||||
})),
|
||||
String(" efg"),
|
||||
Lit(" efg"),
|
||||
]);
|
||||
}
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -10,11 +10,10 @@ use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Node, PatKind, TyKind};
|
||||
use rustc_hir::{self as hir, Node, PatKind, TyKind};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::middle::privacy::Level;
|
||||
use rustc_middle::query::Providers;
|
||||
|
|
@ -637,10 +636,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
|||
let res = self.typeck_results().qpath_res(path, pat.hir_id);
|
||||
self.handle_field_pattern_match(pat, res, fields);
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
|
||||
self.handle_res(res);
|
||||
}
|
||||
PatKind::TupleStruct(ref qpath, fields, dotdot) => {
|
||||
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
|
||||
self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
|
||||
|
|
@ -652,6 +647,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
|||
self.in_pat = false;
|
||||
}
|
||||
|
||||
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
|
||||
match &expr.kind {
|
||||
rustc_hir::PatExprKind::Path(qpath) => {
|
||||
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
|
||||
self.handle_res(res);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
intravisit::walk_pat_expr(self, expr);
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
|
||||
self.handle_res(path.res);
|
||||
intravisit::walk_path(self, path);
|
||||
|
|
|
|||
|
|
@ -298,7 +298,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
TupleStruct,
|
||||
Or,
|
||||
Never,
|
||||
Path,
|
||||
Tuple,
|
||||
Box,
|
||||
Deref,
|
||||
|
|
|
|||
|
|
@ -170,9 +170,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
|
|||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
match fn_kind {
|
||||
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body)
|
||||
if let Some(coroutine_kind) = header.coroutine_kind =>
|
||||
{
|
||||
FnKind::Fn(
|
||||
_ctxt,
|
||||
_ident,
|
||||
_vis,
|
||||
Fn { sig: FnSig { header, decl, span: _ }, generics, body, .. },
|
||||
) if let Some(coroutine_kind) = header.coroutine_kind => {
|
||||
self.visit_fn_header(header);
|
||||
self.visit_generics(generics);
|
||||
|
||||
|
|
|
|||
|
|
@ -986,8 +986,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
match fn_kind {
|
||||
// Bail if the function is foreign, and thus cannot validly have
|
||||
// a body, or if there's no body for some other reason.
|
||||
FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
|
||||
| FnKind::Fn(_, _, sig, _, generics, None) => {
|
||||
FnKind::Fn(FnCtxt::Foreign, _, _, Fn { sig, generics, .. })
|
||||
| FnKind::Fn(_, _, _, Fn { sig, generics, body: None, .. }) => {
|
||||
self.visit_fn_header(&sig.header);
|
||||
self.visit_generics(generics);
|
||||
self.with_lifetime_rib(
|
||||
|
|
@ -1019,7 +1019,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
// Create a label rib for the function.
|
||||
this.with_label_rib(RibKind::FnOrCoroutine, |this| {
|
||||
match fn_kind {
|
||||
FnKind::Fn(_, _, sig, _, generics, body) => {
|
||||
FnKind::Fn(_, _, _, Fn { sig, generics, body, .. }) => {
|
||||
this.visit_generics(generics);
|
||||
|
||||
let declaration = &sig.decl;
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
let suggestion = if self.current_trait_ref.is_none()
|
||||
&& let Some((fn_kind, _)) = self.diag_metadata.current_function
|
||||
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
|
||||
&& let FnKind::Fn(_, _, sig, ..) = fn_kind
|
||||
&& let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = fn_kind
|
||||
&& let Some(items) = self.diag_metadata.current_impl_items
|
||||
&& let Some(item) = items.iter().find(|i| {
|
||||
i.ident.name == item_str.name
|
||||
|
|
@ -560,7 +560,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if !self.self_value_is_available(path[0].ident.span) {
|
||||
if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
|
||||
if let Some((FnKind::Fn(_, _, _, ast::Fn { sig, .. }), fn_span)) =
|
||||
&self.diag_metadata.current_function
|
||||
{
|
||||
let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
|
||||
|
|
@ -3249,7 +3249,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
{
|
||||
let pre = if lt.kind == MissingLifetimeKind::Ampersand
|
||||
&& let Some((kind, _span)) = self.diag_metadata.current_function
|
||||
&& let FnKind::Fn(_, _, sig, _, _, _) = kind
|
||||
&& let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
|
||||
&& !sig.decl.inputs.is_empty()
|
||||
&& let sugg = sig
|
||||
.decl
|
||||
|
|
@ -3290,7 +3290,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
} else if (lt.kind == MissingLifetimeKind::Ampersand
|
||||
|| lt.kind == MissingLifetimeKind::Underscore)
|
||||
&& let Some((kind, _span)) = self.diag_metadata.current_function
|
||||
&& let FnKind::Fn(_, _, sig, _, _, _) = kind
|
||||
&& let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
|
||||
&& let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
|
||||
&& !sig.decl.inputs.is_empty()
|
||||
&& let arg_refs = sig
|
||||
|
|
@ -3350,7 +3350,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
|
||||
let mut sugg = vec![(lt.span, String::new())];
|
||||
if let Some((kind, _span)) = self.diag_metadata.current_function
|
||||
&& let FnKind::Fn(_, _, sig, _, _, _) = kind
|
||||
&& let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
|
||||
&& let ast::FnRetTy::Ty(ty) = &sig.decl.output
|
||||
{
|
||||
let mut lt_finder =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_abi::{Align, Size};
|
||||
use rustc_middle::mir::ConstValue;
|
||||
use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range};
|
||||
use rustc_middle::mir::interpret::{AllocInit, AllocRange, Pointer, alloc_range};
|
||||
use stable_mir::Error;
|
||||
use stable_mir::mir::Mutability;
|
||||
use stable_mir::ty::{Allocation, ProvenanceMap};
|
||||
|
|
@ -44,7 +44,8 @@ pub(crate) fn try_new_allocation<'tcx>(
|
|||
.layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
|
||||
.map_err(|e| e.stable(tables))?
|
||||
.align;
|
||||
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
|
||||
let mut allocation =
|
||||
rustc_middle::mir::interpret::Allocation::new(size, align.abi, AllocInit::Uninit);
|
||||
allocation
|
||||
.write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
|
||||
.map_err(|e| e.stable(tables))?;
|
||||
|
|
@ -68,8 +69,11 @@ pub(crate) fn try_new_allocation<'tcx>(
|
|||
.tcx
|
||||
.layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
|
||||
.map_err(|e| e.stable(tables))?;
|
||||
let mut allocation =
|
||||
rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
|
||||
let mut allocation = rustc_middle::mir::interpret::Allocation::new(
|
||||
layout.size,
|
||||
layout.align.abi,
|
||||
AllocInit::Uninit,
|
||||
);
|
||||
allocation
|
||||
.write_scalar(
|
||||
&tables.tcx,
|
||||
|
|
|
|||
|
|
@ -108,21 +108,19 @@ impl Stability {
|
|||
// per-function level, since we would then allow safe calls from functions with `+soft-float` to
|
||||
// functions without that feature!
|
||||
//
|
||||
// It is important for soundness that features allowed here do *not* change the function call ABI.
|
||||
// For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
|
||||
// arguments, so enabling toggling that feature would be unsound. In fact, since `-Ctarget-feature`
|
||||
// will just allow unknown features (with a warning), we have to explicitly list features that change
|
||||
// the ABI as `Forbidden` to ensure using them causes an error. Note that this is only effective if
|
||||
// such features can never be toggled via `-Ctarget-cpu`! If that is ever a possibility, we will need
|
||||
// extra checks ensuring that the LLVM-computed target features for a CPU did not (un)set a
|
||||
// `Forbidden` feature. See https://github.com/rust-lang/rust/issues/116344 for some more context.
|
||||
// FIXME: add such "forbidden" features for non-x86 targets.
|
||||
// It is important for soundness to consider the interaction of targets features and the function
|
||||
// call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
|
||||
// arguments, so letting people toggle that feature would be unsound. To this end, the
|
||||
// `abi_required_features` function computes which target features must and must not be enabled for
|
||||
// any given target, and individual features can also be marked as `Forbidden`.
|
||||
// See https://github.com/rust-lang/rust/issues/116344 for some more context.
|
||||
//
|
||||
// The one exception to features that change the ABI is features that enable larger vector
|
||||
// registers. Those are permitted to be listed here. This is currently unsound (see
|
||||
// https://github.com/rust-lang/rust/issues/116558); in the future we will have to ensure that
|
||||
// functions can only use such vectors as arguments/return types if the corresponding target feature
|
||||
// is enabled.
|
||||
// registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store
|
||||
// information about which target feature is ABI-required for which vector size; this is used to
|
||||
// ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For
|
||||
// the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.)
|
||||
// Also see https://github.com/rust-lang/rust/issues/116558.
|
||||
//
|
||||
// Stabilizing a target feature requires t-lang approval.
|
||||
|
||||
|
|
@ -137,6 +135,11 @@ const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
|||
// tidy-alphabetical-start
|
||||
("aclass", Unstable(sym::arm_target_feature), &[]),
|
||||
("aes", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
(
|
||||
"atomics-32",
|
||||
Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
|
||||
&[],
|
||||
),
|
||||
("crc", Unstable(sym::arm_target_feature), &[]),
|
||||
("d32", Unstable(sym::arm_target_feature), &[]),
|
||||
("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
|
|
|
|||
|
|
@ -165,6 +165,8 @@ trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime r
|
|||
|
||||
trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
|
||||
|
||||
trait_selection_fn_consider_casting_both = consider casting both fn items to fn pointers using `as {$sig}`
|
||||
|
||||
trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same
|
||||
trait_selection_fps_cast = consider casting to a fn pointer
|
||||
trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
|
||||
self.tcx
|
||||
.explicit_item_super_predicates(def_id)
|
||||
.explicit_item_self_bounds(def_id)
|
||||
.iter_instantiated_copied(self.tcx, args)
|
||||
.find_map(|(predicate, _)| {
|
||||
predicate
|
||||
|
|
@ -1844,7 +1844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
self.suggest_tuple_pattern(cause, &exp_found, diag);
|
||||
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
|
||||
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
|
||||
self.suggest_function_pointers(cause, span, &exp_found, diag);
|
||||
self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
|
||||
self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ impl<T> Trait<T> for X {
|
|||
(ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
|
||||
if let Some(def_id) = t.principal_def_id()
|
||||
&& tcx
|
||||
.explicit_item_super_predicates(alias.def_id)
|
||||
.explicit_item_self_bounds(alias.def_id)
|
||||
.skip_binder()
|
||||
.iter()
|
||||
.any(|(pred, _span)| match pred.kind().skip_binder() {
|
||||
|
|
@ -422,7 +422,7 @@ impl<T> Trait<T> for X {
|
|||
ty::Alias(..) => values.expected,
|
||||
_ => values.found,
|
||||
};
|
||||
let preds = tcx.explicit_item_super_predicates(opaque_ty.def_id);
|
||||
let preds = tcx.explicit_item_self_bounds(opaque_ty.def_id);
|
||||
for (pred, _span) in preds.skip_binder() {
|
||||
let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder()
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use rustc_middle::traits::{
|
|||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||
StatementAsExpression,
|
||||
};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
|
||||
use rustc_span::{Span, sym};
|
||||
|
|
@ -20,7 +21,7 @@ use tracing::debug;
|
|||
use crate::error_reporting::TypeErrCtxt;
|
||||
use crate::error_reporting::infer::hir::Path;
|
||||
use crate::errors::{
|
||||
ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
|
||||
ConsiderAddingAwait, FnConsiderCasting, FnConsiderCastingBoth, FnItemsAreDistinct, FnUniqTypes,
|
||||
FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
|
||||
SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
|
||||
};
|
||||
|
|
@ -381,14 +382,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn suggest_function_pointers(
|
||||
pub fn suggest_function_pointers_impl(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
span: Span,
|
||||
span: Option<Span>,
|
||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||
diag: &mut Diag<'_>,
|
||||
) {
|
||||
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
|
||||
let ty::error::ExpectedFound { expected, found } = exp_found;
|
||||
let expected_inner = expected.peel_refs();
|
||||
let found_inner = found.peel_refs();
|
||||
|
|
@ -411,6 +410,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(span) = span else {
|
||||
let casting = format!("{fn_name} as {sig}");
|
||||
diag.subdiagnostic(FnItemsAreDistinct);
|
||||
diag.subdiagnostic(FnConsiderCasting { casting });
|
||||
return;
|
||||
};
|
||||
|
||||
let sugg = match (expected.is_ref(), found.is_ref()) {
|
||||
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
|
||||
(false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
|
||||
|
|
@ -445,6 +451,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let fn_name = self.tcx.def_path_str_with_args(*did2, args2);
|
||||
|
||||
let Some(span) = span else {
|
||||
diag.subdiagnostic(FnConsiderCastingBoth { sig: *expected_sig });
|
||||
return;
|
||||
};
|
||||
|
||||
let sug = if found.is_ref() {
|
||||
FunctionPointerSuggestion::CastBothRef {
|
||||
span,
|
||||
|
|
@ -488,6 +500,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
};
|
||||
}
|
||||
|
||||
pub(super) fn suggest_function_pointers(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
span: Span,
|
||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||
terr: TypeError<'tcx>,
|
||||
diag: &mut Diag<'_>,
|
||||
) {
|
||||
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
|
||||
|
||||
if exp_found.expected.peel_refs().is_fn() && exp_found.found.peel_refs().is_fn() {
|
||||
self.suggest_function_pointers_impl(Some(span), exp_found, diag);
|
||||
} else if let TypeError::Sorts(exp_found) = terr {
|
||||
self.suggest_function_pointers_impl(None, &exp_found, diag);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_suggest_as_ref_kind(
|
||||
&self,
|
||||
expected: Ty<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1969,6 +1969,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
StringPart::highlighted(exp_found.found.to_string()),
|
||||
StringPart::normal("`"),
|
||||
]);
|
||||
self.suggest_function_pointers_impl(None, &exp_found, err);
|
||||
}
|
||||
|
||||
true
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ impl<'tcx> OnUnimplementedFormatString {
|
|||
let mut result = Ok(());
|
||||
for token in &mut parser {
|
||||
match token {
|
||||
Piece::String(_) => (), // Normal string, no need to check it
|
||||
Piece::Lit(_) => (), // Normal string, no need to check it
|
||||
Piece::NextArgument(a) => {
|
||||
let format_spec = a.format;
|
||||
if self.is_diagnostic_namespace_variant
|
||||
|
|
@ -950,7 +950,7 @@ impl<'tcx> OnUnimplementedFormatString {
|
|||
let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
|
||||
let constructed_message = (&mut parser)
|
||||
.map(|p| match p {
|
||||
Piece::String(s) => s.to_owned(),
|
||||
Piece::Lit(s) => s.to_owned(),
|
||||
Piece::NextArgument(a) => match a.position {
|
||||
Position::ArgumentNamed(arg) => {
|
||||
let s = Symbol::intern(arg);
|
||||
|
|
|
|||
|
|
@ -1087,28 +1087,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),
|
||||
))
|
||||
}
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
||||
.tcx
|
||||
.item_super_predicates(def_id)
|
||||
.instantiate(self.tcx, args)
|
||||
.iter()
|
||||
.find_map(|pred| {
|
||||
if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
||||
self.tcx.item_self_bounds(def_id).instantiate(self.tcx, args).iter().find_map(
|
||||
|pred| {
|
||||
if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
|
||||
&& self
|
||||
.tcx
|
||||
.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
|
||||
// args tuple will always be args[1]
|
||||
&& let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::DefId(def_id),
|
||||
pred.kind().rebind(proj.term.expect_type()),
|
||||
pred.kind().rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::DefId(def_id),
|
||||
pred.kind().rebind(proj.term.expect_type()),
|
||||
pred.kind().rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
|
||||
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
||||
&& self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
|
||||
|
|
@ -2770,6 +2769,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
ObligationCauseCode::SliceOrArrayElem => {
|
||||
err.note("slice and array elements must have `Sized` type");
|
||||
}
|
||||
ObligationCauseCode::ArrayLen(array_ty) => {
|
||||
err.note(format!("the length of array `{array_ty}` must be type `usize`"));
|
||||
}
|
||||
ObligationCauseCode::TupleElem => {
|
||||
err.note("only the last element of a tuple may have a dynamically sized type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1496,6 +1496,12 @@ pub struct FnConsiderCasting {
|
|||
pub casting: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(trait_selection_fn_consider_casting_both)]
|
||||
pub struct FnConsiderCastingBoth<'a> {
|
||||
pub sig: Binder<'a, FnSig<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestAccessingField<'a> {
|
||||
#[suggestion(
|
||||
|
|
|
|||
|
|
@ -1620,9 +1620,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// projections, we will never be able to equate, e.g. `<T as Tr>::A`
|
||||
// with `<<T as Tr>::A as Tr>::A`.
|
||||
let relevant_bounds = if in_parent_alias_type {
|
||||
self.tcx().item_non_self_assumptions(alias_ty.def_id)
|
||||
self.tcx().item_non_self_bounds(alias_ty.def_id)
|
||||
} else {
|
||||
self.tcx().item_super_predicates(alias_ty.def_id)
|
||||
self.tcx().item_self_bounds(alias_ty.def_id)
|
||||
};
|
||||
|
||||
for bound in relevant_bounds.instantiate(self.tcx(), alias_ty.args) {
|
||||
|
|
|
|||
|
|
@ -689,7 +689,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
|
||||
// Note that the len being WF is implicitly checked while visiting.
|
||||
// Here we just check that it's of type usize.
|
||||
let cause = self.cause(ObligationCauseCode::Misc);
|
||||
let cause = self.cause(ObligationCauseCode::ArrayLen(t));
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
tcx,
|
||||
cause,
|
||||
|
|
|
|||
|
|
@ -203,6 +203,16 @@ pub trait Interner:
|
|||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn item_self_bounds(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn item_non_self_bounds(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn predicates_of(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
|
|
|
|||
|
|
@ -313,6 +313,17 @@ pub macro cfg_match {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If desired, it is possible to return expressions through the use of surrounding braces:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cfg_match)]
|
||||
///
|
||||
/// let _some_string = cfg_match! {{
|
||||
/// unix => { "With great power comes great electricity bills" }
|
||||
/// _ => { "Behind every successful diet is an unwatched pizza" }
|
||||
/// }};
|
||||
/// ```
|
||||
#[cfg(not(bootstrap))]
|
||||
#[unstable(feature = "cfg_match", issue = "115585")]
|
||||
#[rustc_diagnostic_item = "cfg_match"]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::io::{Read, Write, pipe};
|
||||
|
||||
#[test]
|
||||
#[cfg(all(windows, unix, not(miri)))]
|
||||
#[cfg(all(any(unix, windows), not(miri)))]
|
||||
fn pipe_creation_clone_and_rw() {
|
||||
let (rx, tx) = pipe().unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ mod uefi_command_internal {
|
|||
helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
|
||||
|
||||
let len = args.len();
|
||||
let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
|
||||
let args_size: u32 = (len * crate::mem::size_of::<u16>()).try_into().unwrap();
|
||||
let ptr = Box::into_raw(args).as_mut_ptr();
|
||||
|
||||
unsafe {
|
||||
|
|
@ -706,9 +706,10 @@ mod uefi_command_internal {
|
|||
res.push(QUOTE);
|
||||
res.extend(prog.encode_wide());
|
||||
res.push(QUOTE);
|
||||
res.push(SPACE);
|
||||
|
||||
for arg in args {
|
||||
res.push(SPACE);
|
||||
|
||||
// Wrap the argument in quotes to be treat as single arg
|
||||
res.push(QUOTE);
|
||||
for c in arg.encode_wide() {
|
||||
|
|
@ -719,8 +720,6 @@ mod uefi_command_internal {
|
|||
res.push(c);
|
||||
}
|
||||
res.push(QUOTE);
|
||||
|
||||
res.push(SPACE);
|
||||
}
|
||||
|
||||
res.into_boxed_slice()
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ ENV PATH="/node/bin:${PATH}"
|
|||
|
||||
# Install es-check
|
||||
# Pin its version to prevent unrelated CI failures due to future es-check versions.
|
||||
RUN npm install es-check@6.1.1 eslint@8.6.0 -g
|
||||
RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
|
@ -68,4 +68,5 @@ ENV SCRIPT \
|
|||
es-check es2019 ../src/librustdoc/html/static/js/*.js && \
|
||||
eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \
|
||||
eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js && \
|
||||
eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js
|
||||
eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js && \
|
||||
tsc --project ../src/librustdoc/html/static/js/tsconfig.json
|
||||
|
|
|
|||
|
|
@ -43,10 +43,6 @@ runners:
|
|||
os: windows-2022-8core-32gb
|
||||
<<: *base-job
|
||||
|
||||
- &job-windows-16c
|
||||
os: windows-2022-16core-64gb
|
||||
<<: *base-job
|
||||
|
||||
- &job-aarch64-linux
|
||||
# Free some disk space to avoid running out of space during the build.
|
||||
free_disk: true
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 82a4a49789bc96db1a1b2a210b4c5ed7c9ef0c0d
|
||||
Subproject commit fa312a343fbff01bc6cef393e326817f70719813
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit d56e0f3a0656b7702ca466d4b191e16c28262b82
|
||||
Subproject commit 4ed5a1a4a2a7ecc2e529a5baaef04f7bc7917eda
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 625b200e5b33a5af35589db0bc454203a3d46d20
|
||||
Subproject commit bc2298865544695c63454fc1f9f98a3dc22e9948
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 293af991003772bdccf2d6b980182d84dd055942
|
||||
Subproject commit 93b921c7d3213d38d920f7f905a3bec093d2217d
|
||||
|
|
@ -58,7 +58,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
|
|||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &Compiler,
|
||||
krate: &rustc_ast::Crate,
|
||||
krate: &mut rustc_ast::Crate,
|
||||
) -> Compilation {
|
||||
for item in &krate.items {
|
||||
println!("{}", item_to_string(&item));
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
|
|||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &Compiler,
|
||||
krate: &rustc_ast::Crate,
|
||||
krate: &mut rustc_ast::Crate,
|
||||
) -> Compilation {
|
||||
for item in &krate.items {
|
||||
println!("{}", item_to_string(&item));
|
||||
|
|
|
|||
|
|
@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
|||
return kw::Underscore;
|
||||
}
|
||||
PatKind::Binding(_, _, ident, _) => return ident.name,
|
||||
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
|
||||
PatKind::TupleStruct(ref p, ..)
|
||||
| PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p),
|
||||
PatKind::Or(pats) => {
|
||||
pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath};
|
||||
use rustc_hir::{
|
||||
ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
|
||||
};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
|
|
@ -191,17 +193,21 @@ impl SpanMapVisitor<'_> {
|
|||
}
|
||||
|
||||
fn handle_pat(&mut self, p: &Pat<'_>) {
|
||||
let mut check_qpath = |qpath, hir_id| match qpath {
|
||||
QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
|
||||
self.infer_id(path.hir_id, Some(hir_id), qpath.span());
|
||||
}
|
||||
QPath::Resolved(_, path) => self.handle_path(path),
|
||||
_ => {}
|
||||
};
|
||||
match p.kind {
|
||||
PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
|
||||
PatKind::Struct(qpath, _, _)
|
||||
| PatKind::TupleStruct(qpath, _, _)
|
||||
| PatKind::Path(qpath) => match qpath {
|
||||
QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
|
||||
self.infer_id(path.hir_id, Some(p.hir_id), qpath.span());
|
||||
}
|
||||
QPath::Resolved(_, path) => self.handle_path(path),
|
||||
_ => {}
|
||||
},
|
||||
PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
|
||||
check_qpath(qpath, p.hir_id)
|
||||
}
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
|
||||
check_qpath(*qpath, *hir_id)
|
||||
}
|
||||
PatKind::Or(pats) => {
|
||||
for pat in pats {
|
||||
self.handle_pat(pat);
|
||||
|
|
|
|||
|
|
@ -3,13 +3,9 @@
|
|||
These JavaScript files are incorporated into the rustdoc binary at build time,
|
||||
and are minified and written to the filesystem as part of the doc build process.
|
||||
|
||||
We use the [Closure Compiler](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler)
|
||||
We use the [TypeScript Compiler](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
|
||||
dialect of JSDoc to comment our code and annotate params and return types.
|
||||
To run a check:
|
||||
|
||||
./x.py doc library/std
|
||||
npm i -g google-closure-compiler
|
||||
google-closure-compiler -W VERBOSE \
|
||||
build/<YOUR PLATFORM>/doc/{search-index*.js,crates*.js} \
|
||||
src/librustdoc/html/static/js/{search.js,main.js,storage.js} \
|
||||
--externs src/librustdoc/html/static/js/externs.js >/dev/null
|
||||
npm i -g typescript
|
||||
tsc --project tsconfig.json
|
||||
|
|
|
|||
|
|
@ -1,270 +0,0 @@
|
|||
// This file contains type definitions that are processed by the Closure Compiler but are
|
||||
// not put into the JavaScript we include as part of the documentation. It is used for
|
||||
// type checking. See README.md in this directory for more info.
|
||||
|
||||
/* eslint-disable */
|
||||
let searchState;
|
||||
function initSearch(searchIndex){}
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* name: string,
|
||||
* id: number|null,
|
||||
* fullPath: Array<string>,
|
||||
* pathWithoutLast: Array<string>,
|
||||
* pathLast: string,
|
||||
* generics: Array<QueryElement>,
|
||||
* bindings: Map<number, Array<QueryElement>>,
|
||||
* }}
|
||||
*/
|
||||
let QueryElement;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* pos: number,
|
||||
* totalElems: number,
|
||||
* typeFilter: (null|string),
|
||||
* userQuery: string,
|
||||
* isInBinding: (null|string),
|
||||
* }}
|
||||
*/
|
||||
let ParserState;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* original: string,
|
||||
* userQuery: string,
|
||||
* typeFilter: number,
|
||||
* elems: Array<QueryElement>,
|
||||
* args: Array<QueryElement>,
|
||||
* returned: Array<QueryElement>,
|
||||
* foundElems: number,
|
||||
* totalElems: number,
|
||||
* literalSearch: boolean,
|
||||
* hasReturnArrow: boolean,
|
||||
* corrections: Array<{from: string, to: integer}> | null,
|
||||
* typeFingerprint: Uint32Array,
|
||||
* error: Array<string> | null,
|
||||
* }}
|
||||
*/
|
||||
let ParsedQuery;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* crate: string,
|
||||
* desc: string,
|
||||
* id: number,
|
||||
* name: string,
|
||||
* normalizedName: string,
|
||||
* parent: (Object|null|undefined),
|
||||
* path: string,
|
||||
* ty: (Number|null|number),
|
||||
* type: FunctionSearchType?
|
||||
* }}
|
||||
*/
|
||||
let Row;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* in_args: Array<Object>,
|
||||
* returned: Array<Object>,
|
||||
* others: Array<Object>,
|
||||
* query: ParsedQuery,
|
||||
* }}
|
||||
*/
|
||||
let ResultsTable;
|
||||
|
||||
/**
|
||||
* @typedef {Map<String, ResultObject>}
|
||||
*/
|
||||
let Results;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* desc: string,
|
||||
* displayPath: string,
|
||||
* fullPath: string,
|
||||
* href: string,
|
||||
* id: number,
|
||||
* lev: number,
|
||||
* name: string,
|
||||
* normalizedName: string,
|
||||
* parent: (Object|undefined),
|
||||
* path: string,
|
||||
* ty: number,
|
||||
* type: FunctionSearchType?,
|
||||
* displayType: Promise<Array<Array<string>>>|null,
|
||||
* displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
|
||||
* }}
|
||||
*/
|
||||
let ResultObject;
|
||||
|
||||
/**
|
||||
* A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
|
||||
* The JavaScript deserializes this into FunctionSearchType.
|
||||
*
|
||||
* Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
|
||||
* because `null` is four bytes while `0` is one byte.
|
||||
*
|
||||
* An input or output can be encoded as just a number if there is only one of them, AND
|
||||
* it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
|
||||
* a function with a single output, and that output had a single generic:
|
||||
*
|
||||
* fn something() -> Result<usize, usize>
|
||||
*
|
||||
* If output was allowed to be any RawFunctionType, it would look like thi
|
||||
*
|
||||
* [[], [50, [3, 3]]]
|
||||
*
|
||||
* The problem is that the above output could be interpreted as either a type with ID 50 and two
|
||||
* generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
|
||||
* with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
|
||||
* in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
|
||||
* is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
|
||||
*
|
||||
* The output can be skipped if it's actually unit and there's no type constraints. If thi
|
||||
* function accepts constrained generics, then the output will be unconditionally emitted, and
|
||||
* after it will come a list of trait constraints. The position of the item in the list will
|
||||
* determine which type parameter it is. For example:
|
||||
*
|
||||
* [1, 2, 3, 4, 5]
|
||||
* ^ ^ ^ ^ ^
|
||||
* | | | | - generic parameter (-3) of trait 5
|
||||
* | | | - generic parameter (-2) of trait 4
|
||||
* | | - generic parameter (-1) of trait 3
|
||||
* | - this function returns a single value (type 2)
|
||||
* - this function takes a single input parameter (type 1)
|
||||
*
|
||||
* Or, for a less contrived version:
|
||||
*
|
||||
* [[[4, -1], 3], [[5, -1]], 11]
|
||||
* -^^^^^^^---- ^^^^^^^ ^^
|
||||
* | | | - generic parameter, roughly `where -1: 11`
|
||||
* | | | since -1 is the type parameter and 11 the trait
|
||||
* | | - function output 5<-1>
|
||||
* | - the overall function signature is something like
|
||||
* | `fn(4<-1>, 3) -> 5<-1> where -1: 11`
|
||||
* - function input, corresponds roughly to 4<-1>
|
||||
* 4 is an index into the `p` array for a type
|
||||
* -1 is the generic parameter, given by 11
|
||||
*
|
||||
* If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
|
||||
* function inputs and outputs:
|
||||
*
|
||||
* [-1, -1, [4, 3]]
|
||||
* ^^^^^^ where -1: 4 + 3
|
||||
*
|
||||
* If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
|
||||
* even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
|
||||
* favor of `4 + 3`:
|
||||
*
|
||||
* [-1, -1, [[4, 3]]]
|
||||
* ^^^^^^^^ where -1: 4 + 3
|
||||
*
|
||||
* [-1, -1, [5, [4, 3]]]
|
||||
* ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
|
||||
*
|
||||
* If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
|
||||
* implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
|
||||
*
|
||||
* @typedef {(
|
||||
* 0 |
|
||||
* [(number|Array<RawFunctionType>)] |
|
||||
* [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
|
||||
* Array<(number|Array<RawFunctionType>)>
|
||||
* )}
|
||||
*/
|
||||
let RawFunctionSearchType;
|
||||
|
||||
/**
|
||||
* A single function input or output type. This is either a single path ID, or a pair of
|
||||
* [path ID, generics].
|
||||
*
|
||||
* Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
|
||||
* because `null` is four bytes while `0` is one byte.
|
||||
*
|
||||
* @typedef {number | [number, Array<RawFunctionType>]}
|
||||
*/
|
||||
let RawFunctionType;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* inputs: Array<FunctionType>,
|
||||
* output: Array<FunctionType>,
|
||||
* where_clause: Array<Array<FunctionType>>,
|
||||
* }}
|
||||
*/
|
||||
let FunctionSearchType;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* id: (null|number),
|
||||
* ty: number,
|
||||
* generics: Array<FunctionType>,
|
||||
* bindings: Map<integer, Array<FunctionType>>,
|
||||
* }}
|
||||
*/
|
||||
let FunctionType;
|
||||
|
||||
/**
|
||||
* The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
|
||||
* are arrays with the same length. `q`, `a`, and `c` use a sparse
|
||||
* representation for compactness.
|
||||
*
|
||||
* `n[i]` contains the name of an item.
|
||||
*
|
||||
* `t[i]` contains the type of that item
|
||||
* (as a string of characters that represent an offset in `itemTypes`).
|
||||
*
|
||||
* `d[i]` contains the description of that item.
|
||||
*
|
||||
* `q` contains the full paths of the items. For compactness, it is a set of
|
||||
* (index, path) pairs used to create a map. If a given index `i` is
|
||||
* not present, this indicates "same as the last index present".
|
||||
*
|
||||
* `i[i]` contains an item's parent, usually a module. For compactness,
|
||||
* it is a set of indexes into the `p` array.
|
||||
*
|
||||
* `f` contains function signatures, or `0` if the item isn't a function.
|
||||
* More information on how they're encoded can be found in rustc-dev-guide
|
||||
*
|
||||
* Functions are themselves encoded as arrays. The first item is a list of
|
||||
* types representing the function's inputs, and the second list item is a list
|
||||
* of types representing the function's output. Tuples are flattened.
|
||||
* Types are also represented as arrays; the first item is an index into the `p`
|
||||
* array, while the second is a list of types representing any generic parameters.
|
||||
*
|
||||
* b[i] contains an item's impl disambiguator. This is only present if an item
|
||||
* is defined in an impl block and, the impl block's type has more than one associated
|
||||
* item with the same name.
|
||||
*
|
||||
* `a` defines aliases with an Array of pairs: [name, offset], where `offset`
|
||||
* points into the n/t/d/q/i/f arrays.
|
||||
*
|
||||
* `doc` contains the description of the crate.
|
||||
*
|
||||
* `p` is a list of path/type pairs. It is used for parents and function parameters.
|
||||
* The first item is the type, the second is the name, the third is the visible path (if any) and
|
||||
* the fourth is the canonical path used for deduplication (if any).
|
||||
*
|
||||
* `r` is the canonical path used for deduplication of re-exported items.
|
||||
* It is not used for associated items like methods (that's the fourth element
|
||||
* of `p`) but is used for modules items like free functions.
|
||||
*
|
||||
* `c` is an array of item indices that are deprecated.
|
||||
* @typedef {{
|
||||
* doc: string,
|
||||
* a: Object,
|
||||
* n: Array<string>,
|
||||
* t: string,
|
||||
* d: Array<string>,
|
||||
* q: Array<[number, string]>,
|
||||
* i: Array<number>,
|
||||
* f: string,
|
||||
* p: Array<[number, string] | [number, string, number] | [number, string, number, number]>,
|
||||
* b: Array<[number, String]>,
|
||||
* c: Array<number>,
|
||||
* r: Array<[number, number]>,
|
||||
* }}
|
||||
*/
|
||||
let RawSearchIndexCrate;
|
||||
File diff suppressed because it is too large
Load diff
387
src/librustdoc/html/static/js/rustdoc.d.ts
vendored
Normal file
387
src/librustdoc/html/static/js/rustdoc.d.ts
vendored
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
// This file contains type definitions that are processed by the TypeScript Compiler but are
|
||||
// not put into the JavaScript we include as part of the documentation. It is used for
|
||||
// type checking. See README.md in this directory for more info.
|
||||
|
||||
/* eslint-disable */
|
||||
declare global {
|
||||
interface Window {
|
||||
/** Make the current theme easy to find */
|
||||
currentTheme: HTMLLinkElement|null;
|
||||
/** Used by the popover tooltip code. */
|
||||
RUSTDOC_TOOLTIP_HOVER_MS: number;
|
||||
/** Used by the popover tooltip code. */
|
||||
RUSTDOC_TOOLTIP_HOVER_EXIT_MS: number;
|
||||
/** Search engine data used by main.js and search.js */
|
||||
searchState: rustdoc.SearchState;
|
||||
/** Global option, with a long list of "../"'s */
|
||||
rootPath: string|null;
|
||||
/**
|
||||
* Currently opened crate.
|
||||
* As a multi-page application, we know this never changes once set.
|
||||
*/
|
||||
currentCrate: string|null;
|
||||
}
|
||||
interface HTMLElement {
|
||||
/** Used by the popover tooltip code. */
|
||||
TOOLTIP_FORCE_VISIBLE: boolean|undefined,
|
||||
/** Used by the popover tooltip code */
|
||||
TOOLTIP_HOVER_TIMEOUT: Timeout|undefined,
|
||||
}
|
||||
}
|
||||
|
||||
export = rustdoc;
|
||||
|
||||
declare namespace rustdoc {
|
||||
interface SearchState {
|
||||
rustdocToolbar: HTMLElement|null;
|
||||
loadingText: string;
|
||||
input: HTMLInputElement|null;
|
||||
title: string;
|
||||
titleBeforeSearch: string;
|
||||
timeout: number|null;
|
||||
currentTab: number;
|
||||
focusedByTab: [number|null, number|null, number|null];
|
||||
clearInputTimeout: function;
|
||||
outputElement: function(): HTMLElement|null;
|
||||
focus: function();
|
||||
defocus: function();
|
||||
showResults: function(HTMLElement|null|undefined);
|
||||
removeQueryParameters: function();
|
||||
hideResults: function();
|
||||
getQueryStringParams: function(): Object.<any, string>;
|
||||
origPlaceholder: string;
|
||||
setup: function();
|
||||
setLoadingSearch: function();
|
||||
descShards: Map<string, SearchDescShard[]>;
|
||||
loadDesc: function({descShard: SearchDescShard, descIndex: number}): Promise<string|null>;
|
||||
loadedDescShard: function(string, number, string);
|
||||
isDisplayed: function(): boolean,
|
||||
}
|
||||
|
||||
interface SearchDescShard {
|
||||
crate: string;
|
||||
promise: Promise<string[]>|null;
|
||||
resolve: function(string[])|null;
|
||||
shard: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single parsed "atom" in a search query. For example,
|
||||
*
|
||||
* std::fmt::Formatter, Write -> Result<()>
|
||||
* ┏━━━━━━━━━━━━━━━━━━ ┌──── ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
|
||||
* ┃ │ ┗ QueryElement { ┊
|
||||
* ┃ │ name: Result ┊
|
||||
* ┃ │ generics: [ ┊
|
||||
* ┃ │ QueryElement ┘
|
||||
* ┃ │ name: ()
|
||||
* ┃ │ ]
|
||||
* ┃ │ }
|
||||
* ┃ └ QueryElement {
|
||||
* ┃ name: Write
|
||||
* ┃ }
|
||||
* ┗ QueryElement {
|
||||
* name: Formatter
|
||||
* pathWithoutLast: std::fmt
|
||||
* }
|
||||
*/
|
||||
interface QueryElement {
|
||||
name: string,
|
||||
id: number|null,
|
||||
fullPath: Array<string>,
|
||||
pathWithoutLast: Array<string>,
|
||||
pathLast: string,
|
||||
normalizedPathLast: string,
|
||||
generics: Array<QueryElement>,
|
||||
bindings: Map<number, Array<QueryElement>>,
|
||||
typeFilter: number|null,
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as QueryElement, but bindings and typeFilter support strings
|
||||
*/
|
||||
interface ParserQueryElement {
|
||||
name: string,
|
||||
id: number|null,
|
||||
fullPath: Array<string>,
|
||||
pathWithoutLast: Array<string>,
|
||||
pathLast: string,
|
||||
normalizedPathLast: string,
|
||||
generics: Array<ParserQueryElement>,
|
||||
bindings: Map<string, Array<ParserQueryElement>>,
|
||||
bindingName: {name: string, generics: ParserQueryElement[]}|null,
|
||||
typeFilter: string|null,
|
||||
}
|
||||
|
||||
/**
|
||||
* Intermediate parser state. Discarded when parsing is done.
|
||||
*/
|
||||
interface ParserState {
|
||||
pos: number;
|
||||
length: number;
|
||||
totalElems: number;
|
||||
genericsElems: number;
|
||||
typeFilter: (null|string);
|
||||
userQuery: string;
|
||||
isInBinding: (null|{name: string, generics: ParserQueryElement[]});
|
||||
}
|
||||
|
||||
/**
|
||||
* A complete parsed query.
|
||||
*/
|
||||
interface ParsedQuery<T> {
|
||||
userQuery: string,
|
||||
elems: Array<T>,
|
||||
returned: Array<T>,
|
||||
foundElems: number,
|
||||
totalElems: number,
|
||||
literalSearch: boolean,
|
||||
hasReturnArrow: boolean,
|
||||
correction: string|null,
|
||||
proposeCorrectionFrom: string|null,
|
||||
proposeCorrectionTo: string|null,
|
||||
typeFingerprint: Uint32Array,
|
||||
error: Array<string> | null,
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry in the search index database.
|
||||
*/
|
||||
interface Row {
|
||||
crate: string,
|
||||
descShard: SearchDescShard,
|
||||
id: number,
|
||||
name: string,
|
||||
normalizedName: string,
|
||||
word: string,
|
||||
parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined),
|
||||
path: string,
|
||||
ty: number,
|
||||
type?: FunctionSearchType
|
||||
}
|
||||
|
||||
/**
|
||||
* The viewmodel for the search engine results page.
|
||||
*/
|
||||
interface ResultsTable {
|
||||
in_args: Array<ResultObject>,
|
||||
returned: Array<ResultObject>,
|
||||
others: Array<ResultObject>,
|
||||
query: ParsedQuery,
|
||||
}
|
||||
|
||||
type Results = Map<String, ResultObject>;
|
||||
|
||||
/**
|
||||
* An annotated `Row`, used in the viewmodel.
|
||||
*/
|
||||
interface ResultObject {
|
||||
desc: string,
|
||||
displayPath: string,
|
||||
fullPath: string,
|
||||
href: string,
|
||||
id: number,
|
||||
dist: number,
|
||||
path_dist: number,
|
||||
name: string,
|
||||
normalizedName: string,
|
||||
word: string,
|
||||
index: number,
|
||||
parent: (Object|undefined),
|
||||
path: string,
|
||||
ty: number,
|
||||
type?: FunctionSearchType,
|
||||
paramNames?: string[],
|
||||
displayType: Promise<Array<Array<string>>>|null,
|
||||
displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
|
||||
item: Row,
|
||||
dontValidate?: boolean,
|
||||
}
|
||||
|
||||
/**
|
||||
* A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
|
||||
* The JavaScript deserializes this into FunctionSearchType.
|
||||
*
|
||||
* Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
|
||||
* because `null` is four bytes while `0` is one byte.
|
||||
*
|
||||
* An input or output can be encoded as just a number if there is only one of them, AND
|
||||
* it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
|
||||
* a function with a single output, and that output had a single generic:
|
||||
*
|
||||
* fn something() -> Result<usize, usize>
|
||||
*
|
||||
* If output was allowed to be any RawFunctionType, it would look like thi
|
||||
*
|
||||
* [[], [50, [3, 3]]]
|
||||
*
|
||||
* The problem is that the above output could be interpreted as either a type with ID 50 and two
|
||||
* generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
|
||||
* with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
|
||||
* in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
|
||||
* is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
|
||||
*
|
||||
* The output can be skipped if it's actually unit and there's no type constraints. If thi
|
||||
* function accepts constrained generics, then the output will be unconditionally emitted, and
|
||||
* after it will come a list of trait constraints. The position of the item in the list will
|
||||
* determine which type parameter it is. For example:
|
||||
*
|
||||
* [1, 2, 3, 4, 5]
|
||||
* ^ ^ ^ ^ ^
|
||||
* | | | | - generic parameter (-3) of trait 5
|
||||
* | | | - generic parameter (-2) of trait 4
|
||||
* | | - generic parameter (-1) of trait 3
|
||||
* | - this function returns a single value (type 2)
|
||||
* - this function takes a single input parameter (type 1)
|
||||
*
|
||||
* Or, for a less contrived version:
|
||||
*
|
||||
* [[[4, -1], 3], [[5, -1]], 11]
|
||||
* -^^^^^^^---- ^^^^^^^ ^^
|
||||
* | | | - generic parameter, roughly `where -1: 11`
|
||||
* | | | since -1 is the type parameter and 11 the trait
|
||||
* | | - function output 5<-1>
|
||||
* | - the overall function signature is something like
|
||||
* | `fn(4<-1>, 3) -> 5<-1> where -1: 11`
|
||||
* - function input, corresponds roughly to 4<-1>
|
||||
* 4 is an index into the `p` array for a type
|
||||
* -1 is the generic parameter, given by 11
|
||||
*
|
||||
* If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
|
||||
* function inputs and outputs:
|
||||
*
|
||||
* [-1, -1, [4, 3]]
|
||||
* ^^^^^^ where -1: 4 + 3
|
||||
*
|
||||
* If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
|
||||
* even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
|
||||
* favor of `4 + 3`:
|
||||
*
|
||||
* [-1, -1, [[4, 3]]]
|
||||
* ^^^^^^^^ where -1: 4 + 3
|
||||
*
|
||||
* [-1, -1, [5, [4, 3]]]
|
||||
* ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
|
||||
*
|
||||
* If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
|
||||
* implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
|
||||
*/
|
||||
type RawFunctionSearchType =
|
||||
0 |
|
||||
[(number|Array<RawFunctionType>)] |
|
||||
[(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
|
||||
Array<(number|Array<RawFunctionType>)>
|
||||
;
|
||||
|
||||
/**
|
||||
* A single function input or output type. This is either a single path ID, or a pair of
|
||||
* [path ID, generics].
|
||||
*
|
||||
* Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
|
||||
* because `null` is four bytes while `0` is one byte.
|
||||
*/
|
||||
type RawFunctionType = number | [number, Array<RawFunctionType>];
|
||||
|
||||
/**
|
||||
* The type signature entry in the decoded search index.
|
||||
* (The "Raw" objects are encoded differently to save space in the JSON).
|
||||
*/
|
||||
interface FunctionSearchType {
|
||||
inputs: Array<FunctionType>,
|
||||
output: Array<FunctionType>,
|
||||
where_clause: Array<Array<FunctionType>>,
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoded function type, made from real objects.
|
||||
* `ty` will be negative for generics, positive for types, and 0 for placeholders.
|
||||
*/
|
||||
interface FunctionType {
|
||||
id: null|number,
|
||||
ty: number|null,
|
||||
name?: string,
|
||||
path: string|null,
|
||||
exactPath: string|null,
|
||||
unboxFlag: boolean,
|
||||
generics: Array<FunctionType>,
|
||||
bindings: Map<number, Array<FunctionType>>,
|
||||
};
|
||||
|
||||
interface HighlightedFunctionType extends FunctionType {
|
||||
generics: HighlightedFunctionType[],
|
||||
bindings: Map<number, HighlightedFunctionType[]>,
|
||||
highlighted?: boolean;
|
||||
}
|
||||
|
||||
interface FingerprintableType {
|
||||
id: number|null;
|
||||
generics: FingerprintableType[];
|
||||
bindings: Map<number, FingerprintableType[]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
|
||||
* are arrays with the same length. `q`, `a`, and `c` use a sparse
|
||||
* representation for compactness.
|
||||
*
|
||||
* `n[i]` contains the name of an item.
|
||||
*
|
||||
* `t[i]` contains the type of that item
|
||||
* (as a string of characters that represent an offset in `itemTypes`).
|
||||
*
|
||||
* `d[i]` contains the description of that item.
|
||||
*
|
||||
* `q` contains the full paths of the items. For compactness, it is a set of
|
||||
* (index, path) pairs used to create a map. If a given index `i` is
|
||||
* not present, this indicates "same as the last index present".
|
||||
*
|
||||
* `i[i]` contains an item's parent, usually a module. For compactness,
|
||||
* it is a set of indexes into the `p` array.
|
||||
*
|
||||
* `f` contains function signatures, or `0` if the item isn't a function.
|
||||
* More information on how they're encoded can be found in rustc-dev-guide
|
||||
*
|
||||
* Functions are themselves encoded as arrays. The first item is a list of
|
||||
* types representing the function's inputs, and the second list item is a list
|
||||
* of types representing the function's output. Tuples are flattened.
|
||||
* Types are also represented as arrays; the first item is an index into the `p`
|
||||
* array, while the second is a list of types representing any generic parameters.
|
||||
*
|
||||
* b[i] contains an item's impl disambiguator. This is only present if an item
|
||||
* is defined in an impl block and, the impl block's type has more than one associated
|
||||
* item with the same name.
|
||||
*
|
||||
* `a` defines aliases with an Array of pairs: [name, offset], where `offset`
|
||||
* points into the n/t/d/q/i/f arrays.
|
||||
*
|
||||
* `doc` contains the description of the crate.
|
||||
*
|
||||
* `p` is a list of path/type pairs. It is used for parents and function parameters.
|
||||
* The first item is the type, the second is the name, the third is the visible path (if any) and
|
||||
* the fourth is the canonical path used for deduplication (if any).
|
||||
*
|
||||
* `r` is the canonical path used for deduplication of re-exported items.
|
||||
* It is not used for associated items like methods (that's the fourth element
|
||||
* of `p`) but is used for modules items like free functions.
|
||||
*
|
||||
* `c` is an array of item indices that are deprecated.
|
||||
*/
|
||||
type RawSearchIndexCrate = {
|
||||
doc: string,
|
||||
a: Object,
|
||||
n: Array<string>,
|
||||
t: string,
|
||||
D: string,
|
||||
e: string,
|
||||
q: Array<[number, string]>,
|
||||
i: string,
|
||||
f: string,
|
||||
p: Array<[number, string] | [number, string, number] | [number, string, number, number] | [number, string, number, number, string]>,
|
||||
b: Array<[number, String]>,
|
||||
c: string,
|
||||
r: Array<[number, number]>,
|
||||
P: Array<[number, string]>,
|
||||
};
|
||||
|
||||
type VlqData = VlqData[] | number;
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
/* global addClass, hasClass, removeClass, onEachLazy */
|
||||
|
||||
// Eventually fix this.
|
||||
// @ts-nocheck
|
||||
|
||||
"use strict";
|
||||
|
||||
(function() {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,6 +3,9 @@
|
|||
/* global addClass, removeClass, onEach, onEachLazy */
|
||||
/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
|
||||
|
||||
// Eventually fix this.
|
||||
// @ts-nocheck
|
||||
|
||||
"use strict";
|
||||
|
||||
(function() {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
/* global addClass, onEachLazy, removeClass, browserSupportsHistoryApi */
|
||||
/* global updateLocalStorage, getVar */
|
||||
|
||||
// Eventually fix this.
|
||||
// @ts-nocheck
|
||||
|
||||
"use strict";
|
||||
|
||||
(function() {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue