Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-01-30 05:06:57 +00:00
commit b8ee38d3e8
322 changed files with 5569 additions and 3047 deletions

View file

@ -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(

View file

@ -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 {

View file

@ -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,

View file

@ -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,
}))
}
}
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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()),
}
}

View file

@ -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, "&lt;")?;
}
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, &region) 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)
}

View file

@ -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) => {

View file

@ -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 }) => {

View file

@ -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)| {

View file

@ -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

View file

@ -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()

View file

@ -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)?;
}

View file

@ -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

View file

@ -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))
}

View file

@ -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));

View file

@ -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();
}

View file

@ -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()`

View file

@ -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);

View file

@ -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) =

View file

@ -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()

View file

@ -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,

View file

@ -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();

View file

@ -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 {

View file

@ -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,

View file

@ -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();

View file

@ -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),

View file

@ -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()
})

View file

@ -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(_, _)

View file

@ -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

View file

@ -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

View file

@ -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,
..

View file

@ -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
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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}

View file

@ -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,
}

View file

@ -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,

View file

@ -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;

View file

@ -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 {

View file

@ -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(

View file

@ -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(

View file

@ -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()

View file

@ -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 }

View file

@ -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());

View file

@ -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)>>,

View file

@ -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()

View file

@ -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,

View file

@ -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) }
}

View file

@ -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,

View file

@ -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;
};

View file

@ -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| {

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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 };

View file

@ -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);
}
}

View file

@ -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) => {}
}
}

View file

@ -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 {

View file

@ -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]

View file

@ -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);

View file

@ -298,7 +298,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
TupleStruct,
Or,
Never,
Path,
Tuple,
Box,
Deref,

View file

@ -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);

View file

@ -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;

View file

@ -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 =

View file

@ -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,

View file

@ -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"]),

View file

@ -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}`

View file

@ -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);
}
}

View file

@ -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 {

View file

@ -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>,

View file

@ -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

View file

@ -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);

View file

@ -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");
}

View file

@ -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(

View file

@ -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) {

View file

@ -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,

View file

@ -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,

View file

@ -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"]

View file

@ -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();

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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));

View file

@ -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(" | ")
}

View file

@ -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);

View file

@ -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

View file

@ -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

View 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;
}

View file

@ -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

View file

@ -3,6 +3,9 @@
/* global addClass, removeClass, onEach, onEachLazy */
/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
// Eventually fix this.
// @ts-nocheck
"use strict";
(function() {

View file

@ -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