diff --git a/Cargo.lock b/Cargo.lock
index 71967b03b09d..cf5425a5a896 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -210,9 +210,9 @@ dependencies = [
[[package]]
name = "ar_archive_writer"
-version = "0.1.5"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9792d37ca5173d7e7f4fe453739a0671d0557915a030a383d6b866476bbc3e71"
+checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a"
dependencies = [
"object 0.32.2",
]
@@ -3342,6 +3342,7 @@ name = "run_make_support"
version = "0.0.0"
dependencies = [
"object 0.34.0",
+ "regex",
"wasmparser",
]
@@ -4278,6 +4279,7 @@ dependencies = [
"rustc_fluent_macro",
"rustc_graphviz",
"rustc_hir",
+ "rustc_hir_pretty",
"rustc_index",
"rustc_macros",
"rustc_query_system",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 5b708cf4e1a5..519eeeded9a9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -36,6 +36,7 @@ use rustc_macros::HashStable_Generic;
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
+use std::cmp;
use std::fmt;
use std::mem;
use thin_vec::{thin_vec, ThinVec};
@@ -63,7 +64,7 @@ impl fmt::Debug for Label {
/// A "Lifetime" is an annotation of the scope in which variable
/// can be used, e.g. `'a` in `&'a i32`.
-#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq)]
+#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq, Hash)]
pub struct Lifetime {
pub id: NodeId,
pub ident: Ident,
@@ -731,6 +732,13 @@ impl BindingAnnotation {
Self::MUT_REF_MUT => "mut ref mut ",
}
}
+
+ pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
+ if let ByRef::Yes(old_mutbl) = &mut self.0 {
+ *old_mutbl = cmp::min(*old_mutbl, mutbl);
+ }
+ self
+ }
}
#[derive(Clone, Encodable, Decodable, Debug)]
@@ -2132,7 +2140,7 @@ pub enum TyKind {
/// The `NodeId` exists to prevent lowering from having to
/// generate `NodeId`s on the fly, which would complicate
/// the generation of opaque `type Foo = impl Trait` items significantly.
- ImplTrait(NodeId, GenericBounds),
+ ImplTrait(NodeId, GenericBounds, Option
, Span)>>),
/// No-op; kept solely so that we can pretty-print faithfully.
Paren(P),
/// Unused for now.
@@ -2188,6 +2196,14 @@ pub enum TraitObjectSyntax {
None,
}
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum PreciseCapturingArg {
+ /// Lifetime parameter
+ Lifetime(Lifetime),
+ /// Type or const parameter
+ Arg(Path, NodeId),
+}
+
/// Inline assembly operand explicit register or register class.
///
/// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 98138cedb24d..5e3fc7e33577 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -308,11 +308,11 @@ impl MetaItem {
// FIXME: Share code with `parse_path`.
let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() {
Some(&TokenTree::Token(
- Token { kind: ref kind @ (token::Ident(..) | token::ModSep), span },
+ Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
_,
)) => 'arm: {
let mut segments = if let &token::Ident(name, _) = kind {
- if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }, _)) =
+ if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
tokens.peek()
{
tokens.next();
@@ -331,7 +331,7 @@ impl MetaItem {
} else {
return None;
}
- if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }, _)) =
+ if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
tokens.peek()
{
tokens.next();
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index da57def263df..c4e49d7dbea4 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -259,6 +259,10 @@ pub trait MutVisitor: Sized {
noop_visit_param_bound(tpb, self);
}
+ fn visit_precise_capturing_arg(&mut self, arg: &mut PreciseCapturingArg) {
+ noop_visit_precise_capturing_arg(arg, self);
+ }
+
fn visit_mt(&mut self, mt: &mut MutTy) {
noop_visit_mt(mt, self);
}
@@ -518,9 +522,14 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) {
TyKind::TraitObject(bounds, _syntax) => {
visit_vec(bounds, |bound| vis.visit_param_bound(bound))
}
- TyKind::ImplTrait(id, bounds) => {
+ TyKind::ImplTrait(id, bounds, precise_capturing) => {
vis.visit_id(id);
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+ if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() {
+ for arg in precise_capturing {
+ vis.visit_precise_capturing_arg(arg);
+ }
+ }
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
@@ -914,6 +923,18 @@ pub fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T)
}
}
+pub fn noop_visit_precise_capturing_arg(arg: &mut PreciseCapturingArg, vis: &mut T) {
+ match arg {
+ PreciseCapturingArg::Lifetime(lt) => {
+ vis.visit_lifetime(lt);
+ }
+ PreciseCapturingArg::Arg(path, id) => {
+ vis.visit_path(path);
+ vis.visit_id(id);
+ }
+ }
+}
+
pub fn noop_flat_map_generic_param(
mut param: GenericParam,
vis: &mut T,
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 5060bbec4216..5b41ac8a69ee 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -51,7 +51,7 @@ pub enum Delimiter {
Brace,
/// `[ ... ]`
Bracket,
- /// `Ø ... Ø`
+ /// `∅ ... ∅`
/// An invisible delimiter, that may, for example, appear around tokens coming from a
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
/// `$var * 3` where `$var` is `1 + 2`.
@@ -290,7 +290,7 @@ pub enum TokenKind {
/// `:`
Colon,
/// `::`
- ModSep,
+ PathSep,
/// `->`
RArrow,
/// `<-`
@@ -393,7 +393,7 @@ impl TokenKind {
BinOpEq(Shr) => (Gt, Ge),
DotDot => (Dot, Dot),
DotDotDot => (Dot, DotDot),
- ModSep => (Colon, Colon),
+ PathSep => (Colon, Colon),
RArrow => (BinOp(Minus), Gt),
LArrow => (Lt, BinOp(Minus)),
FatArrow => (Eq, Gt),
@@ -454,7 +454,9 @@ impl Token {
match self.kind {
Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
| BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
- | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true,
+ | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => {
+ true
+ }
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | Eof => false,
@@ -481,7 +483,7 @@ impl Token {
// DotDotDot is no longer supported, but we need some way to display the error
DotDot | DotDotDot | DotDotEq | // range notation
Lt | BinOp(Shl) | // associated path
- ModSep | // global path
+ PathSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
@@ -507,7 +509,7 @@ impl Token {
// DotDotDot is no longer supported
| DotDot | DotDotDot | DotDotEq // ranges
| Lt | BinOp(Shl) // associated path
- | ModSep => true, // global path
+ | PathSep => true, // global path
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
NtPat(..) |
NtBlock(..) |
@@ -530,7 +532,7 @@ impl Token {
Question | // maybe bound in trait object
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
- ModSep => true, // global path
+ PathSep => true, // global path
Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
// For anonymous structs or unions, which only appear in specific positions
// (type of struct fields or union fields), we don't consider them as regular types
@@ -708,7 +710,7 @@ impl Token {
}
pub fn is_path_start(&self) -> bool {
- self == &ModSep
+ self == &PathSep
|| self.is_qpath_start()
|| self.is_whole_path()
|| self.is_path_segment_keyword()
@@ -821,7 +823,7 @@ impl Token {
_ => return None,
},
Colon => match joint.kind {
- Colon => ModSep,
+ Colon => PathSep,
_ => return None,
},
SingleQuote => match joint.kind {
@@ -830,7 +832,7 @@ impl Token {
},
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
- | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
+ | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
| Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
};
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 9e9ae52962d8..968d10ad4872 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -184,6 +184,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
walk_param_bound(self, bounds)
}
+ fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
+ walk_precise_capturing_arg(self, arg);
+ }
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
walk_poly_trait_ref(self, t)
}
@@ -457,8 +460,13 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
TyKind::TraitObject(bounds, ..) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
}
- TyKind::ImplTrait(_, bounds) => {
+ TyKind::ImplTrait(_, bounds, precise_capturing) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
+ if let Some((precise_capturing, _span)) = precise_capturing.as_deref() {
+ for arg in precise_capturing {
+ try_visit!(visitor.visit_precise_capturing_arg(arg));
+ }
+ }
}
TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
@@ -637,6 +645,20 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
}
}
+pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
+ visitor: &mut V,
+ arg: &'a PreciseCapturingArg,
+) {
+ match arg {
+ PreciseCapturingArg::Lifetime(lt) => {
+ visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg);
+ }
+ PreciseCapturingArg::Arg(path, id) => {
+ visitor.visit_path(path, *id);
+ }
+ }
+}
+
pub fn walk_generic_param<'a, V: Visitor<'a>>(
visitor: &mut V,
param: &'a GenericParam,
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index d91d65497e1c..a23e714ef017 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -127,6 +127,8 @@ ast_lowering_never_pattern_with_guard =
a guard on a never pattern will never be run
.suggestion = remove this guard
+ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
+
ast_lowering_previously_used_here = previously used here
ast_lowering_register1 = register `{$reg1_name}`
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 6fd980ed3ca9..ca0821e2c9ed 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -414,3 +414,10 @@ pub(crate) struct AsyncBoundOnlyForFnTraits {
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_no_precise_captures_on_apit)]
+pub(crate) struct NoPreciseCapturesOnApit {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 389cf4e31321..66841c094cec 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -14,6 +14,7 @@ use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
+use rustc_hir::HirId;
use rustc_middle::span_bug;
use rustc_session::errors::report_lit_error;
use rustc_span::source_map::{respan, Spanned};
@@ -701,8 +702,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn maybe_forward_track_caller(
&mut self,
span: Span,
- outer_hir_id: hir::HirId,
- inner_hir_id: hir::HirId,
+ outer_hir_id: HirId,
+ inner_hir_id: HirId,
) {
if self.tcx.features().async_fn_track_caller
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
@@ -1048,7 +1049,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
- closure_hir_id: hir::HirId,
+ closure_hir_id: HirId,
coroutine_kind: CoroutineKind,
decl: &FnDecl,
body: &Expr,
@@ -2036,7 +2037,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
sp: Span,
ident: Ident,
- binding: hir::HirId,
+ binding: HirId,
) -> &'hir hir::Expr<'hir> {
self.arena.alloc(self.expr_ident_mut(sp, ident, binding))
}
@@ -2045,7 +2046,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
span: Span,
ident: Ident,
- binding: hir::HirId,
+ binding: HirId,
) -> hir::Expr<'hir> {
let hir_id = self.next_id();
let res = Res::Local(binding);
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 4c552289a816..93be9b9b8cf5 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -385,4 +385,21 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p)
}
+
+ fn visit_precise_capturing_arg(
+ &mut self,
+ arg: &'hir PreciseCapturingArg<'hir>,
+ ) -> Self::Result {
+ match arg {
+ PreciseCapturingArg::Lifetime(_) => {
+ // This is represented as a `Node::Lifetime`, intravisit will get to it below.
+ }
+ PreciseCapturingArg::Param(param) => self.insert(
+ param.ident.span,
+ param.hir_id,
+ Node::PreciseCapturingNonLifetimeArg(param),
+ ),
+ }
+ intravisit::walk_precise_capturing_arg(self, arg);
+ }
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 5005c22d4cc3..d6e62462b98d 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -48,6 +48,7 @@ use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
@@ -56,7 +57,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{
- ConstArg, GenericArg, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
+ ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
};
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_macros::extension;
@@ -107,7 +108,7 @@ struct LoweringContext<'a, 'hir> {
/// When inside an `async` context, this is the `HirId` of the
/// `task_context` local bound to the resume argument of the coroutine.
- task_context: Option,
+ task_context: Option,
/// Used to get the current `fn`'s def span to point to when using `await`
/// outside of an `async fn`.
@@ -661,18 +662,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
/// properly. Calling the method twice with the same `NodeId` is fine though.
#[instrument(level = "debug", skip(self), ret)]
- fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
+ fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId {
assert_ne!(ast_node_id, DUMMY_NODE_ID);
match self.node_id_to_local_id.entry(ast_node_id) {
- Entry::Occupied(o) => {
- hir::HirId { owner: self.current_hir_id_owner, local_id: *o.get() }
- }
+ Entry::Occupied(o) => HirId { owner: self.current_hir_id_owner, local_id: *o.get() },
Entry::Vacant(v) => {
// Generate a new `HirId`.
let owner = self.current_hir_id_owner;
let local_id = self.item_local_id_counter;
- let hir_id = hir::HirId { owner, local_id };
+ let hir_id = HirId { owner, local_id };
v.insert(local_id);
self.item_local_id_counter.increment_by(1);
@@ -693,12 +692,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// Generate a new `HirId` without a backing `NodeId`.
#[instrument(level = "debug", skip(self), ret)]
- fn next_id(&mut self) -> hir::HirId {
+ fn next_id(&mut self) -> HirId {
let owner = self.current_hir_id_owner;
let local_id = self.item_local_id_counter;
assert_ne!(local_id, hir::ItemLocalId::ZERO);
self.item_local_id_counter.increment_by(1);
- hir::HirId { owner, local_id }
+ HirId { owner, local_id }
}
#[instrument(level = "trace", skip(self))]
@@ -706,7 +705,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let res: Result = res.apply_id(|id| {
let owner = self.current_hir_id_owner;
let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?;
- Ok(hir::HirId { owner, local_id })
+ Ok(HirId { owner, local_id })
});
trace!(?res);
@@ -889,7 +888,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ret
}
- fn lower_attrs(&mut self, id: hir::HirId, attrs: &[Attribute]) -> Option<&'hir [Attribute]> {
+ fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> Option<&'hir [Attribute]> {
if attrs.is_empty() {
None
} else {
@@ -921,7 +920,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) }
}
- fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
+ fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
debug_assert_eq!(id.owner, self.current_hir_id_owner);
debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
if let Some(&a) = self.attrs.get(&target_id.local_id) {
@@ -1398,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
});
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
}
- TyKind::ImplTrait(def_node_id, bounds) => {
+ TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
let span = t.span;
match itctx {
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
@@ -1408,8 +1407,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds,
fn_kind,
itctx,
+ precise_capturing.as_deref().map(|(args, _)| args.as_slice()),
),
ImplTraitContext::Universal => {
+ if let Some(&(_, span)) = precise_capturing.as_deref() {
+ self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
+ };
let span = t.span;
// HACK: pprust breaks strings with newlines when the type
@@ -1520,6 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds: &GenericBounds,
fn_kind: Option,
itctx: ImplTraitContext,
+ precise_capturing_args: Option<&[PreciseCapturingArg]>,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
@@ -1528,42 +1532,59 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
- let captured_lifetimes_to_duplicate = match origin {
- hir::OpaqueTyOrigin::TyAlias { .. } => {
- // type alias impl trait and associated type position impl trait were
- // decided to capture all in-scope lifetimes, which we collect for
- // all opaques during resolution.
- self.resolver
- .take_extra_lifetime_params(opaque_ty_node_id)
- .into_iter()
- .map(|(ident, id, _)| Lifetime { id, ident })
+ let captured_lifetimes_to_duplicate =
+ if let Some(precise_capturing) = precise_capturing_args {
+ // We'll actually validate these later on; all we need is the list of
+ // lifetimes to duplicate during this portion of lowering.
+ precise_capturing
+ .iter()
+ .filter_map(|arg| match arg {
+ PreciseCapturingArg::Lifetime(lt) => Some(*lt),
+ PreciseCapturingArg::Arg(..) => None,
+ })
+ // Add in all the lifetimes mentioned in the bounds. We will error
+ // them out later, but capturing them here is important to make sure
+ // they actually get resolved in resolve_bound_vars.
+ .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
.collect()
- }
- hir::OpaqueTyOrigin::FnReturn(..) => {
- if matches!(
- fn_kind.expect("expected RPITs to be lowered with a FnKind"),
- FnDeclKind::Impl | FnDeclKind::Trait
- ) || self.tcx.features().lifetime_capture_rules_2024
- || span.at_least_rust_2024()
- {
- // return-position impl trait in trait was decided to capture all
- // in-scope lifetimes, which we collect for all opaques during resolution.
- self.resolver
- .take_extra_lifetime_params(opaque_ty_node_id)
- .into_iter()
- .map(|(ident, id, _)| Lifetime { id, ident })
- .collect()
- } else {
- // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
- // example, we only need to duplicate lifetimes that appear in the
- // bounds, since those are the only ones that are captured by the opaque.
- lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
+ } else {
+ match origin {
+ hir::OpaqueTyOrigin::TyAlias { .. } => {
+ // type alias impl trait and associated type position impl trait were
+ // decided to capture all in-scope lifetimes, which we collect for
+ // all opaques during resolution.
+ self.resolver
+ .take_extra_lifetime_params(opaque_ty_node_id)
+ .into_iter()
+ .map(|(ident, id, _)| Lifetime { id, ident })
+ .collect()
+ }
+ hir::OpaqueTyOrigin::FnReturn(..) => {
+ if matches!(
+ fn_kind.expect("expected RPITs to be lowered with a FnKind"),
+ FnDeclKind::Impl | FnDeclKind::Trait
+ ) || self.tcx.features().lifetime_capture_rules_2024
+ || span.at_least_rust_2024()
+ {
+ // return-position impl trait in trait was decided to capture all
+ // in-scope lifetimes, which we collect for all opaques during resolution.
+ self.resolver
+ .take_extra_lifetime_params(opaque_ty_node_id)
+ .into_iter()
+ .map(|(ident, id, _)| Lifetime { id, ident })
+ .collect()
+ } else {
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+ // example, we only need to duplicate lifetimes that appear in the
+ // bounds, since those are the only ones that are captured by the opaque.
+ lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
+ }
+ }
+ hir::OpaqueTyOrigin::AsyncFn(..) => {
+ unreachable!("should be using `lower_async_fn_ret_ty`")
+ }
}
- }
- hir::OpaqueTyOrigin::AsyncFn(..) => {
- unreachable!("should be using `lower_async_fn_ret_ty`")
- }
- };
+ };
debug!(?captured_lifetimes_to_duplicate);
self.lower_opaque_inner(
@@ -1573,6 +1594,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes_to_duplicate,
span,
opaque_ty_span,
+ precise_capturing_args,
|this| this.lower_param_bounds(bounds, itctx),
)
}
@@ -1582,9 +1604,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
opaque_ty_node_id: NodeId,
origin: hir::OpaqueTyOrigin,
in_trait: bool,
- captured_lifetimes_to_duplicate: Vec,
+ captured_lifetimes_to_duplicate: FxIndexSet,
span: Span,
opaque_ty_span: Span,
+ precise_capturing_args: Option<&[PreciseCapturingArg]>,
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def(
@@ -1671,8 +1694,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Install the remapping from old to new (if any). This makes sure that
// any lifetimes that would have resolved to the def-id of captured
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
- let bounds = this
- .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
+ let (bounds, precise_capturing_args) =
+ this.with_remapping(captured_to_synthesized_mapping, |this| {
+ (
+ lower_item_bounds(this),
+ precise_capturing_args.map(|precise_capturing| {
+ this.lower_precise_capturing_args(precise_capturing)
+ }),
+ )
+ });
let generic_params =
this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
@@ -1717,6 +1747,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
origin,
lifetime_mapping,
in_trait,
+ precise_capturing_args,
};
// Generate an `type Foo = impl Trait;` declaration.
@@ -1749,6 +1780,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
}
+ fn lower_precise_capturing_args(
+ &mut self,
+ precise_capturing_args: &[PreciseCapturingArg],
+ ) -> &'hir [hir::PreciseCapturingArg<'hir>] {
+ self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg {
+ PreciseCapturingArg::Lifetime(lt) => {
+ hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt))
+ }
+ PreciseCapturingArg::Arg(path, id) => {
+ let [segment] = path.segments.as_slice() else {
+ panic!();
+ };
+ let res = self.resolver.get_partial_res(*id).map_or(Res::Err, |partial_res| {
+ partial_res.full_res().expect("no partial res expected for precise capture arg")
+ });
+ hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
+ hir_id: self.lower_node_id(*id),
+ ident: self.lower_ident(segment.ident),
+ res: self.lower_res(res),
+ })
+ }
+ }))
+ }
+
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
@@ -1889,7 +1944,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let opaque_ty_span =
self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features);
- let captured_lifetimes: Vec<_> = self
+ let captured_lifetimes = self
.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
@@ -1903,6 +1958,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes,
span,
opaque_ty_span,
+ None,
|this| {
let bound = this.lower_coroutine_fn_output_type_to_bound(
output,
@@ -2421,11 +2477,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.pat(span, hir::PatKind::Struct(qpath, fields, false))
}
- fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
+ fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) {
self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::NONE)
}
- fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) {
+ fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, HirId) {
self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::NONE)
}
@@ -2434,7 +2490,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
ident: Ident,
bm: hir::BindingAnnotation,
- ) -> (&'hir hir::Pat<'hir>, hir::HirId) {
+ ) -> (&'hir hir::Pat<'hir>, HirId) {
let (pat, hir_id) = self.pat_ident_binding_mode_mut(span, ident, bm);
(self.arena.alloc(pat), hir_id)
}
@@ -2444,7 +2500,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
ident: Ident,
bm: hir::BindingAnnotation,
- ) -> (hir::Pat<'hir>, hir::HirId) {
+ ) -> (hir::Pat<'hir>, HirId) {
let hir_id = self.next_id();
(
@@ -2476,12 +2532,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
- fn ty_path(
- &mut self,
- mut hir_id: hir::HirId,
- span: Span,
- qpath: hir::QPath<'hir>,
- ) -> hir::Ty<'hir> {
+ fn ty_path(&mut self, mut hir_id: HirId, span: Span, qpath: hir::QPath<'hir>) -> hir::Ty<'hir> {
let kind = match qpath {
hir::QPath::Resolved(None, path) => {
// Turn trait object paths into `TyKind::TraitObject` instead.
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 4b1c057cdbf1..5456abd489be 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -1,6 +1,7 @@
use super::ResolverAstLoweringExt;
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
+use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def::{DefKind, LifetimeRes, Res};
use rustc_middle::span_bug;
use rustc_middle::ty::ResolverAstLowering;
@@ -10,27 +11,23 @@ use rustc_span::Span;
struct LifetimeCollectVisitor<'ast> {
resolver: &'ast ResolverAstLowering,
current_binders: Vec,
- collected_lifetimes: Vec,
+ collected_lifetimes: FxIndexSet,
}
impl<'ast> LifetimeCollectVisitor<'ast> {
fn new(resolver: &'ast ResolverAstLowering) -> Self {
- Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
+ Self { resolver, current_binders: Vec::new(), collected_lifetimes: FxIndexSet::default() }
}
fn record_lifetime_use(&mut self, lifetime: Lifetime) {
match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
if !self.current_binders.contains(&binder) {
- if !self.collected_lifetimes.contains(&lifetime) {
- self.collected_lifetimes.push(lifetime);
- }
+ self.collected_lifetimes.insert(lifetime);
}
}
LifetimeRes::Static | LifetimeRes::Error => {
- if !self.collected_lifetimes.contains(&lifetime) {
- self.collected_lifetimes.push(lifetime);
- }
+ self.collected_lifetimes.insert(lifetime);
}
LifetimeRes::Infer => {}
res => {
@@ -111,7 +108,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
pub(crate) fn lifetimes_in_bounds(
resolver: &ResolverAstLowering,
bounds: &GenericBounds,
-) -> Vec {
+) -> FxIndexSet {
let mut visitor = LifetimeCollectVisitor::new(resolver);
for bound in bounds {
visitor.visit_param_bound(bound, BoundKind::Bound);
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index cb4dcf3ae75f..495e90e967b9 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -737,7 +737,7 @@ impl<'a> AstValidator<'a> {
}
}
}
- TyKind::ImplTrait(_, bounds) => {
+ TyKind::ImplTrait(_, bounds, _) => {
if self.is_impl_trait_banned {
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index d7cd3efe408b..70a3ccb0f440 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -569,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
+ gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 51ccfe89fbdb..242335f769ce 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -893,7 +893,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere
token::Comma => ",".into(),
token::Semi => ";".into(),
token::Colon => ":".into(),
- token::ModSep => "::".into(),
+ token::PathSep => "::".into(),
token::RArrow => "->".into(),
token::LArrow => "<-".into(),
token::FatArrow => "=>".into(),
@@ -1150,8 +1150,17 @@ impl<'a> State<'a> {
}
self.print_type_bounds(bounds);
}
- ast::TyKind::ImplTrait(_, bounds) => {
+ ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => {
self.word_nbsp("impl");
+ if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() {
+ self.word("use");
+ self.word("<");
+ self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg {
+ ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
+ ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
+ });
+ self.word(">")
+ }
self.print_type_bounds(bounds);
}
ast::TyKind::Array(ty, length) => {
diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs
index 3b2b60a86f06..5b5ffbc6f882 100644
--- a/compiler/rustc_ast_pretty/src/pprust/tests.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs
@@ -3,6 +3,7 @@ use super::*;
use rustc_ast as ast;
use rustc_span::create_default_session_globals_then;
use rustc_span::symbol::Ident;
+use rustc_span::DUMMY_SP;
use thin_vec::ThinVec;
fn fun_to_string(
@@ -28,10 +29,7 @@ fn test_fun_to_string() {
create_default_session_globals_then(|| {
let abba_ident = Ident::from_str("abba");
- let decl = ast::FnDecl {
- inputs: ThinVec::new(),
- output: ast::FnRetTy::Default(rustc_span::DUMMY_SP),
- };
+ let decl = ast::FnDecl { inputs: ThinVec::new(), output: ast::FnRetTy::Default(DUMMY_SP) };
let generics = ast::Generics::default();
assert_eq!(
fun_to_string(&decl, ast::FnHeader::default(), abba_ident, &generics),
@@ -48,7 +46,7 @@ fn test_variant_to_string() {
let var = ast::Variant {
ident,
vis: ast::Visibility {
- span: rustc_span::DUMMY_SP,
+ span: DUMMY_SP,
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
@@ -56,7 +54,7 @@ fn test_variant_to_string() {
id: ast::DUMMY_NODE_ID,
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
disr_expr: None,
- span: rustc_span::DUMMY_SP,
+ span: DUMMY_SP,
is_placeholder: false,
};
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 0a4f32c95850..8ccf88ec59c0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1752,32 +1752,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
- struct FindUselessClone<'hir> {
- tcx: TyCtxt<'hir>,
- def_id: DefId,
- pub clones: Vec<&'hir hir::Expr<'hir>>,
+
+ struct FindUselessClone<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'tcx ty::TypeckResults<'tcx>,
+ pub clones: Vec<&'tcx hir::Expr<'tcx>>,
}
- impl<'hir> FindUselessClone<'hir> {
- pub fn new(tcx: TyCtxt<'hir>, def_id: DefId) -> Self {
- Self { tcx, def_id, clones: vec![] }
+ impl<'tcx> FindUselessClone<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+ Self { tcx, typeck_results: tcx.typeck(def_id), clones: vec![] }
}
}
-
- impl<'v> Visitor<'v> for FindUselessClone<'v> {
- fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
- if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind
- && segment.ident.name == sym::clone
- && args.len() == 0
- && let Some(def_id) = self.def_id.as_local()
- && let Some(method) = self.tcx.lookup_method_for_diagnostic((def_id, ex.hir_id))
- && Some(self.tcx.parent(method)) == self.tcx.lang_items().clone_trait()
+ impl<'tcx> Visitor<'tcx> for FindUselessClone<'tcx> {
+ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::MethodCall(..) = ex.kind
+ && let Some(method_def_id) =
+ self.typeck_results.type_dependent_def_id(ex.hir_id)
+ && self.tcx.lang_items().clone_trait() == Some(self.tcx.parent(method_def_id))
{
self.clones.push(ex);
}
hir::intravisit::walk_expr(self, ex);
}
}
- let mut expr_finder = FindUselessClone::new(tcx, self.mir_def_id().into());
+
+ let mut expr_finder = FindUselessClone::new(tcx, self.mir_def_id());
let body = hir.body(body_id).value;
expr_finder.visit_expr(body);
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 304d41d69417..2fe75fe2a2bf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -26,7 +26,6 @@ use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_middle::ty::{Region, TyCtxt};
use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
-use rustc_trait_selection::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
@@ -813,7 +812,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
self.suggest_move_on_borrowing_closure(&mut diag);
- self.suggest_deref_closure_value(&mut diag);
+ self.suggest_deref_closure_return(&mut diag);
diag
}
@@ -1048,125 +1047,111 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// When encountering a lifetime error caused by the return type of a closure, check the
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
/// them. If so, we produce a structured suggestion.
- fn suggest_deref_closure_value(&self, diag: &mut Diag<'_>) {
+ fn suggest_deref_closure_return(&self, diag: &mut Diag<'_>) {
let tcx = self.infcx.tcx;
- let map = tcx.hir();
// Get the closure return value and type.
- let body_id = map.body_owned_by(self.mir_def_id());
- let body = &map.body(body_id);
- let value = &body.value.peel_blocks();
- let hir::Node::Expr(closure_expr) = tcx.hir_node_by_def_id(self.mir_def_id()) else {
+ let closure_def_id = self.mir_def_id();
+ let hir::Node::Expr(
+ closure_expr @ hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { body, .. }), ..
+ },
+ ) = tcx.hir_node_by_def_id(closure_def_id)
+ else {
return;
};
- let fn_call_id = tcx.parent_hir_id(self.mir_hir_id());
- let hir::Node::Expr(expr) = tcx.hir_node(fn_call_id) else { return };
- let def_id = map.enclosing_body_owner(fn_call_id);
- let tables = tcx.typeck(def_id);
- let Some(return_value_ty) = tables.node_type_opt(value.hir_id) else { return };
- let return_value_ty = self.infcx.resolve_vars_if_possible(return_value_ty);
+ let ty::Closure(_, args) = *tcx.type_of(closure_def_id).instantiate_identity().kind()
+ else {
+ return;
+ };
+ let args = args.as_closure();
+
+ // Make sure that the parent expression is a method call.
+ let parent_expr_id = tcx.parent_hir_id(self.mir_hir_id());
+ let hir::Node::Expr(
+ parent_expr @ hir::Expr {
+ kind: hir::ExprKind::MethodCall(_, rcvr, call_args, _), ..
+ },
+ ) = tcx.hir_node(parent_expr_id)
+ else {
+ return;
+ };
+ let typeck_results = tcx.typeck(self.mir_def_id());
// We don't use `ty.peel_refs()` to get the number of `*`s needed to get the root type.
- let mut ty = return_value_ty;
+ let liberated_sig = tcx.liberate_late_bound_regions(closure_def_id.to_def_id(), args.sig());
+ let mut peeled_ty = liberated_sig.output();
let mut count = 0;
- while let ty::Ref(_, t, _) = ty.kind() {
- ty = *t;
+ while let ty::Ref(_, ref_ty, _) = *peeled_ty.kind() {
+ peeled_ty = ref_ty;
count += 1;
}
- if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
+ if !self.infcx.type_is_copy_modulo_regions(self.param_env, peeled_ty) {
return;
}
// Build a new closure where the return type is an owned value, instead of a ref.
- let Some(ty::Closure(did, args)) =
- tables.node_type_opt(closure_expr.hir_id).as_ref().map(|ty| ty.kind())
- else {
- return;
- };
- let sig = args.as_closure().sig();
let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr(
tcx,
- sig.map_bound(|s| {
- let unsafety = hir::Unsafety::Normal;
- use rustc_target::spec::abi;
- tcx.mk_fn_sig(
- [s.inputs()[0]],
- s.output().peel_refs(),
- s.c_variadic,
- unsafety,
- abi::Abi::Rust,
- )
- }),
+ ty::Binder::dummy(tcx.mk_fn_sig(
+ liberated_sig.inputs().iter().copied(),
+ peeled_ty,
+ liberated_sig.c_variadic,
+ hir::Unsafety::Normal,
+ rustc_target::spec::abi::Abi::Rust,
+ )),
);
- let parent_args = GenericArgs::identity_for_item(
+ let closure_ty = Ty::new_closure(
tcx,
- tcx.typeck_root_def_id(self.mir_def_id().to_def_id()),
+ closure_def_id.to_def_id(),
+ ty::ClosureArgs::new(
+ tcx,
+ ty::ClosureArgsParts {
+ parent_args: args.parent_args(),
+ closure_kind_ty: args.kind_ty(),
+ tupled_upvars_ty: args.tupled_upvars_ty(),
+ closure_sig_as_fn_ptr_ty,
+ },
+ )
+ .args,
);
- let closure_kind = args.as_closure().kind();
- let closure_kind_ty = Ty::from_closure_kind(tcx, closure_kind);
- let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::ClosureSynthetic,
- span: closure_expr.span,
- });
- let closure_args = ty::ClosureArgs::new(
- tcx,
- ty::ClosureArgsParts {
- parent_args,
- closure_kind_ty,
- closure_sig_as_fn_ptr_ty,
- tupled_upvars_ty,
- },
- );
- let closure_ty = Ty::new_closure(tcx, *did, closure_args.args);
- let closure_ty = tcx.erase_regions(closure_ty);
- let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return };
- let Some(pos) = args
- .iter()
- .enumerate()
- .find(|(_, arg)| arg.hir_id == closure_expr.hir_id)
- .map(|(i, _)| i)
+ let Some((closure_arg_pos, _)) =
+ call_args.iter().enumerate().find(|(_, arg)| arg.hir_id == closure_expr.hir_id)
else {
return;
};
- // The found `Self` type of the method call.
- let Some(possible_rcvr_ty) = tables.node_type_opt(rcvr.hir_id) else { return };
-
- // The `MethodCall` expression is `Res::Err`, so we search for the method on the `rcvr_ty`.
- let Some(method) = tcx.lookup_method_for_diagnostic((self.mir_def_id(), expr.hir_id))
- else {
- return;
- };
-
// Get the type for the parameter corresponding to the argument the closure with the
// lifetime error we had.
- let Some(input) = tcx
- .fn_sig(method)
- .instantiate_identity()
+ let Some(method_def_id) = typeck_results.type_dependent_def_id(parent_expr.hir_id) else {
+ return;
+ };
+ let Some(input_arg) = tcx
+ .fn_sig(method_def_id)
+ .skip_binder()
.inputs()
.skip_binder()
// Methods have a `self` arg, so `pos` is actually `+ 1` to match the method call arg.
- .get(pos + 1)
+ .get(closure_arg_pos + 1)
else {
return;
};
-
- trace!(?input);
-
- let ty::Param(closure_param) = input.kind() else { return };
+ // If this isn't a param, then we can't substitute a new closure.
+ let ty::Param(closure_param) = input_arg.kind() else { return };
// Get the arguments for the found method, only specifying that `Self` is the receiver type.
- let args = GenericArgs::for_item(tcx, method, |param, _| {
+ let Some(possible_rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) else { return };
+ let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
if param.index == 0 {
possible_rcvr_ty.into()
} else if param.index == closure_param.index {
closure_ty.into()
} else {
- self.infcx.var_for_def(expr.span, param)
+ self.infcx.var_for_def(parent_expr.span, param)
}
});
- let preds = tcx.predicates_of(method).instantiate(tcx, args);
+ let preds = tcx.predicates_of(method_def_id).instantiate(tcx, args);
let ocx = ObligationCtxt::new(&self.infcx);
ocx.register_obligations(preds.iter().map(|(pred, span)| {
@@ -1176,7 +1161,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if ocx.select_all_or_error().is_empty() {
diag.span_suggestion_verbose(
- value.span.shrink_to_lo(),
+ tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
"dereference the return value",
"*".repeat(count),
Applicability::MachineApplicable,
diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
index c103ba3c4070..f145d30fe38a 100644
--- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs
+++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
@@ -6,7 +6,38 @@ use std::borrow::Cow;
use std::io::{self, Write};
use super::*;
+use itertools::Itertools;
use rustc_graphviz as dot;
+use rustc_middle::ty::UniverseIndex;
+
+fn render_outlives_constraint(constraint: &OutlivesConstraint<'_>) -> String {
+ match constraint.locations {
+ Locations::All(_) => "All(...)".to_string(),
+ Locations::Single(loc) => format!("{loc:?}"),
+ }
+}
+
+fn render_universe(u: UniverseIndex) -> String {
+ if u.is_root() {
+ return "".to_string();
+ }
+
+ format!("/{:?}", u)
+}
+
+fn render_region_vid(rvid: RegionVid, regioncx: &RegionInferenceContext<'_>) -> String {
+ let universe_str = render_universe(regioncx.region_definition(rvid).universe);
+
+ let external_name_str = if let Some(external_name) =
+ regioncx.region_definition(rvid).external_name.and_then(|e| e.get_name())
+ {
+ format!(" ({external_name})")
+ } else {
+ "".to_string()
+ };
+
+ format!("{:?}{universe_str}{external_name_str}", rvid)
+}
impl<'tcx> RegionInferenceContext<'tcx> {
/// Write out the region constraint graph.
@@ -46,10 +77,10 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
}
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
- dot::LabelText::LabelStr(format!("{n:?}").into())
+ dot::LabelText::LabelStr(render_region_vid(*n, self.regioncx).into())
}
fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
- dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
+ dot::LabelText::LabelStr(render_outlives_constraint(e).into())
}
}
@@ -96,8 +127,9 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> {
Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
}
fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> {
- let nodes = &self.nodes_per_scc[*n];
- dot::LabelText::LabelStr(format!("{n:?} = {nodes:?}").into())
+ let nodes_str =
+ self.nodes_per_scc[*n].iter().map(|n| render_region_vid(*n, self.regioncx)).join(", ");
+ dot::LabelText::LabelStr(format!("SCC({n}) = {{{nodes_str}}}", n = n.as_usize()).into())
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 599f7dd18c3e..dd75548a15df 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1562,7 +1562,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Because this free region must be in the ROOT universe, we
// know it cannot contain any bound universes.
- assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT);
+ assert!(self.scc_universes[longer_fr_scc].is_root());
debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none());
// Only check all of the relations for the main representative of each
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 9f0e54febe4c..73ba5bee13b7 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -213,7 +213,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let scc = self.constraint_sccs.scc(vid);
// Special handling of higher-ranked regions.
- if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
+ if !self.scc_universes[scc].is_root() {
match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
// If the region contains a single placeholder then they're equal.
Some((0, placeholder)) => {
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index a4c1066ee8e9..2511a1535af1 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -11,7 +11,7 @@ use std::assert_matches::assert_matches;
use itertools::Itertools;
use rustc_hir as hir;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
@@ -75,10 +75,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
let next_ty_var = || {
- self.infcx.next_ty_var(TypeVariableOrigin {
- span: body.span,
- kind: TypeVariableOriginKind::MiscVariable,
- })
+ self.infcx.next_ty_var(TypeVariableOrigin { span: body.span, param_def_id: None })
};
let output_ty = Ty::new_coroutine(
self.tcx(),
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 71b54a761a2b..0600a105459b 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -16,7 +16,7 @@ use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::{
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
};
@@ -2425,7 +2425,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ty::RawPtr(_, _) | ty::FnPtr(_) => {
let ty_right = right.ty(body, tcx);
let common_ty = self.infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
+ param_def_id: None,
span: body.source_info(location).span,
});
self.sub_types(
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 78609a482ed2..d67ede57e787 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,6 +1,6 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases};
use rustc_infer::traits::{Obligation, PredicateObligations};
@@ -129,10 +129,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
// the opaque.
let mut enable_subtyping = |ty, opaque_is_expected| {
let ty_vid = infcx.next_ty_var_id_in_universe(
- TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.span(),
- },
+ TypeVariableOrigin { param_def_id: None, span: self.span() },
ty::UniverseIndex::ROOT,
);
@@ -437,7 +434,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
- let a = self.type_checker.infcx.shallow_resolve(a);
+ let a = self.type_checker.infcx.shallow_resolve_const(a);
assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 603cefdd3862..188833246832 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -8,8 +8,7 @@ use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfK
use rustc_expand::base::ExtCtxt;
use rustc_span::source_map::respan;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
use thin_vec::ThinVec;
/// A path, e.g., `::std::option::Option::` (global). Has support
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index baf10622a6df..f347a7fb0bb1 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
-ar_archive_writer = "0.1.5"
+ar_archive_writer = "0.2.0"
bitflags = "2.4.1"
cc = "1.0.90"
itertools = "0.12"
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index ef55682d541e..d336973d2b9c 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -285,14 +285,7 @@ impl<'a> ArArchiveBuilder<'a> {
.tempfile_in(output.parent().unwrap_or_else(|| Path::new("")))
.map_err(|err| io_error_context("couldn't create a temp file", err))?;
- write_archive_to_stream(
- archive_tmpfile.as_file_mut(),
- &entries,
- true,
- archive_kind,
- true,
- false,
- )?;
+ write_archive_to_stream(archive_tmpfile.as_file_mut(), &entries, archive_kind, false)?;
let any_entries = !entries.is_empty();
drop(entries);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index e7d6a671e120..b458f325b737 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2059,7 +2059,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained:
/// Add options making relocation sections in the produced ELF files read-only
/// and suppressing lazy binding.
fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) {
- match sess.opts.unstable_opts.relro_level.unwrap_or(sess.target.relro_level) {
+ match sess.opts.cg.relro_level.unwrap_or(sess.target.relro_level) {
RelroLevel::Full => cmd.full_relro(),
RelroLevel::Partial => cmd.partial_relro(),
RelroLevel::Off => cmd.no_relro(),
@@ -3038,9 +3038,10 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result {}
"watchsimulator"
if sdkroot.contains("WatchOS.platform") || sdkroot.contains("MacOSX.platform") => {}
- "visionos"
- if sdkroot.contains("XROS.platform") || sdkroot.contains("MacOSX.platform") => {}
- "visionossimulator"
+ "xros"
+ if sdkroot.contains("XRSimulator.platform")
+ || sdkroot.contains("MacOSX.platform") => {}
+ "xrsimulator"
if sdkroot.contains("XROS.platform") || sdkroot.contains("MacOSX.platform") => {}
// Ignore `SDKROOT` if it's not a valid path.
_ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index e7f692144ff0..c4f062405bb5 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -907,8 +907,6 @@ fn execute_copy_from_cache_work_item(
module: CachedModuleCodegen,
module_config: &ModuleConfig,
) -> WorkItemResult {
- assert!(module_config.emit_obj != EmitObj::None);
-
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| {
@@ -928,12 +926,6 @@ fn execute_copy_from_cache_work_item(
}
};
- let object = load_from_incr_comp_dir(
- cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)),
- module.source.saved_files.get("o").unwrap_or_else(|| {
- cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name })
- }),
- );
let dwarf_object =
module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
let dwarf_obj_out = cgcx
@@ -955,9 +947,14 @@ fn execute_copy_from_cache_work_item(
}
};
+ let should_emit_obj = module_config.emit_obj != EmitObj::None;
let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly);
let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly);
let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode);
+ let object = load_from_incr_cache(should_emit_obj, OutputType::Object);
+ if should_emit_obj && object.is_none() {
+ cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name })
+ }
WorkItemResult::Finished(CompiledModule {
name: module.name,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 24f2c50e882f..452398e6d828 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1861,12 +1861,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
enum ReturnDest<'tcx, V> {
- // Do nothing; the return value is indirect or ignored.
+ /// Do nothing; the return value is indirect or ignored.
Nothing,
- // Store the return value to the pointer.
+ /// Store the return value to the pointer.
Store(PlaceRef<'tcx, V>),
- // Store an indirect return value to an operand local place.
+ /// Store an indirect return value to an operand local place.
IndirectOperand(PlaceRef<'tcx, V>, mir::Local),
- // Store a direct return value to an operand local place.
+ /// Store a direct return value to an operand local place.
DirectOperand(mir::Local),
}
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 827d8fd9417c..3aeae5ebf6de 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -347,8 +347,6 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// allocation (because a copy had to be done to adjust things), machine memory will
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
/// owned allocation to the map even when the map is shared.)
- ///
- /// This must only fail if `alloc` contains provenance.
fn adjust_allocation<'b>(
ecx: &InterpCx<'mir, 'tcx, Self>,
id: AllocId,
@@ -427,6 +425,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
_prov: (AllocId, Self::ProvenanceExtra),
_size: Size,
_align: Align,
+ _kind: MemoryKind,
) -> InterpResult<'tcx> {
Ok(())
}
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 9b1d9cf932bd..fbb0907f7d05 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -227,7 +227,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.allocate_raw_ptr(alloc, kind)
}
- /// This can fail only if `alloc` contains provenance.
pub fn allocate_raw_ptr(
&mut self,
alloc: Allocation,
@@ -355,6 +354,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(alloc_id, prov),
size,
alloc.align,
+ kind,
)?;
// Don't forget to remember size and align of this now-dead allocation
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 543996c86bac..a506d10c1d08 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -168,7 +168,7 @@ impl<'ck, 'mir, 'tcx> TypeVisitor> for LocalReturnTyVisitor<'ck, 'm
match t.kind() {
ty::FnPtr(_) => {}
ty::Ref(_, _, hir::Mutability::Mut) => {
- self.checker.check_op(ops::ty::MutRef(self.kind));
+ self.checker.check_op(ops::mut_ref::MutRef(self.kind));
t.super_visit_with(self)
}
_ => t.super_visit_with(self),
@@ -331,6 +331,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
if self.tcx.is_thread_local_static(def_id) {
self.tcx.dcx().span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
}
+ if let Some(def_id) = def_id.as_local()
+ && let Err(guar) = self.tcx.at(span).check_well_formed(hir::OwnerId { def_id })
+ {
+ self.error_emitted = Some(guar);
+ }
self.check_op_spanned(ops::StaticAccess, span)
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index e87e60f62dc8..dda8f3ed87d2 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -9,9 +9,10 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::{self, CallSource};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::TraitRef;
-use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
-use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{
+ self, suggest_constraining_type_param, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef,
+ Param, TraitRef, Ty,
+};
use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
@@ -123,7 +124,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
);
}
}
- Adt(..) => {
+ ty::Adt(..) => {
let obligation =
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
@@ -620,7 +621,7 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
}
/// Types that cannot appear in the signature or locals of a `const fn`.
-pub mod ty {
+pub mod mut_ref {
use super::*;
#[derive(Debug)]
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index c0c6201f73d4..40f6f7649937 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -24,20 +24,6 @@ struct AstNoAnn;
impl pprust_ast::PpAnn for AstNoAnn {}
-struct HirNoAnn<'tcx> {
- tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> pprust_hir::PpAnn for HirNoAnn<'tcx> {
- fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
- pprust_hir::PpAnn::nested(
- &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>),
- state,
- nested,
- )
- }
-}
-
struct AstIdentifiedAnn;
impl pprust_ast::PpAnn for AstIdentifiedAnn {
@@ -300,10 +286,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
)
};
match s {
- PpHirMode::Normal => {
- let annotation = HirNoAnn { tcx };
- f(&annotation)
- }
+ PpHirMode::Normal => f(&tcx),
PpHirMode::Identified => {
let annotation = HirIdentifiedAnn { tcx };
f(&annotation)
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index ddc685c9d07d..5a66b0fbdef1 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -208,7 +208,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec op(","),
Semi => op(";"),
Colon => op(":"),
- ModSep => op("::"),
+ PathSep => op("::"),
RArrow => op("->"),
LArrow => op("<-"),
FatArrow => op("=>"),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e6b19817de38..9641d336c3f3 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -533,6 +533,8 @@ declare_features! (
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
/// Allows the `#[must_not_suspend]` attribute.
(unstable, must_not_suspend, "1.57.0", Some(83310)),
+ /// Make `mut` not reset the binding mode on edition >= 2024.
+ (incomplete, mut_preserve_binding_mode_2024, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows `mut ref` and `mut ref mut` identifier patterns.
(incomplete, mut_ref, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows using `#[naked]` on functions.
@@ -567,10 +569,14 @@ declare_features! (
(unstable, optimize_attribute, "1.34.0", Some(54882)),
/// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
+ /// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.
+ (incomplete, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)),
/// Allows macro attributes on expressions, statements and non-inline modules.
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
(unstable, raw_ref_op, "1.41.0", Some(64490)),
+ /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
+ (incomplete, ref_pat_eat_one_layer_2024, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows using the `#[register_tool]` attribute.
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 2662f5661ba5..37d9b2ffd6ab 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -207,7 +207,6 @@ impl DefKind {
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
- | DefKind::OpaqueTy
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
@@ -234,7 +233,8 @@ impl DefKind {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::GlobalAsm
- | DefKind::Impl { .. } => None,
+ | DefKind::Impl { .. }
+ | DefKind::OpaqueTy => None,
}
}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c6e3ad31f013..b39056d8690c 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2557,6 +2557,27 @@ pub struct OpaqueTy<'hir> {
/// originating from a trait method. This makes it so that the opaque is
/// lowered as an associated type.
pub in_trait: bool,
+ /// List of arguments captured via `impl use<'a, P, ...> Trait` syntax.
+ pub precise_capturing_args: Option<&'hir [PreciseCapturingArg<'hir>]>,
+}
+
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub enum PreciseCapturingArg<'hir> {
+ Lifetime(&'hir Lifetime),
+ /// Non-lifetime argument (type or const)
+ Param(PreciseCapturingNonLifetimeArg),
+}
+
+/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
+/// resolution to. Lifetimes don't have this problem, and for them, it's actually
+/// kind of detrimental to use a custom node type versus just using [`Lifetime`],
+/// since resolve_bound_vars operates on `Lifetime`s.
+// FIXME(precise_capturing): Investigate storing this as a path instead?
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub struct PreciseCapturingNonLifetimeArg {
+ pub hir_id: HirId,
+ pub ident: Ident,
+ pub res: Res,
}
/// From whence the opaque type came.
@@ -3535,6 +3556,7 @@ pub enum Node<'hir> {
WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>),
// FIXME: Merge into `Node::Infer`.
ArrayLenInfer(&'hir InferArg),
+ PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg),
// Created by query feeding
Synthetic,
// Span by reference to minimize `Node`'s size
@@ -3571,6 +3593,7 @@ impl<'hir> Node<'hir> {
Node::TypeBinding(b) => Some(b.ident),
Node::PatField(f) => Some(f.ident),
Node::ExprField(f) => Some(f.ident),
+ Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident),
Node::Param(..)
| Node::AnonConst(..)
| Node::ConstBlock(..)
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 5da9d4444da3..cd9f9ff9109c 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -413,6 +413,9 @@ pub trait Visitor<'v>: Sized {
fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> Self::Result {
walk_param_bound(self, bounds)
}
+ fn visit_precise_capturing_arg(&mut self, arg: &'v PreciseCapturingArg<'v>) -> Self::Result {
+ walk_precise_capturing_arg(self, arg)
+ }
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result {
walk_poly_trait_ref(self, t)
}
@@ -526,10 +529,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_generics(generics));
}
- ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
+ ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(walk_generics(visitor, generics));
walk_list!(visitor, visit_param_bound, bounds);
+ if let Some(precise_capturing_args) = precise_capturing_args {
+ for arg in precise_capturing_args {
+ try_visit!(visitor.visit_precise_capturing_arg(arg));
+ }
+ }
}
ItemKind::Enum(ref enum_definition, ref generics) => {
try_visit!(visitor.visit_generics(generics));
@@ -1137,6 +1145,16 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(
}
}
+pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>(
+ visitor: &mut V,
+ arg: &'v PreciseCapturingArg<'v>,
+) -> V::Result {
+ match *arg {
+ PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt),
+ PreciseCapturingArg::Param(param) => visitor.visit_id(param.hir_id),
+ }
+}
+
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_ref: &'v PolyTraitRef<'v>,
diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs
index 74b8e88a9779..571923b54629 100644
--- a/compiler/rustc_hir/src/tests.rs
+++ b/compiler/rustc_hir/src/tests.rs
@@ -14,7 +14,7 @@ fn def_path_hash_depends_on_crate_id() {
// the crate by changing the crate disambiguator (e.g. via bumping the
// crate's version number).
- create_session_globals_then(Edition::Edition2024, || {
+ create_session_globals_then(Edition::Edition2024, None, || {
let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], "");
let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 86b8b6d6b2b6..0ff78ebff995 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -37,6 +37,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
.label = deref recursion limit reached
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found}
+
hir_analysis_cannot_capture_late_bound_const =
cannot capture late-bound const parameter in {$what}
.label = parameter defined here
@@ -111,6 +113,9 @@ hir_analysis_drop_impl_on_wrong_item =
hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
+hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
+ .label = parameter captured again here
+
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
.note = impl is a specialization of this impl
@@ -214,6 +219,13 @@ hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetim
hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
.label = type parameter declared here
+hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters
+ .label = move the lifetime before this parameter
+
+hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
+ .label = lifetime captured due to being mentioned in the bounds of the `impl Trait`
+ .param_label = this lifetime parameter is captured
+
hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait
@@ -339,6 +351,10 @@ hir_analysis_param_in_ty_of_assoc_const_binding =
*[normal] the {$param_def_kind} `{$param_name}` is defined here
}
+hir_analysis_param_not_captured = `impl Trait` must mention all {$kind} parameters in scope
+ .label = {$kind} parameter is implicitly captured by this `impl Trait`
+ .note = currently, all {$kind} parameters are required to be mentioned in the precise captures list
+
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
@@ -355,6 +371,9 @@ hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pa
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures
+hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
+ .label = `Self` is not a generic argument, but an alias to the type of the {$what}
+
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 216b89fd4f15..8c85d13650b4 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,10 +1,10 @@
use crate::check::intrinsicck::InlineAsmCtxt;
-use crate::errors::LinkageType;
use super::compare_impl_item::check_type_bounds;
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
use super::*;
use rustc_attr as attr;
+use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::{codes::*, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind};
@@ -12,6 +12,7 @@ use rustc_hir::Node;
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
+use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::fold::BottomUpFolder;
@@ -474,6 +475,133 @@ fn sanity_check_found_hidden_type<'tcx>(
}
}
+/// Check that the opaque's precise captures list is valid (if present).
+/// We check this for regular `impl Trait`s and also RPITITs, even though the latter
+/// are technically GATs.
+///
+/// This function is responsible for:
+/// 1. Checking that all type/const params are mention in the captures list.
+/// 2. Checking that all lifetimes that are implicitly captured are mentioned.
+/// 3. Asserting that all parameters mentioned in the captures list are invariant.
+fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
+ let hir::OpaqueTy { precise_capturing_args, .. } =
+ *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+ let Some(precise_capturing_args) = precise_capturing_args else {
+ // No precise capturing args; nothing to validate
+ return;
+ };
+
+ let mut expected_captures = UnordSet::default();
+ let mut seen_params = UnordMap::default();
+ let mut prev_non_lifetime_param = None;
+ for arg in precise_capturing_args {
+ let (hir_id, ident) = match *arg {
+ hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
+ hir_id,
+ ident,
+ ..
+ }) => {
+ if prev_non_lifetime_param.is_none() {
+ prev_non_lifetime_param = Some(ident);
+ }
+ (hir_id, ident)
+ }
+ hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {
+ if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {
+ tcx.dcx().emit_err(errors::LifetimesMustBeFirst {
+ lifetime_span: ident.span,
+ name: ident.name,
+ other_span: prev_non_lifetime_param.span,
+ });
+ }
+ (hir_id, ident)
+ }
+ };
+
+ let ident = ident.normalize_to_macros_2_0();
+ if let Some(span) = seen_params.insert(ident, ident.span) {
+ tcx.dcx().emit_err(errors::DuplicatePreciseCapture {
+ name: ident.name,
+ first_span: span,
+ second_span: ident.span,
+ });
+ }
+
+ match tcx.named_bound_var(hir_id) {
+ Some(ResolvedArg::EarlyBound(def_id)) => {
+ expected_captures.insert(def_id);
+ }
+ _ => {
+ tcx.dcx().span_delayed_bug(
+ tcx.hir().span(hir_id),
+ "parameter should have been resolved",
+ );
+ }
+ }
+ }
+
+ let variances = tcx.variances_of(opaque_def_id);
+ let mut def_id = Some(opaque_def_id.to_def_id());
+ while let Some(generics) = def_id {
+ let generics = tcx.generics_of(generics);
+ def_id = generics.parent;
+
+ for param in &generics.params {
+ if expected_captures.contains(¶m.def_id) {
+ assert_eq!(
+ variances[param.index as usize],
+ ty::Invariant,
+ "precise captured param should be invariant"
+ );
+ continue;
+ }
+
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => {
+ // Check if the lifetime param was captured but isn't named in the precise captures list.
+ if variances[param.index as usize] == ty::Invariant {
+ let param_span =
+ if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
+ | ty::ReLateParam(ty::LateParamRegion {
+ bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
+ ..
+ }) = *tcx
+ .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
+ {
+ Some(tcx.def_span(def_id))
+ } else {
+ None
+ };
+ // FIXME(precise_capturing): Structured suggestion for this would be useful
+ tcx.dcx().emit_err(errors::LifetimeNotCaptured {
+ use_span: tcx.def_span(param.def_id),
+ param_span,
+ opaque_span: tcx.def_span(opaque_def_id),
+ });
+ continue;
+ }
+ }
+ ty::GenericParamDefKind::Type { .. } => {
+ // FIXME(precise_capturing): Structured suggestion for this would be useful
+ tcx.dcx().emit_err(errors::ParamNotCaptured {
+ param_span: tcx.def_span(param.def_id),
+ opaque_span: tcx.def_span(opaque_def_id),
+ kind: "type",
+ });
+ }
+ ty::GenericParamDefKind::Const { .. } => {
+ // FIXME(precise_capturing): Structured suggestion for this would be useful
+ tcx.dcx().emit_err(errors::ParamNotCaptured {
+ param_span: tcx.def_span(param.def_id),
+ opaque_span: tcx.def_span(opaque_def_id),
+ kind: "const",
+ });
+ }
+ }
+ }
+ }
+}
+
fn is_enum_of_nonnullable_ptr<'tcx>(
tcx: TyCtxt<'tcx>,
adt_def: AdtDef<'tcx>,
@@ -499,7 +627,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
_ => true,
} {
- tcx.dcx().emit_err(LinkageType { span: tcx.def_span(def_id) });
+ tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) });
}
}
}
@@ -566,6 +694,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_union(tcx, def_id);
}
DefKind::OpaqueTy => {
+ check_opaque_precise_captures(tcx, def_id);
+
let origin = tcx.opaque_type_origin(def_id);
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index a668a1045757..d2759087cb47 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
use rustc_hir::{GenericParamKind, ImplItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, FulfillmentError};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -800,10 +800,10 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> {
bug!("FIXME(RPITIT): error here");
}
// Replace with infer var
- let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
- span: self.span,
- kind: TypeVariableOriginKind::MiscVariable,
- });
+ let infer_ty = self
+ .ocx
+ .infcx
+ .next_ty_var(TypeVariableOrigin { span: self.span, param_def_id: None });
self.types.insert(proj.def_id, (infer_ty, proj.args));
// Recurse into bounds
for (pred, pred_span) in self
diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs
index 548f9b0810fa..a49626eed35a 100644
--- a/compiler/rustc_hir_analysis/src/check/errs.rs
+++ b/compiler/rustc_hir_analysis/src/check/errs.rs
@@ -12,7 +12,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
let hir_id = expr.hir_id;
if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind
&& matches!(borrow_kind, hir::BorrowKind::Ref)
- && let Some(var) = is_path_static_mut(*expr)
+ && let Some(var) = path_if_static_mut(tcx, expr)
{
handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id);
}
@@ -24,7 +24,7 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
&& let hir::ByRef::Yes(rmutbl) = ba.0
&& let Some(init) = loc.init
- && let Some(var) = is_path_static_mut(*init)
+ && let Some(var) = path_if_static_mut(tcx, init)
{
handle_static_mut_ref(
tcx,
@@ -37,13 +37,13 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
}
}
-fn is_path_static_mut(expr: hir::Expr<'_>) -> Option {
+fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option {
if let hir::ExprKind::Path(qpath) = expr.kind
&& let hir::QPath::Resolved(_, path) = qpath
&& let hir::def::Res::Def(def_kind, _) = path.res
&& let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind
{
- return Some(qpath_to_string(&qpath));
+ return Some(qpath_to_string(&tcx, &qpath));
}
None
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 5e4048476561..0b6c60e4ba29 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -10,8 +10,8 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::{self, RegionResolutionError};
-use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
@@ -189,10 +189,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
// even if they do not carry that attribute.
use rustc_type_ir::TyKind::*;
match (source.kind(), target.kind()) {
- (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
- if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
- && mutbl_a == *mutbl_b =>
- {
+ (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if r_a == *r_b && mutbl_a == *mutbl_b => {
Ok(())
}
(&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
@@ -230,18 +227,14 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
}
}
- if let Ok(ok) =
- infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
- {
- if ok.obligations.is_empty() {
- res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
- span,
- name: field.name,
- ty: ty_a,
- }));
+ if ty_a == ty_b {
+ res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
+ span,
+ name: field.name,
+ ty: ty_a,
+ }));
- return false;
- }
+ return false;
}
return true;
@@ -433,14 +426,12 @@ pub fn coerce_unsized_info<'tcx>(
// something more accepting, but we use
// equality because we want to be able to
// perform this check without computing
- // variance where possible. (This is because
- // we may have to evaluate constraint
+ // variance or constraining opaque types' hidden types.
+ // (This is because we may have to evaluate constraint
// expressions in the course of execution.)
// See e.g., #41936.
- if let Ok(ok) = infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, a, b) {
- if ok.obligations.is_empty() {
- return None;
- }
+ if a == b {
+ return None;
}
// Collect up all fields that were significantly changed
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index efd3ceebe6ca..472657290ed1 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -37,7 +37,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
// from the trait itself that *shouldn't* be shown as the source of
// an obligation and instead be skipped. Otherwise we'd use
// `tcx.def_span(def_id);`
- let span = rustc_span::DUMMY_SP;
+ let span = DUMMY_SP;
result.predicates =
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 3d16f1420d99..a5f038d383d8 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -13,7 +13,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
use rustc_macros::extension;
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
@@ -107,7 +107,7 @@ enum Scope<'a> {
/// queried later. However, if we enter an elision scope, we have to
/// later append the elided bound vars to the list and need to know what
/// to append to.
- hir_id: hir::HirId,
+ hir_id: HirId,
s: ScopeRef<'a>,
@@ -557,6 +557,50 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}
+ fn visit_precise_capturing_arg(
+ &mut self,
+ arg: &'tcx hir::PreciseCapturingArg<'tcx>,
+ ) -> Self::Result {
+ match *arg {
+ hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
+ LifetimeName::Param(def_id) => {
+ self.resolve_lifetime_ref(def_id, lt);
+ }
+ LifetimeName::Error => {}
+ LifetimeName::ImplicitObjectLifetimeDefault
+ | LifetimeName::Infer
+ | LifetimeName::Static => {
+ self.tcx.dcx().emit_err(errors::BadPreciseCapture {
+ span: lt.ident.span,
+ kind: "lifetime",
+ found: format!("`{}`", lt.ident.name),
+ });
+ }
+ },
+ hir::PreciseCapturingArg::Param(param) => match param.res {
+ Res::Def(DefKind::TyParam | DefKind::ConstParam, def_id)
+ | Res::SelfTyParam { trait_: def_id } => {
+ self.resolve_type_ref(def_id.expect_local(), param.hir_id);
+ }
+ Res::Err => {}
+ Res::SelfTyAlias { alias_to, .. } => {
+ self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias {
+ span: param.ident.span,
+ self_span: self.tcx.def_span(alias_to),
+ what: self.tcx.def_descr(alias_to),
+ });
+ }
+ res => {
+ self.tcx.dcx().emit_err(errors::BadPreciseCapture {
+ span: param.ident.span,
+ kind: "type or const",
+ found: res.descr().to_string(),
+ });
+ }
+ },
+ }
+ }
+
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind {
hir::ForeignItemKind::Fn(_, _, generics) => {
@@ -781,7 +825,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}
- fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: hir::HirId) {
+ fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: HirId) {
for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
if let Some(args) = segment.args {
@@ -983,7 +1027,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
}
}
- fn record_late_bound_vars(&mut self, hir_id: hir::HirId, binder: Vec) {
+ fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec) {
if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
bug!(
"overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
@@ -1010,12 +1054,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
/// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
/// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the
/// ordering is not important there.
- fn visit_early_late(
- &mut self,
- hir_id: hir::HirId,
- generics: &'tcx hir::Generics<'tcx>,
- walk: F,
- ) where
+ fn visit_early_late(&mut self, hir_id: HirId, generics: &'tcx hir::Generics<'tcx>, walk: F)
+ where
F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
{
let mut named_late_bound_vars = 0;
@@ -1062,7 +1102,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.with(scope, walk);
}
- fn visit_early(&mut self, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F)
+ fn visit_early(&mut self, hir_id: HirId, generics: &'tcx hir::Generics<'tcx>, walk: F)
where
F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
{
@@ -1288,7 +1328,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
);
}
- fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: hir::HirId) {
+ fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: HirId) {
// Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the
// given name or we run out of scopes.
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d129614e0e1a..867ee772a30a 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -10,6 +10,9 @@ use rustc_span::{symbol::Ident, Span, Symbol};
mod pattern_types;
pub use pattern_types::*;
+mod precise_captures;
+pub(crate) use precise_captures::*;
+
#[derive(Diagnostic)]
#[diag(hir_analysis_ambiguous_assoc_item)]
pub struct AmbiguousAssocItem<'a> {
diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
new file mode 100644
index 000000000000..520bf1d9f404
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs
@@ -0,0 +1,63 @@
+use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_param_not_captured)]
+#[note]
+pub struct ParamNotCaptured {
+ #[primary_span]
+ pub param_span: Span,
+ #[label]
+ pub opaque_span: Span,
+ pub kind: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_lifetime_not_captured)]
+pub struct LifetimeNotCaptured {
+ #[primary_span]
+ pub use_span: Span,
+ #[label(hir_analysis_param_label)]
+ pub param_span: Option,
+ #[label]
+ pub opaque_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_bad_precise_capture)]
+pub struct BadPreciseCapture {
+ #[primary_span]
+ pub span: Span,
+ pub kind: &'static str,
+ pub found: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_precise_capture_self_alias)]
+pub struct PreciseCaptureSelfAlias {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub self_span: Span,
+ pub what: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_duplicate_precise_capture)]
+pub struct DuplicatePreciseCapture {
+ #[primary_span]
+ pub first_span: Span,
+ pub name: Symbol,
+ #[label]
+ pub second_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_lifetime_must_be_first)]
+pub struct LifetimesMustBeFirst {
+ #[primary_span]
+ pub lifetime_span: Span,
+ pub name: Symbol,
+ #[label]
+ pub other_span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index b15bf54234d0..0d5a295ca966 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -35,7 +35,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
-use rustc_hir::{GenericArg, GenericArgs};
+use rustc_hir::{GenericArg, GenericArgs, HirId};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
@@ -158,7 +158,7 @@ pub trait HirTyLowerer<'tcx> {
fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option>;
/// Record the lowered type of a HIR node in this context.
- fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
+ fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span);
/// The inference context of the lowering context if applicable.
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
@@ -999,7 +999,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
#[instrument(level = "debug", skip_all, ret)]
pub fn lower_assoc_path(
&self,
- hir_ref_id: hir::HirId,
+ hir_ref_id: HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself: &'tcx hir::Ty<'tcx>,
@@ -1200,7 +1200,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
segment: &hir::PathSegment<'tcx>,
adt_did: DefId,
self_ty: Ty<'tcx>,
- block: hir::HirId,
+ block: HirId,
span: Span,
) -> Result