Rollup merge of #125080 - bvanjoi:fix-124946, r=nnethercote
only find segs chain for missing methods when no available candidates
Fixes #124946
This PR includes two changes:
- Extracting the lookup for the missing method in chains into a single function.
- Calling this function only when there are no candidates available.
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index a048622..2cf811e 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -240,7 +240,6 @@ fn tokens(&self) -> Option<&LazyAttrTokenStream> {
Nonterminal::NtPath(path) => path.tokens(),
Nonterminal::NtVis(vis) => vis.tokens(),
Nonterminal::NtBlock(block) => block.tokens(),
- Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
@@ -254,7 +253,6 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(),
- Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
}
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0f12fd3..0684163 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -345,7 +345,7 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
Path { span, segments, tokens: None }
}
- Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 {
+ Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(path) => (**path).clone(),
_ => return None,
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 379c2e2..5c41622 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -781,10 +781,14 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
*span = ident.span;
return; // Avoid visiting the span for the second time.
}
+ token::NtIdent(ident, _is_raw) => {
+ vis.visit_ident(ident);
+ }
+ token::NtLifetime(ident) => {
+ vis.visit_ident(ident);
+ }
token::Interpolated(nt) => {
let nt = Lrc::make_mut(nt);
- let (nt, sp) = (&mut nt.0, &mut nt.1);
- vis.visit_span(sp);
visit_nonterminal(nt, vis);
}
_ => {}
@@ -834,8 +838,6 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
token::NtPat(pat) => vis.visit_pat(pat),
token::NtExpr(expr) => vis.visit_expr(expr),
token::NtTy(ty) => vis.visit_ty(ty),
- token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
- token::NtLifetime(ident) => vis.visit_ident(ident),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut();
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 72f8973..d00352e 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -111,7 +111,7 @@ pub fn from_token(token: &Token) -> Option<Lit> {
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
Literal(token_lit) => Some(token_lit),
Interpolated(ref nt)
- if let NtExpr(expr) | NtLiteral(expr) = &nt.0
+ if let NtExpr(expr) | NtLiteral(expr) = &**nt
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
{
Some(token_lit)
@@ -318,11 +318,20 @@ pub enum TokenKind {
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated identifiers in the same way.
Ident(Symbol, IdentIsRaw),
+ /// This identifier (and its span) is the identifier passed to the
+ /// declarative macro. The span in the surrounding `Token` is the span of
+ /// the `ident` metavariable in the macro's RHS.
+ NtIdent(Ident, IdentIsRaw),
+
/// Lifetime identifier token.
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated lifetime identifiers in the same way.
Lifetime(Symbol),
+ /// This identifier (and its span) is the lifetime passed to the
+ /// declarative macro. The span in the surrounding `Token` is the span of
+ /// the `lifetime` metavariable in the macro's RHS.
+ NtLifetime(Ident),
/// An embedded AST node, as produced by a macro. This only exists for
/// historical reasons. We'd like to get rid of it, for multiple reasons.
@@ -333,7 +342,11 @@ pub enum TokenKind {
/// - It prevents `Token` from implementing `Copy`.
/// It adds complexity and likely slows things down. Please don't add new
/// occurrences of this token kind!
- Interpolated(Lrc<(Nonterminal, Span)>),
+ ///
+ /// The span in the surrounding `Token` is that of the metavariable in the
+ /// macro's RHS. The span within the Nonterminal is that of the fragment
+ /// passed to the macro at the call site.
+ Interpolated(Lrc<Nonterminal>),
/// A doc comment token.
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
@@ -440,8 +453,9 @@ pub fn from_ast_ident(ident: Ident) -> Self {
/// Note that keywords are also identifiers, so they should use this
/// if they keep spans or perform edition checks.
pub fn uninterpolated_span(&self) -> Span {
- match &self.kind {
- Interpolated(nt) => nt.0.use_span(),
+ match self.kind {
+ NtIdent(ident, _) | NtLifetime(ident) => ident.span,
+ Interpolated(ref nt) => nt.use_span(),
_ => self.span,
}
}
@@ -459,7 +473,7 @@ pub fn is_punct(&self) -> bool {
}
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
- | Lifetime(..) | Interpolated(..) | Eof => false,
+ | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
}
}
@@ -486,7 +500,7 @@ pub fn can_begin_expr(&self) -> bool {
PathSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
- Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
+ Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
NtPath(..)),
@@ -510,7 +524,7 @@ pub fn can_begin_pattern(&self) -> bool {
| DotDot | DotDotDot | DotDotEq // ranges
| Lt | BinOp(Shl) // associated path
| PathSep => true, // global path
- Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
+ Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
NtPat(..) |
NtBlock(..) |
NtPath(..)),
@@ -533,7 +547,7 @@ pub fn can_begin_type(&self) -> bool {
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
PathSep => true, // global path
- Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
+ Interpolated(ref nt) => matches!(&**nt, 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
_ => false,
@@ -544,7 +558,7 @@ pub fn can_begin_type(&self) -> bool {
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
OpenDelim(Delimiter::Brace) => true,
- Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
+ Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
_ => self.can_begin_literal_maybe_minus(),
}
}
@@ -589,7 +603,7 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
match self.uninterpolate().kind {
Literal(..) | BinOp(Minus) => true,
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
- Interpolated(ref nt) => match &nt.0 {
+ Interpolated(ref nt) => match &**nt {
NtLiteral(_) => true,
NtExpr(e) => match &e.kind {
ast::ExprKind::Lit(_) => true,
@@ -609,14 +623,9 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
/// into the regular identifier or lifetime token it refers to,
/// otherwise returns the original token.
pub fn uninterpolate(&self) -> Cow<'_, Token> {
- match &self.kind {
- Interpolated(nt) => match &nt.0 {
- NtIdent(ident, is_raw) => {
- Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
- }
- NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
- _ => Cow::Borrowed(self),
- },
+ match self.kind {
+ NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)),
+ NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
}
}
@@ -625,12 +634,9 @@ pub fn uninterpolate(&self) -> Cow<'_, Token> {
#[inline]
pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
// We avoid using `Token::uninterpolate` here because it's slow.
- match &self.kind {
- &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
- Interpolated(nt) => match &nt.0 {
- NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
- _ => None,
- },
+ match self.kind {
+ Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
+ NtIdent(ident, is_raw) => Some((ident, is_raw)),
_ => None,
}
}
@@ -639,12 +645,9 @@ pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
#[inline]
pub fn lifetime(&self) -> Option<Ident> {
// We avoid using `Token::uninterpolate` here because it's slow.
- match &self.kind {
- &Lifetime(name) => Some(Ident::new(name, self.span)),
- Interpolated(nt) => match &nt.0 {
- NtLifetime(ident) => Some(*ident),
- _ => None,
- },
+ match self.kind {
+ Lifetime(name) => Some(Ident::new(name, self.span)),
+ NtLifetime(ident) => Some(ident),
_ => None,
}
}
@@ -668,7 +671,7 @@ pub fn is_ident_named(&self, name: Symbol) -> bool {
/// Returns `true` if the token is an interpolated path.
fn is_whole_path(&self) -> bool {
if let Interpolated(nt) = &self.kind
- && let NtPath(..) = &nt.0
+ && let NtPath(..) = &**nt
{
return true;
}
@@ -681,7 +684,7 @@ fn is_whole_path(&self) -> bool {
/// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool {
if let Interpolated(nt) = &self.kind
- && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0
+ && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt
{
return true;
}
@@ -692,7 +695,7 @@ pub fn is_whole_expr(&self) -> bool {
/// Is the token an interpolated block (`$b:block`)?
pub fn is_whole_block(&self) -> bool {
if let Interpolated(nt) = &self.kind
- && let NtBlock(..) = &nt.0
+ && let NtBlock(..) = &**nt
{
return true;
}
@@ -833,8 +836,10 @@ pub fn glue(&self, joint: &Token) -> Option<Token> {
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
| DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
- | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
- | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
+ | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
+ | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => {
+ return None;
+ }
};
Some(Token::new(kind, self.span.to(joint.span)))
@@ -857,8 +862,6 @@ pub enum Nonterminal {
NtPat(P<ast::Pat>),
NtExpr(P<ast::Expr>),
NtTy(P<ast::Ty>),
- NtIdent(Ident, IdentIsRaw),
- NtLifetime(Ident),
NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>),
@@ -953,7 +956,6 @@ pub fn use_span(&self) -> Span {
NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span,
NtTy(ty) => ty.span,
- NtIdent(ident, _) | NtLifetime(ident) => ident.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span,
NtVis(vis) => vis.span,
@@ -969,8 +971,6 @@ pub fn descr(&self) -> &'static str {
NtExpr(..) => "expression",
NtLiteral(..) => "literal",
NtTy(..) => "type",
- NtIdent(..) => "identifier",
- NtLifetime(..) => "lifetime",
NtMeta(..) => "attribute",
NtPath(..) => "path",
NtVis(..) => "visibility",
@@ -979,18 +979,12 @@ pub fn descr(&self) -> &'static str {
}
impl PartialEq for Nonterminal {
- fn eq(&self, rhs: &Self) -> bool {
- match (self, rhs) {
- (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
- ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
- }
- (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
- // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
- // correctly based on data from AST. This will prevent them from matching each other
- // in macros. The comparison will become possible only when each nonterminal has an
- // attached token stream from which it was parsed.
- _ => false,
- }
+ fn eq(&self, _rhs: &Self) -> bool {
+ // FIXME: Assume that all nonterminals are not equal, we can't compare them
+ // correctly based on data from AST. This will prevent them from matching each other
+ // in macros. The comparison will become possible only when each nonterminal has an
+ // attached token stream from which it was parsed.
+ false
}
}
@@ -1003,12 +997,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
NtPat(..) => f.pad("NtPat(..)"),
NtExpr(..) => f.pad("NtExpr(..)"),
NtTy(..) => f.pad("NtTy(..)"),
- NtIdent(..) => f.pad("NtIdent(..)"),
NtLiteral(..) => f.pad("NtLiteral(..)"),
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"),
NtVis(..) => f.pad("NtVis(..)"),
- NtLifetime(..) => f.pad("NtLifetime(..)"),
}
}
}
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 8e80161..fb66655 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -466,12 +466,6 @@ pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> To
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
match nt {
- Nonterminal::NtIdent(ident, is_raw) => {
- TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span)
- }
- Nonterminal::NtLifetime(ident) => {
- TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
- }
Nonterminal::NtItem(item) => TokenStream::from_ast(item),
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
@@ -489,15 +483,21 @@ pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
}
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
- match &token.kind {
- token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
+ match token.kind {
+ token::NtIdent(ident, is_raw) => {
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
}
- token::Interpolated(nt) => TokenTree::Delimited(
+ token::NtLifetime(ident) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
- TokenStream::from_nonterminal_ast(&nt.0).flattened(),
+ TokenStream::token_alone(token::Lifetime(ident.name), ident.span),
+ ),
+ token::Interpolated(ref nt) => TokenTree::Delimited(
+ DelimSpan::from_single(token.span),
+ DelimSpacing::new(Spacing::JointHidden, spacing),
+ Delimiter::Invisible,
+ TokenStream::from_nonterminal_ast(&nt).flattened(),
),
_ => TokenTree::Token(token.clone(), spacing),
}
@@ -516,7 +516,10 @@ fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
pub fn flattened(&self) -> TokenStream {
fn can_skip(stream: &TokenStream) -> bool {
stream.trees().all(|tree| match tree {
- TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)),
+ TokenTree::Token(token, _) => !matches!(
+ token.kind,
+ token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
+ ),
TokenTree::Delimited(.., inner) => can_skip(inner),
})
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index a769357..c23da8a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1407,7 +1407,7 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
bounds,
fn_kind,
itctx,
- precise_capturing.as_deref().map(|(args, _)| args.as_slice()),
+ precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)),
),
ImplTraitContext::Universal => {
if let Some(&(_, span)) = precise_capturing.as_deref() {
@@ -1523,7 +1523,7 @@ fn lower_opaque_impl_trait(
bounds: &GenericBounds,
fn_kind: Option<FnDeclKind>,
itctx: ImplTraitContext,
- precise_capturing_args: Option<&[PreciseCapturingArg]>,
+ precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
) -> 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
@@ -1533,7 +1533,7 @@ fn lower_opaque_impl_trait(
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
let captured_lifetimes_to_duplicate =
- if let Some(precise_capturing) = precise_capturing_args {
+ 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
@@ -1607,7 +1607,7 @@ fn lower_opaque_inner(
captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
span: Span,
opaque_ty_span: Span,
- precise_capturing_args: Option<&[PreciseCapturingArg]>,
+ precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def(
@@ -1698,8 +1698,11 @@ fn lower_opaque_inner(
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)
+ precise_capturing_args.map(|(precise_capturing, span)| {
+ (
+ this.lower_precise_capturing_args(precise_capturing),
+ this.lower_span(span),
+ )
}),
)
});
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index c41c7a3..defb666 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -858,8 +858,6 @@ fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
token::NtBlock(e) => self.block_to_string(e),
token::NtStmt(e) => self.stmt_to_string(e),
token::NtPat(e) => self.pat_to_string(e),
- &token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
- token::NtLifetime(e) => e.to_string(),
token::NtLiteral(e) => self.expr_to_string(e),
token::NtVis(e) => self.vis_to_string(e),
}
@@ -921,10 +919,14 @@ fn token_kind_to_string_ext(
token::Literal(lit) => literal_to_string(lit).into(),
/* Name components */
- token::Ident(s, is_raw) => {
- IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
+ token::Ident(name, is_raw) => {
+ IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
}
- token::Lifetime(s) => s.to_string().into(),
+ token::NtIdent(ident, is_raw) => {
+ IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
+ }
+ token::Lifetime(name) => name.to_string().into(),
+ token::NtLifetime(ident) => ident.name.to_string().into(),
/* Other */
token::DocComment(comment_kind, attr_style, data) => {
@@ -932,7 +934,7 @@ fn token_kind_to_string_ext(
}
token::Eof => "<eof>".into(),
- token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(),
+ token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
}
}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 897420a..67a5a91 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -201,10 +201,17 @@ fn can_skip(stream: &AttrTokenStream) -> bool {
inner = self.configure_tokens(&inner);
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
}
- AttrTokenTree::Token(ref token, _)
- if let TokenKind::Interpolated(nt) = &token.kind =>
- {
- panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
+ AttrTokenTree::Token(
+ Token {
+ kind:
+ TokenKind::NtIdent(..)
+ | TokenKind::NtLifetime(..)
+ | TokenKind::Interpolated(..),
+ ..
+ },
+ _,
+ ) => {
+ panic!("Nonterminal should have been flattened: {:?}", tree);
}
AttrTokenTree::Token(token, spacing) => {
Some(AttrTokenTree::Token(token, spacing)).into_iter()
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 464361c..3fee39d 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -73,12 +73,6 @@ pub(super) fn failed_to_match_macro<'cx>(
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|| matches!(token.kind, TokenKind::Interpolated(_)))
{
- if let TokenKind::Interpolated(node) = &expected_token.kind {
- err.span_label(node.1, "");
- }
- if let TokenKind::Interpolated(node) = &token.kind {
- err.span_label(node.1, "");
- }
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ffb50f4..27cf6fe 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -75,10 +75,9 @@
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
-use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
+use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorGuaranteed;
use rustc_lint_defs::pluralize;
use rustc_parse::parser::{ParseNtResult, Parser};
@@ -392,7 +391,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
#[derive(Debug, Clone)]
pub(crate) enum NamedMatch {
MatchedSeq(Vec<NamedMatch>),
- MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
+ MatchedSingle(ParseNtResult),
}
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@@ -686,11 +685,7 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
}
Ok(nt) => nt,
};
- mp.push_match(
- next_metavar,
- seq_depth,
- MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
- );
+ mp.push_match(next_metavar, seq_depth, MatchedSingle(nt));
mp.idx += 1;
} else {
unreachable!()
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 011aa95..e35eba0 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -261,6 +261,16 @@ pub(super) fn transcribe<'a>(
// without wrapping them into groups.
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
}
+ MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
+ marker.visit_span(&mut sp);
+ let kind = token::NtIdent(*ident, *is_raw);
+ TokenTree::token_alone(kind, sp)
+ }
+ MatchedSingle(ParseNtResult::Lifetime(ident)) => {
+ marker.visit_span(&mut sp);
+ let kind = token::NtLifetime(*ident);
+ TokenTree::token_alone(kind, sp)
+ }
MatchedSingle(ParseNtResult::Nt(nt)) => {
// Other variables are emitted into the output stream as groups with
// `Delimiter::Invisible` to maintain parsing priorities.
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 4b5c148..530059e 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -127,7 +127,7 @@ fn expand(
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
_ => unreachable!(),
};
- TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
+ TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
} else {
item.to_tokens()
};
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 5a66b0f..1f3547c 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -220,6 +220,12 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
Ident(sym, is_raw) => {
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
}
+ NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
+ sym: ident.name,
+ is_raw: is_raw.into(),
+ span: ident.span,
+ })),
+
Lifetime(name) => {
let ident = symbol::Ident::new(name, span).without_first_quote();
trees.extend([
@@ -227,6 +233,15 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
]);
}
+ NtLifetime(ident) => {
+ let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span);
+ trees.push(TokenTree::Group(Group {
+ delimiter: pm::Delimiter::None,
+ stream: Some(stream),
+ span: DelimSpan::from_single(span),
+ }))
+ }
+
Literal(token::Lit { kind, symbol, suffix }) => {
trees.push(TokenTree::Literal(self::Literal {
kind: FromInternal::from_internal(kind),
@@ -259,23 +274,15 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
}));
}
- Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
- trees.push(TokenTree::Ident(Ident {
- sym: ident.name,
- is_raw: matches!(is_raw, IdentIsRaw::Yes),
- span: ident.span,
- }))
- }
-
Interpolated(nt) => {
- let stream = TokenStream::from_nonterminal_ast(&nt.0);
+ let stream = TokenStream::from_nonterminal_ast(&nt);
// A hack used to pass AST fragments to attribute and derive
// macros as a single nonterminal token instead of a token
// stream. Such token needs to be "unwrapped" and not
// represented as a delimited group.
// FIXME: It needs to be removed, but there are some
// compatibility issues (see #73345).
- if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.ecx.sess) {
+ if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) {
trees.extend(Self::from_internal((stream, rustc)));
} else {
trees.push(TokenTree::Group(Group {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 7d991e2..6e4cef0 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2631,7 +2631,7 @@ pub struct OpaqueTy<'hir> {
/// 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>]>,
+ pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -2641,6 +2641,15 @@ pub enum PreciseCapturingArg<'hir> {
Param(PreciseCapturingNonLifetimeArg),
}
+impl PreciseCapturingArg<'_> {
+ pub fn hir_id(self) -> HirId {
+ match self {
+ PreciseCapturingArg::Lifetime(lt) => lt.hir_id,
+ PreciseCapturingArg::Param(param) => param.hir_id,
+ }
+ }
+}
+
/// 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`],
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 0b095db..664784c 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -533,7 +533,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
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 {
+ if let Some((precise_capturing_args, _)) = precise_capturing_args {
for arg in precise_capturing_args {
try_visit!(visitor.visit_precise_capturing_arg(arg));
}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 652c188..b5c0675 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -486,7 +486,7 @@ fn sanity_check_found_hidden_type<'tcx>(
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 {
+ let Some((precise_capturing_args, _)) = precise_capturing_args else {
// No precise capturing args; nothing to validate
return;
};
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 316a2bf..9e9a1f6 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -141,7 +141,10 @@ fn pointer_kind(
| ty::Never
| ty::Dynamic(_, _, ty::DynStar)
| ty::Error(_) => {
- self.dcx().span_bug(span, format!("`{t:?}` should be sized but is not?"));
+ let guar = self
+ .dcx()
+ .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?"));
+ return Err(guar);
}
})
}
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 676a7c2..5180fce 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -269,6 +269,17 @@
lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
+lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024
+ .note = specifically, {$num_captured ->
+ [one] this lifetime is
+ *[other] these lifetimes are
+ } in scope but not mentioned in the type's bounds
+ .note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+ .suggestion = use the precise capturing `use<...>` syntax to make the captures explicit
+
+lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+ .suggestion = remove the `use<...>` syntax
+
lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
.label = not FFI-safe
.note = the type is defined here
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
new file mode 100644
index 0000000..30bf80b
--- /dev/null
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -0,0 +1,425 @@
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::{Applicability, LintDiagnostic};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_macros::LintDiagnostic;
+use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
+use rustc_middle::ty::{
+ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
+use rustc_middle::{bug, span_bug};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::{sym, BytePos, Span};
+
+use crate::fluent_generated as fluent;
+use crate::{LateContext, LateLintPass};
+
+declare_lint! {
+ /// The `impl_trait_overcaptures` lint warns against cases where lifetime
+ /// capture behavior will differ in edition 2024.
+ ///
+ /// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope,
+ /// rather than just the lifetimes that are mentioned in the bounds of the type.
+ /// Often these sets are equal, but if not, it means that the `impl Trait` may
+ /// cause erroneous borrow-checker errors.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # #![feature(precise_capturing)]
+ /// # #![allow(incomplete_features)]
+ /// # #![deny(impl_trait_overcaptures)]
+ /// # use std::fmt::Display;
+ /// let mut x = vec![];
+ /// x.push(1);
+ ///
+ /// fn test(x: &Vec<i32>) -> impl Display {
+ /// x[0]
+ /// }
+ ///
+ /// let element = test(&x);
+ /// x.push(2);
+ /// println!("{element}");
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In edition < 2024, the returned `impl Display` doesn't capture the
+ /// lifetime from the `&Vec<i32>`, so the vector can be mutably borrowed
+ /// while the `impl Display` is live.
+ ///
+ /// To fix this, we can explicitly state that the `impl Display` doesn't
+ /// capture any lifetimes, using `impl use<> Display`.
+ pub IMPL_TRAIT_OVERCAPTURES,
+ Allow,
+ "`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
+ @feature_gate = sym::precise_capturing;
+ //@future_incompatible = FutureIncompatibleInfo {
+ // reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+ // reference: "<FIXME>",
+ //};
+}
+
+declare_lint! {
+ /// The `impl_trait_redundant_captures` lint warns against cases where use of the
+ /// precise capturing `use<...>` syntax is not needed.
+ ///
+ /// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope.
+ /// If precise-capturing `use<...>` syntax is used, and the set of parameters
+ /// that are captures are *equal* to the set of parameters in scope, then
+ /// the syntax is redundant, and can be removed.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
+ /// # #![allow(incomplete_features)]
+ /// # #![deny(impl_trait_redundant_captures)]
+ /// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// To fix this, remove the `use<'a>`, since the lifetime is already captured
+ /// since it is in scope.
+ pub IMPL_TRAIT_REDUNDANT_CAPTURES,
+ Warn,
+ "redundant precise-capturing `use<...>` syntax on an `impl Trait`",
+ @feature_gate = sym::precise_capturing;
+}
+
+declare_lint_pass!(
+ /// Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes
+ /// in edition 2024.
+ ImplTraitOvercaptures => [IMPL_TRAIT_OVERCAPTURES, IMPL_TRAIT_REDUNDANT_CAPTURES]
+);
+
+impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'tcx>) {
+ match &it.kind {
+ hir::ItemKind::Fn(..) => check_fn(cx.tcx, it.owner_id.def_id),
+ _ => {}
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::ImplItem<'tcx>) {
+ match &it.kind {
+ hir::ImplItemKind::Fn(_, _) => check_fn(cx.tcx, it.owner_id.def_id),
+ _ => {}
+ }
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::TraitItem<'tcx>) {
+ match &it.kind {
+ hir::TraitItemKind::Fn(_, _) => check_fn(cx.tcx, it.owner_id.def_id),
+ _ => {}
+ }
+ }
+}
+
+fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
+ let sig = tcx.fn_sig(parent_def_id).instantiate_identity();
+
+ let mut in_scope_parameters = FxIndexSet::default();
+ // Populate the in_scope_parameters list first with all of the generics in scope
+ let mut current_def_id = Some(parent_def_id.to_def_id());
+ while let Some(def_id) = current_def_id {
+ let generics = tcx.generics_of(def_id);
+ for param in &generics.own_params {
+ in_scope_parameters.insert(param.def_id);
+ }
+ current_def_id = generics.parent;
+ }
+
+ // Then visit the signature to walk through all the binders (incl. the late-bound
+ // vars on the function itself, which we need to count too).
+ sig.visit_with(&mut VisitOpaqueTypes {
+ tcx,
+ parent_def_id,
+ in_scope_parameters,
+ seen: Default::default(),
+ });
+}
+
+struct VisitOpaqueTypes<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ parent_def_id: LocalDefId,
+ in_scope_parameters: FxIndexSet<DefId>,
+ seen: FxIndexSet<LocalDefId>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
+ fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> Self::Result {
+ // When we get into a binder, we need to add its own bound vars to the scope.
+ let mut added = vec![];
+ for arg in t.bound_vars() {
+ let arg: ty::BoundVariableKind = arg;
+ match arg {
+ ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..))
+ | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => {
+ added.push(def_id);
+ let unique = self.in_scope_parameters.insert(def_id);
+ assert!(unique);
+ }
+ _ => {
+ self.tcx.dcx().span_delayed_bug(
+ self.tcx.def_span(self.parent_def_id),
+ format!("unsupported bound variable kind: {arg:?}"),
+ );
+ }
+ }
+ }
+
+ t.super_visit_with(self);
+
+ // And remove them. The `shift_remove` should be `O(1)` since we're popping
+ // them off from the end.
+ for arg in added.into_iter().rev() {
+ self.in_scope_parameters.shift_remove(&arg);
+ }
+ }
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+ if !t.has_aliases() {
+ return;
+ }
+
+ if let ty::Alias(ty::Projection, opaque_ty) = *t.kind()
+ && self.tcx.is_impl_trait_in_trait(opaque_ty.def_id)
+ {
+ // visit the opaque of the RPITIT
+ self.tcx
+ .type_of(opaque_ty.def_id)
+ .instantiate(self.tcx, opaque_ty.args)
+ .visit_with(self)
+ } else if let ty::Alias(ty::Opaque, opaque_ty) = *t.kind()
+ && let Some(opaque_def_id) = opaque_ty.def_id.as_local()
+ // Don't recurse infinitely on an opaque
+ && self.seen.insert(opaque_def_id)
+ // If it's owned by this function
+ && let opaque =
+ self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty()
+ && let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
+ && parent_def_id == self.parent_def_id
+ {
+ // Compute the set of args that are captured by the opaque...
+ let mut captured = FxIndexSet::default();
+ let variances = self.tcx.variances_of(opaque_def_id);
+ let mut current_def_id = Some(opaque_def_id.to_def_id());
+ while let Some(def_id) = current_def_id {
+ let generics = self.tcx.generics_of(def_id);
+ for param in &generics.own_params {
+ // A param is captured if it's invariant.
+ if variances[param.index as usize] != ty::Invariant {
+ continue;
+ }
+ // We need to turn all `ty::Param`/`ConstKind::Param` and
+ // `ReEarlyParam`/`ReBound` into def ids.
+ captured.insert(extract_def_id_from_arg(
+ self.tcx,
+ generics,
+ opaque_ty.args[param.index as usize],
+ ));
+ }
+ current_def_id = generics.parent;
+ }
+
+ // Compute the set of in scope params that are not captured. Get their spans,
+ // since that's all we really care about them for emitting the diagnostic.
+ let uncaptured_spans: Vec<_> = self
+ .in_scope_parameters
+ .iter()
+ .filter(|def_id| !captured.contains(*def_id))
+ .map(|def_id| self.tcx.def_span(def_id))
+ .collect();
+
+ let opaque_span = self.tcx.def_span(opaque_def_id);
+ let new_capture_rules =
+ opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024;
+
+ // If we have uncaptured args, and if the opaque doesn't already have
+ // `use<>` syntax on it, and we're < edition 2024, then warn the user.
+ if !new_capture_rules
+ && opaque.precise_capturing_args.is_none()
+ && !uncaptured_spans.is_empty()
+ {
+ let suggestion = if let Ok(snippet) =
+ self.tcx.sess.source_map().span_to_snippet(opaque_span)
+ && snippet.starts_with("impl ")
+ {
+ let (lifetimes, others): (Vec<_>, Vec<_>) = captured
+ .into_iter()
+ .partition(|def_id| self.tcx.def_kind(*def_id) == DefKind::LifetimeParam);
+ // Take all lifetime params first, then all others (ty/ct).
+ let generics: Vec<_> = lifetimes
+ .into_iter()
+ .chain(others)
+ .map(|def_id| self.tcx.item_name(def_id).to_string())
+ .collect();
+ // Make sure that we're not trying to name any APITs
+ if generics.iter().all(|name| !name.starts_with("impl ")) {
+ Some((
+ format!(" use<{}>", generics.join(", ")),
+ opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(),
+ ))
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+
+ self.tcx.emit_node_span_lint(
+ IMPL_TRAIT_OVERCAPTURES,
+ self.tcx.local_def_id_to_hir_id(opaque_def_id),
+ opaque_span,
+ ImplTraitOvercapturesLint {
+ self_ty: t,
+ num_captured: uncaptured_spans.len(),
+ uncaptured_spans,
+ suggestion,
+ },
+ );
+ }
+ // Otherwise, if we are edition 2024, have `use<>` syntax, and
+ // have no uncaptured args, then we should warn to the user that
+ // it's redundant to capture all args explicitly.
+ else if new_capture_rules
+ && let Some((captured_args, capturing_span)) = opaque.precise_capturing_args
+ {
+ let mut explicitly_captured = UnordSet::default();
+ for arg in captured_args {
+ match self.tcx.named_bound_var(arg.hir_id()) {
+ Some(
+ ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id),
+ ) => {
+ if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy {
+ let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
+ | ty::ReLateParam(ty::LateParamRegion {
+ bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
+ ..
+ })) = self
+ .tcx
+ .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
+ .kind()
+ else {
+ span_bug!(
+ self.tcx.def_span(def_id),
+ "variable should have been duplicated from a parent"
+ );
+ };
+ explicitly_captured.insert(def_id);
+ } else {
+ explicitly_captured.insert(def_id);
+ }
+ }
+ _ => {
+ self.tcx.dcx().span_delayed_bug(
+ self.tcx.hir().span(arg.hir_id()),
+ "no valid for captured arg",
+ );
+ }
+ }
+ }
+
+ if self
+ .in_scope_parameters
+ .iter()
+ .all(|def_id| explicitly_captured.contains(def_id))
+ {
+ self.tcx.emit_node_span_lint(
+ IMPL_TRAIT_REDUNDANT_CAPTURES,
+ self.tcx.local_def_id_to_hir_id(opaque_def_id),
+ opaque_span,
+ ImplTraitRedundantCapturesLint { capturing_span },
+ );
+ }
+ }
+
+ // Walk into the bounds of the opaque, too, since we want to get nested opaques
+ // in this lint as well. Interestingly, one place that I expect this lint to fire
+ // is for `impl for<'a> Bound<Out = impl Other>`, since `impl Other` will begin
+ // to capture `'a` in e2024 (even though late-bound vars in opaques are not allowed).
+ for clause in
+ self.tcx.item_bounds(opaque_ty.def_id).iter_instantiated(self.tcx, opaque_ty.args)
+ {
+ clause.visit_with(self)
+ }
+ }
+
+ t.super_visit_with(self);
+ }
+}
+
+struct ImplTraitOvercapturesLint<'tcx> {
+ uncaptured_spans: Vec<Span>,
+ self_ty: Ty<'tcx>,
+ num_captured: usize,
+ suggestion: Option<(String, Span)>,
+}
+
+impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
+ diag.arg("self_ty", self.self_ty.to_string())
+ .arg("num_captured", self.num_captured)
+ .span_note(self.uncaptured_spans, fluent::lint_note)
+ .note(fluent::lint_note2);
+ if let Some((suggestion, span)) = self.suggestion {
+ diag.span_suggestion(
+ span,
+ fluent::lint_suggestion,
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ fn msg(&self) -> rustc_errors::DiagMessage {
+ fluent::lint_impl_trait_overcaptures
+ }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_impl_trait_redundant_captures)]
+struct ImplTraitRedundantCapturesLint {
+ #[suggestion(lint_suggestion, code = "", applicability = "machine-applicable")]
+ capturing_span: Span,
+}
+
+fn extract_def_id_from_arg<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx ty::Generics,
+ arg: ty::GenericArg<'tcx>,
+) -> DefId {
+ match arg.unpack() {
+ ty::GenericArgKind::Lifetime(re) => match *re {
+ ty::ReEarlyParam(ebr) => generics.region_param(ebr, tcx).def_id,
+ ty::ReBound(
+ _,
+ ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, ..), .. },
+ ) => def_id,
+ _ => unreachable!(),
+ },
+ ty::GenericArgKind::Type(ty) => {
+ let ty::Param(param_ty) = *ty.kind() else {
+ bug!();
+ };
+ generics.type_param(param_ty, tcx).def_id
+ }
+ ty::GenericArgKind::Const(ct) => {
+ let ty::ConstKind::Param(param_ct) = ct.kind() else {
+ bug!();
+ };
+ generics.const_param(param_ct, tcx).def_id
+ }
+ }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index a78b410..d93edad 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,6 +55,7 @@
mod for_loops_over_fallibles;
mod foreign_modules;
pub mod hidden_unicode_codepoints;
+mod impl_trait_overcaptures;
mod internal;
mod invalid_from_utf8;
mod late;
@@ -94,6 +95,7 @@
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
use for_loops_over_fallibles::*;
use hidden_unicode_codepoints::*;
+use impl_trait_overcaptures::ImplTraitOvercaptures;
use internal::*;
use invalid_from_utf8::*;
use let_underscore::*;
@@ -228,6 +230,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
MissingDoc: MissingDoc,
AsyncFnInTrait: AsyncFnInTrait,
NonLocalDefinitions: NonLocalDefinitions::default(),
+ ImplTraitOvercaptures: ImplTraitOvercaptures,
]
]
);
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index 2ddcb8a..9e94489 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -153,6 +153,8 @@ pub enum ProbeKind<'tcx> {
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
UpcastProjectionCompatibility,
+ /// Looking for param-env candidates that satisfy the trait ref for a projection.
+ ShadowedEnvProbing,
/// Try to unify an opaque type with an existing key in the storage.
OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index e652f05..5b3c50c 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -118,6 +118,9 @@ pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
ProbeKind::TraitCandidate { source, result } => {
write!(self.f, "CANDIDATE {source:?}: {result:?}")
}
+ ProbeKind::ShadowedEnvProbing => {
+ write!(self.f, "PROBING FOR IMPLS SHADOWED BY PARAM-ENV CANDIDATE:")
+ }
}?;
self.nested(|this| {
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index d5d8060..a57eb70 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -363,7 +363,7 @@ pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
// We can't use `maybe_whole` here because it would bump in the `None`
// case, which we don't want.
if let token::Interpolated(nt) = &self.token.kind
- && let token::NtMeta(attr_item) = &nt.0
+ && let token::NtMeta(attr_item) = &**nt
{
match attr_item.meta(attr_item.path.span) {
Some(meta) => {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 50698db..63762f6 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2372,9 +2372,9 @@ pub(super) fn expected_expression_found(&self) -> Diag<'a> {
// in a subsequent macro invocation (#71039).
let mut tok = self.token.clone();
let mut labels = vec![];
- while let TokenKind::Interpolated(node) = &tok.kind {
- let tokens = node.0.tokens();
- labels.push(node.clone());
+ while let TokenKind::Interpolated(nt) = &tok.kind {
+ let tokens = nt.tokens();
+ labels.push(nt.clone());
if let Some(tokens) = tokens
&& let tokens = tokens.to_attr_token_stream()
&& let tokens = tokens.0.deref()
@@ -2387,27 +2387,20 @@ pub(super) fn expected_expression_found(&self) -> Diag<'a> {
}
let mut iter = labels.into_iter().peekable();
let mut show_link = false;
- while let Some(node) = iter.next() {
- let descr = node.0.descr();
+ while let Some(nt) = iter.next() {
+ let descr = nt.descr();
if let Some(next) = iter.peek() {
- let next_descr = next.0.descr();
+ let next_descr = next.descr();
if next_descr != descr {
- err.span_label(next.1, format!("this macro fragment matcher is {next_descr}"));
- err.span_label(node.1, format!("this macro fragment matcher is {descr}"));
+ err.span_label(next.use_span(), format!("this is expected to be {next_descr}"));
err.span_label(
- next.0.use_span(),
- format!("this is expected to be {next_descr}"),
- );
- err.span_label(
- node.0.use_span(),
+ nt.use_span(),
format!(
"this is interpreted as {}, but it is expected to be {}",
next_descr, descr,
),
);
show_link = true;
- } else {
- err.span_label(node.1, "");
}
}
}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 441aa5b..cbc7ce9 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -45,7 +45,7 @@
macro_rules! maybe_whole_expr {
($p:expr) => {
if let token::Interpolated(nt) = &$p.token.kind {
- match &nt.0 {
+ match &**nt {
token::NtExpr(e) | token::NtLiteral(e) => {
let e = e.clone();
$p.bump();
@@ -724,7 +724,9 @@ fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
match self.prev_token.kind {
- TokenKind::Interpolated(..) => self.prev_token.span,
+ TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => {
+ self.prev_token.span
+ }
_ => expr.span,
}
}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index df6996d..29957bd 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2841,7 +2841,7 @@ fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
fn is_named_param(&self) -> bool {
let offset = match &self.token.kind {
- token::Interpolated(nt) => match &nt.0 {
+ token::Interpolated(nt) => match &**nt {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
_ => 0,
},
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index bfb6c4a..3e0a98a 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -11,7 +11,6 @@
mod ty;
use crate::lexer::UnmatchedDelim;
-use ast::token::IdentIsRaw;
pub use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery;
pub(crate) use expr::ForbiddenLetReason;
@@ -21,7 +20,7 @@
use core::fmt;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
use rustc_ast::util::case::Case;
@@ -32,6 +31,7 @@
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -107,7 +107,7 @@ pub enum TrailingToken {
macro_rules! maybe_whole {
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
if let token::Interpolated(nt) = &$p.token.kind
- && let token::$constructor(x) = &nt.0
+ && let token::$constructor(x) = &**nt
{
#[allow(unused_mut)]
let mut $x = x.clone();
@@ -125,7 +125,7 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
&& $self.may_recover()
&& $self.look_ahead(1, |t| t == &token::PathSep)
&& let token::Interpolated(nt) = &$self.token.kind
- && let token::NtTy(ty) = &nt.0
+ && let token::NtTy(ty) = &**nt
{
let ty = ty.clone();
$self.bump();
@@ -407,7 +407,9 @@ pub(super) fn token_descr(token: &Token) -> String {
(Some(TokenDescription::Keyword), _) => Some("keyword"),
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
- (None, TokenKind::Interpolated(node)) => Some(node.0.descr()),
+ (None, TokenKind::NtIdent(..)) => Some("identifier"),
+ (None, TokenKind::NtLifetime(..)) => Some("lifetime"),
+ (None, TokenKind::Interpolated(node)) => Some(node.descr()),
(None, _) => None,
};
@@ -708,7 +710,7 @@ fn check_const_closure(&self) -> bool {
fn check_inline_const(&self, dist: usize) -> bool {
self.is_keyword_ahead(dist, &[kw::Const])
&& self.look_ahead(dist + 1, |t| match &t.kind {
- token::Interpolated(nt) => matches!(&nt.0, token::NtBlock(..)),
+ token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)),
token::OpenDelim(Delimiter::Brace) => true,
_ => false,
})
@@ -1631,19 +1633,11 @@ pub enum FlatToken {
// Metavar captures of various kinds.
#[derive(Clone, Debug)]
-pub enum ParseNtResult<NtType> {
+pub enum ParseNtResult {
Tt(TokenTree),
- Nt(NtType),
-}
+ Ident(Ident, IdentIsRaw),
+ Lifetime(Ident),
-impl<T> ParseNtResult<T> {
- pub fn map_nt<F, U>(self, mut f: F) -> ParseNtResult<U>
- where
- F: FnMut(T) -> U,
- {
- match self {
- ParseNtResult::Tt(tt) => ParseNtResult::Tt(tt),
- ParseNtResult::Nt(nt) => ParseNtResult::Nt(f(nt)),
- }
- }
+ /// This case will eventually be removed, along with `Token::Interpolate`.
+ Nt(Lrc<Nonterminal>),
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 73b1735..a6f0ab7 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,7 +1,8 @@
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, NonterminalKind, Token};
+use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
use rustc_ast::HasTokens;
use rustc_ast_pretty::pprust;
+use rustc_data_structures::sync::Lrc;
use rustc_errors::PResult;
use rustc_span::symbol::{kw, Ident};
@@ -24,15 +25,13 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
| NtPat(_)
| NtExpr(_)
| NtTy(_)
- | NtIdent(..)
| NtLiteral(_) // `true`, `false`
| NtMeta(_)
| NtPath(_) => true,
NtItem(_)
| NtBlock(_)
- | NtVis(_)
- | NtLifetime(_) => false,
+ | NtVis(_) => false,
}
}
@@ -49,25 +48,30 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
NonterminalKind::Vis => match token.kind {
// The follow-set of :vis + "priv" keyword + interpolated
- token::Comma | token::Ident(..) | token::Interpolated(_) => true,
+ token::Comma
+ | token::Ident(..)
+ | token::NtIdent(..)
+ | token::NtLifetime(..)
+ | token::Interpolated(_) => true,
_ => token.can_begin_type(),
},
NonterminalKind::Block => match &token.kind {
token::OpenDelim(Delimiter::Brace) => true,
- token::Interpolated(nt) => match &nt.0 {
- NtBlock(_) | NtLifetime(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
- NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_)
- | NtVis(_) => false,
+ token::NtLifetime(..) => true,
+ token::Interpolated(nt) => match &**nt {
+ NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
+ NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
},
_ => false,
},
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
- token::PathSep | token::Ident(..) => true,
- token::Interpolated(nt) => may_be_ident(&nt.0),
+ token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
+ token::Interpolated(nt) => may_be_ident(nt),
_ => false,
},
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
- token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
+ // box, ref, mut, and other identifiers (can stricten)
+ token::Ident(..) | token::NtIdent(..) |
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
token::OpenDelim(Delimiter::Bracket) | // slice pattern
token::BinOp(token::And) | // reference
@@ -81,14 +85,11 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
token::BinOp(token::Shl) => true, // path (double UFCS)
// leading vert `|` or-pattern
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
- token::Interpolated(nt) => may_be_ident(&nt.0),
+ token::Interpolated(nt) => may_be_ident(nt),
_ => false,
},
NonterminalKind::Lifetime => match &token.kind {
- token::Lifetime(_) => true,
- token::Interpolated(nt) => {
- matches!(&nt.0, NtLifetime(_))
- }
+ token::Lifetime(_) | token::NtLifetime(..) => true,
_ => false,
},
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
@@ -100,10 +101,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
/// site.
#[inline]
- pub fn parse_nonterminal(
- &mut self,
- kind: NonterminalKind,
- ) -> PResult<'a, ParseNtResult<Nonterminal>> {
+ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> {
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
// which requires having captured tokens available. Since we cannot determine
// in advance whether or not a proc-macro will be (transitively) invoked,
@@ -156,15 +154,16 @@ pub fn parse_nonterminal(
}
// this could be handled like a token, since it is one
- NonterminalKind::Ident if let Some((ident, is_raw)) = get_macro_ident(&self.token) => {
- self.bump();
- NtIdent(ident, is_raw)
- }
NonterminalKind::Ident => {
- return Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
- span: self.token.span,
- token: self.token.clone(),
- }));
+ return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
+ self.bump();
+ Ok(ParseNtResult::Ident(ident, is_raw))
+ } else {
+ Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
+ span: self.token.span,
+ token: self.token.clone(),
+ }))
+ };
}
NonterminalKind::Path => {
NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
@@ -175,14 +174,14 @@ pub fn parse_nonterminal(
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
}
NonterminalKind::Lifetime => {
- if self.check_lifetime() {
- NtLifetime(self.expect_lifetime().ident)
+ return if self.check_lifetime() {
+ Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
} else {
- return Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
+ Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
span: self.token.span,
token: self.token.clone(),
- }));
- }
+ }))
+ };
}
};
@@ -196,7 +195,7 @@ pub fn parse_nonterminal(
);
}
- Ok(ParseNtResult::Nt(nt))
+ Ok(ParseNtResult::Nt(Lrc::new(nt)))
}
}
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 78d3d01..8af415f 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -757,7 +757,7 @@ fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
if let token::Interpolated(nt) = &self.token.kind {
- if let token::NtPat(..) = &nt.0 {
+ if let token::NtPat(..) = &**nt {
self.expected_ident_found_err().emit();
}
}
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 3636a35..c37d3f0 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -193,7 +193,7 @@ pub(super) fn parse_path_inner(
maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
if let token::Interpolated(nt) = &self.token.kind {
- if let token::NtTy(ty) = &nt.0 {
+ if let token::NtTy(ty) = &**nt {
if let ast::TyKind::Path(None, path) = &ty.kind {
let path = path.clone();
self.bump();
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 7096b20..2f08a48 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -675,8 +675,8 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
let precise_capturing = if self.eat_keyword(kw::Use) {
let use_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
- let args = self.parse_precise_capturing_args()?;
- Some(P((args, use_span)))
+ let (args, args_span) = self.parse_precise_capturing_args()?;
+ Some(P((args, use_span.to(args_span))))
} else {
None
};
@@ -689,32 +689,34 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing))
}
- fn parse_precise_capturing_args(&mut self) -> PResult<'a, ThinVec<PreciseCapturingArg>> {
- Ok(self
- .parse_unspanned_seq(
- &TokenKind::Lt,
- &TokenKind::Gt,
- SeqSep::trailing_allowed(token::Comma),
- |self_| {
- if self_.check_keyword(kw::SelfUpper) {
- self_.bump();
- Ok(PreciseCapturingArg::Arg(
- ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
- DUMMY_NODE_ID,
- ))
- } else if self_.check_ident() {
- Ok(PreciseCapturingArg::Arg(
- ast::Path::from_ident(self_.parse_ident()?),
- DUMMY_NODE_ID,
- ))
- } else if self_.check_lifetime() {
- Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
- } else {
- self_.unexpected_any()
- }
- },
- )?
- .0)
+ fn parse_precise_capturing_args(
+ &mut self,
+ ) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> {
+ let lo = self.token.span;
+ let (args, _) = self.parse_unspanned_seq(
+ &TokenKind::Lt,
+ &TokenKind::Gt,
+ SeqSep::trailing_allowed(token::Comma),
+ |self_| {
+ if self_.check_keyword(kw::SelfUpper) {
+ self_.bump();
+ Ok(PreciseCapturingArg::Arg(
+ ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
+ DUMMY_NODE_ID,
+ ))
+ } else if self_.check_ident() {
+ Ok(PreciseCapturingArg::Arg(
+ ast::Path::from_ident(self_.parse_ident()?),
+ DUMMY_NODE_ID,
+ ))
+ } else if self_.check_lifetime() {
+ Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
+ } else {
+ self_.unexpected_any()
+ }
+ },
+ )?;
+ Ok((args, lo.to(self.prev_token.span)))
}
/// Is a `dyn B0 + ... + Bn` type allowed here?
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8307803..8ba945e 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1774,6 +1774,9 @@ fn $module() {
("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
("x86_64-unknown-linux-ohos", x86_64_unknown_linux_ohos),
+
+ ("x86_64-unknown-linux-none", x86_64_unknown_linux_none),
+
}
/// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
new file mode 100644
index 0000000..b6e331b
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
@@ -0,0 +1,25 @@
+use crate::spec::{base, Cc, LinkerFlavor, Lld, StackProbeType, Target};
+
+pub fn target() -> Target {
+ let mut base = base::linux::opts();
+ base.cpu = "x86-64".into();
+ base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
+ base.linker_flavor = LinkerFlavor::Gnu(Cc::No, Lld::Yes);
+ base.linker = Some("rust-lld".into());
+
+ Target {
+ llvm_target: "x86_64-unknown-linux-none".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: None,
+ tier: None,
+ host_tools: None,
+ std: None,
+ },
+ pointer_width: 64,
+ data_layout:
+ "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+ arch: "x86_64".into(),
+ options: base,
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 9a027d7..97bea28 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -1,7 +1,7 @@
//! Code shared by trait and projection goals for candidate assembly.
use crate::solve::GoalSource;
-use crate::solve::{inspect, EvalCtxt, SolverMode};
+use crate::solve::{EvalCtxt, SolverMode};
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::bug;
@@ -16,7 +16,6 @@
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
use std::fmt::Debug;
-use std::mem;
pub(super) mod structural_traits;
@@ -792,17 +791,16 @@ fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>(
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
) {
- // HACK: We temporarily remove the `ProofTreeBuilder` to
- // avoid adding `Trait` candidates to the candidates used
- // to prove the current goal.
- let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop());
-
let tcx = self.tcx();
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
goal.with(tcx, goal.predicate.trait_ref(tcx));
- let mut trait_candidates_from_env = Vec::new();
- self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
- self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
+
+ let mut trait_candidates_from_env = vec![];
+ self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
+ ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
+ ecx.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
+ });
+
if !trait_candidates_from_env.is_empty() {
let trait_env_result = self.merge_candidates(trait_candidates_from_env);
match trait_env_result.unwrap().value.certainty {
@@ -831,7 +829,6 @@ fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>(
}
}
}
- self.inspect = inspect;
}
/// If there are multiple ways to prove a trait or projection goal, we have
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 6fda5f4..68c0c8b 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -176,7 +176,8 @@ fn to_selection<'tcx>(
| ProbeKind::UnsizeAssembly
| ProbeKind::UpcastProjectionCompatibility
| ProbeKind::OpaqueTypeStorageLookup { result: _ }
- | ProbeKind::Root { result: _ } => {
+ | ProbeKind::Root { result: _ }
+ | ProbeKind::ShadowedEnvProbing => {
span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
}
})
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index fd36b7f..b71a1b3 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -18,8 +18,8 @@
use rustc_middle::traits::solve::{inspect, QueryResult};
use rustc_middle::traits::solve::{Certainty, Goal};
use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty;
use rustc_middle::ty::TypeFoldable;
+use rustc_middle::{bug, ty};
use rustc_span::{Span, DUMMY_SP};
use crate::solve::eval_ctxt::canonical;
@@ -290,12 +290,25 @@ fn candidates_recur(
match *step {
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
inspect::ProbeStep::NestedProbe(ref probe) => {
- // Nested probes have to prove goals added in their parent
- // but do not leak them, so we truncate the added goals
- // afterwards.
- let num_goals = nested_goals.len();
- self.candidates_recur(candidates, nested_goals, probe);
- nested_goals.truncate(num_goals);
+ match probe.kind {
+ // These never assemble candidates for the goal we're trying to solve.
+ inspect::ProbeKind::UpcastProjectionCompatibility
+ | inspect::ProbeKind::ShadowedEnvProbing => continue,
+
+ inspect::ProbeKind::NormalizedSelfTyAssembly
+ | inspect::ProbeKind::UnsizeAssembly
+ | inspect::ProbeKind::Root { .. }
+ | inspect::ProbeKind::TryNormalizeNonRigid { .. }
+ | inspect::ProbeKind::TraitCandidate { .. }
+ | inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => {
+ // Nested probes have to prove goals added in their parent
+ // but do not leak them, so we truncate the added goals
+ // afterwards.
+ let num_goals = nested_goals.len();
+ self.candidates_recur(candidates, nested_goals, probe);
+ nested_goals.truncate(num_goals);
+ }
+ }
}
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
assert_eq!(shallow_certainty.replace(c), None);
@@ -308,9 +321,10 @@ fn candidates_recur(
}
match probe.kind {
- inspect::ProbeKind::NormalizedSelfTyAssembly
- | inspect::ProbeKind::UnsizeAssembly
- | inspect::ProbeKind::UpcastProjectionCompatibility => (),
+ inspect::ProbeKind::UpcastProjectionCompatibility
+ | inspect::ProbeKind::ShadowedEnvProbing => bug!(),
+
+ inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
// We add a candidate even for the root evaluation if there
// is only one way to prove a given goal, e.g. for `WellFormed`.
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 8d7192c..f87b6bb 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -63,11 +63,39 @@
//!
//! ## Allocated object
//!
-//! For several operations, such as [`offset`] or field projections (`expr.field`), the notion of an
-//! "allocated object" becomes relevant. An allocated object is a contiguous region of memory.
-//! Common examples of allocated objects include stack-allocated variables (each variable is a
-//! separate allocated object), heap allocations (each allocation created by the global allocator is
-//! a separate allocated object), and `static` variables.
+//! An *allocated object* is a subset of program memory which is addressable
+//! from Rust, and within which pointer arithmetic is possible. Examples of
+//! allocated objects include heap allocations, stack-allocated variables,
+//! statics, and consts. The safety preconditions of some Rust operations -
+//! such as `offset` and field projections (`expr.field`) - are defined in
+//! terms of the allocated objects on which they operate.
+//!
+//! An allocated object has a base address, a size, and a set of memory
+//! addresses. It is possible for an allocated object to have zero size, but
+//! such an allocated object will still have a base address. The base address
+//! of an allocated object is not necessarily unique. While it is currently the
+//! case that an allocated object always has a set of memory addresses which is
+//! fully contiguous (i.e., has no "holes"), there is no guarantee that this
+//! will not change in the future.
+//!
+//! For any allocated object with `base` address, `size`, and a set of
+//! `addresses`, the following are guaranteed:
+//! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
+//! size)` (note that this requires `a < base + size`, not `a <= base + size`)
+//! - `base` is not equal to [`null()`] (i.e., the address with the numerical
+//! value 0)
+//! - `base + size <= usize::MAX`
+//! - `size <= isize::MAX`
+//!
+//! As a consequence of these guarantees, given any address `a` within the set
+//! of addresses of an allocated object:
+//! - It is guaranteed that `a - base` does not overflow `isize`
+//! - It is guaranteed that `a - base` is non-negative
+//! - It is guaranteed that, given `o = a - base` (i.e., the offset of `a` within
+//! the allocated object), `base + o` will not wrap around the address space (in
+//! other words, will not overflow `usize`)
+//!
+//! [`null()`]: null
//!
//! # Strict Provenance
//!
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index c9c0ee4..c7e3293 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -74,6 +74,7 @@
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
- [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
- [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
+ - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md)
- [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
- [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md)
- [Targets](targets/index.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 764798a..8adc410 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -382,5 +382,6 @@
[`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 64-bit Windows 7 support
`x86_64-wrs-vxworks` | ? | |
[`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
+[`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc
[runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 9c2e05b..3e1db69 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -387,7 +387,7 @@
```
*Note: Relative manifest paths are resolved starting from the working directory
-of `pm`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
+of `ffx`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
SDK.*
The `.manifest` file will be used to describe the contents of the package by
@@ -459,12 +459,10 @@
Next, we'll build a package manifest as defined by our manifest:
```sh
-${SDK_PATH}/tools/${ARCH}/pm \
- -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 | awk -F ' ' '{print $2}') \
- -o pkg/hello_fuchsia_manifest \
- -m pkg/hello_fuchsia.manifest \
- build \
- -output-package-manifest pkg/hello_fuchsia_package_manifest
+${SDK_PATH}/tools/${ARCH}/ffx package build \
+ --api-level $(${SDK_PATH}/tools/${ARCH}/ffx --machine json version | jq .tool_version.api_level) \
+ --out pkg/hello_fuchsia_manifest \
+ pkg/hello_fuchsia.manifest
```
This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
@@ -498,8 +496,7 @@
We can set up our repository with:
```sh
-${SDK_PATH}/tools/${ARCH}/pm newrepo \
- -repo pkg/repo
+${SDK_PATH}/tools/${ARCH}/ffx repository create pkg/repo
```
**Current directory structure**
@@ -523,17 +520,17 @@
We can publish our new package to that repository with:
```sh
-${SDK_PATH}/tools/${ARCH}/pm publish \
- -repo pkg/repo \
- -lp -f <(echo "pkg/hello_fuchsia_package_manifest")
+${SDK_PATH}/tools/${ARCH}/ffx repository publish \
+ --package pkg/hello_fuchsia_package_manifest \
+ pkg/repo
```
Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
```sh
${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
- pkg/repo \
- -r hello-fuchsia
+ --repository hello-fuchsia \
+ pkg/repo
```
## Running a Fuchsia component on an emulator
diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
new file mode 100644
index 0000000..5608b5c
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
@@ -0,0 +1,40 @@
+# `x86_64-unknown-linux-none`
+
+**Tier: 3**
+
+Freestanding x86-64 linux binary with no dependency on libc.
+
+## Target maintainers
+
+- [morr0ne](https://github.com/morr0ne/)
+
+## Requirements
+
+This target is cross compiled and can be built from any host.
+
+This target has no support for host tools, std, or alloc.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["x86_64-unknown-linux-none"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Created binaries will run on linux without any external requirements
+
+## Cross-compilation toolchains and C code
+
+Support for C code is currently untested
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
index 9d593f8..74e873e 100644
--- a/src/doc/style-guide/src/editions.md
+++ b/src/doc/style-guide/src/editions.md
@@ -40,6 +40,8 @@
of a delimited expression, delimited expressions are generally combinable,
regardless of the number of members. Previously only applied with exactly
one member (except for closures with explicit blocks).
+- When line-breaking a binary operator, if the first operand spans multiple
+ lines, use the base indentation of the last line.
- Miscellaneous `rustfmt` bugfixes.
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index 171a24c..3bb0ee6 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -328,6 +328,37 @@
Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
than at other binary operators.
+If line-breaking at a binary operator (including assignment operators) where the
+first operand spans multiple lines, use the base indentation of the *last*
+line of the first operand, and indent relative to that:
+
+```rust
+impl SomeType {
+ fn method(&mut self) {
+ self.array[array_index as usize]
+ .as_mut()
+ .expect("thing must exist")
+ .extra_info =
+ long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
+
+ self.array[array_index as usize]
+ .as_mut()
+ .expect("thing must exist")
+ .extra_info
+ + long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
+
+ self.array[array_index as usize]
+ .as_mut()
+ .expect("thing must exist")
+ .extra_info = Some(ExtraInfo {
+ parent,
+ count: count as u16,
+ children: children.into_boxed_slice(),
+ });
+ }
+}
+```
+
### Casts (`as`)
Format `as` casts like a binary operator. In particular, always include spaces
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index 1671a01..7d239ff 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -150,6 +150,19 @@ pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
self
}
+ /// Enables link time optimizations in rustc. Equivalent to `-Clto``.
+ pub fn lto(&mut self) -> &mut Self {
+ self.cmd.arg("-Clto");
+ self
+ }
+
+ /// Add a directory to the library search path.
+ pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+ self.cmd.arg("-L");
+ self.cmd.arg(path.as_ref());
+ self
+ }
+
/// Specify the edition year.
pub fn edition(&mut self, edition: &str) -> &mut Self {
self.cmd.arg("--edition");
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 18a7cb1..5f68f77 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -9,7 +9,6 @@
run-make/c-dynamic-rlib/Makefile
run-make/c-link-to-rust-dylib/Makefile
run-make/c-link-to-rust-staticlib/Makefile
-run-make/c-link-to-rust-va-list-fn/Makefile
run-make/c-static-dylib/Makefile
run-make/c-static-rlib/Makefile
run-make/c-unwind-abi-catch-lib-panic/Makefile
@@ -96,7 +95,6 @@
run-make/issue-10971-temps-dir/Makefile
run-make/issue-109934-lto-debuginfo/Makefile
run-make/issue-11908/Makefile
-run-make/issue-14500/Makefile
run-make/issue-14698/Makefile
run-make/issue-15460/Makefile
run-make/issue-18943/Makefile
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 3563aec..0db2a35 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -555,6 +555,9 @@
//@ revisions: x86_64_unknown_linux_ohos
//@ [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos
//@ [x86_64_unknown_linux_ohos] needs-llvm-components: x86
+//@ revisions: x86_64_unknown_linux_none
+//@ [x86_64_unknown_linux_none] compile-flags: --target x86_64-unknown-linux-none
+//@ [x86_64_unknown_linux_none] needs-llvm-components: x86
//@ revisions: x86_64_unknown_netbsd
//@ [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd
//@ [x86_64_unknown_netbsd] needs-llvm-components: x86
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/Makefile b/tests/run-make/c-link-to-rust-va-list-fn/Makefile
deleted file mode 100644
index 596c0fc..0000000
--- a/tests/run-make/c-link-to-rust-va-list-fn/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
- $(RUSTC) checkrust.rs
- $(CC) test.c $(call STATICLIB,checkrust) $(call OUT_EXE,test) $(EXTRACFLAGS)
- $(call RUN,test)
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
new file mode 100644
index 0000000..7a450ef
--- /dev/null
+++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
@@ -0,0 +1,18 @@
+// test.c and its static library checkrust.rs make use of variadic functions (VaList).
+// This test checks that the use of this feature does not
+// prevent the creation of a functional binary.
+// See https://github.com/rust-lang/rust/pull/49878
+
+//@ ignore-cross-compile
+
+use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
+
+fn main() {
+ rustc().input("checkrust.rs").run();
+ cc().input("test.c")
+ .input(static_lib("checkrust"))
+ .out_exe("test")
+ .args(&extra_c_flags())
+ .run();
+ run("test");
+}
diff --git a/tests/run-make/issue-14500/Makefile b/tests/run-make/issue-14500/Makefile
deleted file mode 100644
index eeab48d..0000000
--- a/tests/run-make/issue-14500/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-
-# Test to make sure that reachable extern fns are always available in final
-# productcs, including when LTO is used. In this test, the `foo` crate has a
-# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
-# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
-# only way that `foo.c` will successfully compile.
-
-all:
- $(RUSTC) foo.rs --crate-type=rlib
- $(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
- $(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo)
- $(call RUN,foo)
diff --git a/tests/run-make/issue-14500/bar.rs b/tests/run-make/reachable-extern-fn-available-lto/bar.rs
similarity index 100%
rename from tests/run-make/issue-14500/bar.rs
rename to tests/run-make/reachable-extern-fn-available-lto/bar.rs
diff --git a/tests/run-make/issue-14500/foo.c b/tests/run-make/reachable-extern-fn-available-lto/foo.c
similarity index 100%
rename from tests/run-make/issue-14500/foo.c
rename to tests/run-make/reachable-extern-fn-available-lto/foo.c
diff --git a/tests/run-make/issue-14500/foo.rs b/tests/run-make/reachable-extern-fn-available-lto/foo.rs
similarity index 100%
rename from tests/run-make/issue-14500/foo.rs
rename to tests/run-make/reachable-extern-fn-available-lto/foo.rs
diff --git a/tests/run-make/reachable-extern-fn-available-lto/rmake.rs b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs
new file mode 100644
index 0000000..3e38b92
--- /dev/null
+++ b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs
@@ -0,0 +1,26 @@
+// Test to make sure that reachable extern fns are always available in final
+// productcs, including when link time optimizations (LTO) are used.
+
+// In this test, the `foo` crate has a reahable symbol,
+// and is a dependency of the `bar` crate. When the `bar` crate
+// is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
+// only way that `foo.c` will successfully compile.
+// See https://github.com/rust-lang/rust/issues/14500
+
+//@ ignore-cross-compile
+
+use run_make_support::{cc, extra_c_flags, run, rustc, static_lib, tmp_dir};
+
+fn main() {
+ let libbar_path = static_lib("bar");
+ rustc().input("foo.rs").crate_type("rlib").run();
+ rustc()
+ .input("bar.rs")
+ .crate_type("staticlib")
+ .lto()
+ .library_search_path(".")
+ .output(&libbar_path)
+ .run();
+ cc().input("foo.c").input(libbar_path).args(&extra_c_flags()).out_exe("foo").run();
+ run("foo");
+}
diff --git a/tests/ui/cast/ice-cast-type-with-error-124848.rs b/tests/ui/cast/ice-cast-type-with-error-124848.rs
new file mode 100644
index 0000000..9b3732b
--- /dev/null
+++ b/tests/ui/cast/ice-cast-type-with-error-124848.rs
@@ -0,0 +1,18 @@
+// Regression test for ICE #124848
+// Tests that there is no ICE when a cast
+// involves a type with error
+
+use std::cell::Cell;
+
+struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+//~^ ERROR use of undeclared lifetime name `'unpinned`
+//~| ERROR cannot find type `Pin` in this scope
+
+fn main() {
+ let mut unpinned = MyType(Cell::new(None));
+ //~^ ERROR his struct takes 2 arguments but 1 argument was supplied
+ let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+ //~^ ERROR use of undeclared lifetime name `'a`
+ //~| ERROR use of undeclared lifetime name `'a`
+ //~| ERROR casting `&MyType<'_>` as `*const Cell<Option<&mut MyType<'_>>>` is invalid
+}
diff --git a/tests/ui/cast/ice-cast-type-with-error-124848.stderr b/tests/ui/cast/ice-cast-type-with-error-124848.stderr
new file mode 100644
index 0000000..2d86bf7
--- /dev/null
+++ b/tests/ui/cast/ice-cast-type-with-error-124848.stderr
@@ -0,0 +1,63 @@
+error[E0261]: use of undeclared lifetime name `'unpinned`
+ --> $DIR/ice-cast-type-with-error-124848.rs:7:32
+ |
+LL | struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+ | - ^^^^^^^^^ undeclared lifetime
+ | |
+ | help: consider introducing lifetime `'unpinned` here: `'unpinned,`
+
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/ice-cast-type-with-error-124848.rs:14:53
+ |
+LL | fn main() {
+ | - help: consider introducing lifetime `'a` here: `<'a>`
+...
+LL | let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+ | ^^ undeclared lifetime
+
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/ice-cast-type-with-error-124848.rs:14:67
+ |
+LL | fn main() {
+ | - help: consider introducing lifetime `'a` here: `<'a>`
+...
+LL | let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+ | ^^ undeclared lifetime
+
+error[E0412]: cannot find type `Pin` in this scope
+ --> $DIR/ice-cast-type-with-error-124848.rs:7:60
+ |
+LL | struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+ | ^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL + use std::pin::Pin;
+ |
+
+error[E0061]: this struct takes 2 arguments but 1 argument was supplied
+ --> $DIR/ice-cast-type-with-error-124848.rs:12:24
+ |
+LL | let mut unpinned = MyType(Cell::new(None));
+ | ^^^^^^----------------- an argument is missing
+ |
+note: tuple struct defined here
+ --> $DIR/ice-cast-type-with-error-124848.rs:7:8
+ |
+LL | struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+ | ^^^^^^
+help: provide the argument
+ |
+LL | let mut unpinned = MyType(Cell::new(None), /* value */);
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0606]: casting `&MyType<'_>` as `*const Cell<Option<&mut MyType<'_>>>` is invalid
+ --> $DIR/ice-cast-type-with-error-124848.rs:14:20
+ |
+LL | let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0061, E0261, E0412, E0606.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/coercion/pin-dyn-dispatch-sound.rs b/tests/ui/coercion/pin-dyn-dispatch-sound.rs
new file mode 100644
index 0000000..b9d43eb
--- /dev/null
+++ b/tests/ui/coercion/pin-dyn-dispatch-sound.rs
@@ -0,0 +1,19 @@
+use std::marker::PhantomPinned;
+use std::pin::Pin;
+
+trait MyUnpinTrait {
+ fn into_pinned_type(self: Pin<&mut Self>) -> Pin<&mut PhantomPinned>;
+}
+impl MyUnpinTrait for PhantomPinned {
+ fn into_pinned_type(self: Pin<&mut Self>) -> Pin<&mut PhantomPinned> {
+ self
+ }
+}
+impl Unpin for dyn MyUnpinTrait {} //~ ERROR E0321
+
+// It would be unsound for this function to compile.
+fn pin_it(not_yet_pinned: &mut PhantomPinned) -> Pin<&mut PhantomPinned> {
+ Pin::new(not_yet_pinned as &mut dyn MyUnpinTrait).into_pinned_type()
+}
+
+fn main() {}
diff --git a/tests/ui/coercion/pin-dyn-dispatch-sound.stderr b/tests/ui/coercion/pin-dyn-dispatch-sound.stderr
new file mode 100644
index 0000000..45860bf
--- /dev/null
+++ b/tests/ui/coercion/pin-dyn-dispatch-sound.stderr
@@ -0,0 +1,9 @@
+error[E0321]: cross-crate traits with a default impl, like `Unpin`, can only be implemented for a struct/enum type, not `(dyn MyUnpinTrait + 'static)`
+ --> $DIR/pin-dyn-dispatch-sound.rs:12:1
+ |
+LL | impl Unpin for dyn MyUnpinTrait {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0321`.
diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr
index 36bf80d..96548f5 100644
--- a/tests/ui/impl-trait/precise-capturing/apit.stderr
+++ b/tests/ui/impl-trait/precise-capturing/apit.stderr
@@ -11,7 +11,7 @@
--> $DIR/apit.rs:4:18
|
LL | fn hello(_: impl use<> Sized) {}
- | ^^^
+ | ^^^^^
error: aborting due to 1 previous error; 1 warning emitted
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
new file mode 100644
index 0000000..014ab23
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
@@ -0,0 +1,29 @@
+//@ run-rustfix
+
+#![feature(precise_capturing)]
+#![allow(unused, incomplete_features)]
+#![deny(impl_trait_overcaptures)]
+
+fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn implicit(x: &i32) -> impl use<> Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+struct W;
+impl W {
+ fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
+ //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
+}
+
+trait Higher<'a> {
+ type Output;
+}
+impl Higher<'_> for () {
+ type Output = ();
+}
+
+fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
new file mode 100644
index 0000000..e4b7828
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
@@ -0,0 +1,29 @@
+//@ run-rustfix
+
+#![feature(precise_capturing)]
+#![allow(unused, incomplete_features)]
+#![deny(impl_trait_overcaptures)]
+
+fn named<'a>(x: &'a i32) -> impl Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn implicit(x: &i32) -> impl Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+struct W;
+impl W {
+ fn hello(&self, x: &i32) -> impl Sized + '_ { self }
+ //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
+}
+
+trait Higher<'a> {
+ type Output;
+}
+impl Higher<'_> for () {
+ type Output = ();
+}
+
+fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
new file mode 100644
index 0000000..16cb8b7
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
@@ -0,0 +1,75 @@
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+ --> $DIR/overcaptures-2024.rs:7:29
+ |
+LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
+ | ^^^^^^^^^^
+ |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+ --> $DIR/overcaptures-2024.rs:7:10
+ |
+LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
+ | ^^
+ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+note: the lint level is defined here
+ --> $DIR/overcaptures-2024.rs:5:9
+ |
+LL | #![deny(impl_trait_overcaptures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+ |
+LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
+ | +++++
+
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+ --> $DIR/overcaptures-2024.rs:10:25
+ |
+LL | fn implicit(x: &i32) -> impl Sized { *x }
+ | ^^^^^^^^^^
+ |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+ --> $DIR/overcaptures-2024.rs:10:16
+ |
+LL | fn implicit(x: &i32) -> impl Sized { *x }
+ | ^
+ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+ |
+LL | fn implicit(x: &i32) -> impl use<> Sized { *x }
+ | +++++
+
+error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
+ --> $DIR/overcaptures-2024.rs:15:33
+ |
+LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
+ | ^^^^^^^^^^^^^^^
+ |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+ --> $DIR/overcaptures-2024.rs:15:24
+ |
+LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
+ | ^
+ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+ |
+LL | fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
+ | +++++++
+
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+ --> $DIR/overcaptures-2024.rs:26:47
+ |
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
+ | ^^^^^^^^^^
+ |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+ --> $DIR/overcaptures-2024.rs:26:23
+ |
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
+ | ^^
+ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+ |
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
+ | +++++
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs
new file mode 100644
index 0000000..108a4cb
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/redundant.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Zunstable-options --edition=2024
+//@ check-pass
+
+#![feature(precise_capturing)]
+//~^ WARN the feature `precise_capturing` is incomplete
+
+fn hello<'a>() -> impl use<'a> Sized {}
+//~^ WARN all possible in-scope parameters are already captured
+
+struct Inherent;
+impl Inherent {
+ fn inherent(&self) -> impl use<'_> Sized {}
+ //~^ WARN all possible in-scope parameters are already captured
+}
+
+trait Test<'a> {
+ fn in_trait() -> impl use<'a, Self> Sized;
+ //~^ WARN all possible in-scope parameters are already captured
+}
+impl<'a> Test<'a> for () {
+ fn in_trait() -> impl use<'a> Sized {}
+ //~^ WARN all possible in-scope parameters are already captured
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr
new file mode 100644
index 0000000..325f04d
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr
@@ -0,0 +1,45 @@
+warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/redundant.rs:4:12
+ |
+LL | #![feature(precise_capturing)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+ --> $DIR/redundant.rs:7:19
+ |
+LL | fn hello<'a>() -> impl use<'a> Sized {}
+ | ^^^^^-------^^^^^^
+ | |
+ | help: remove the `use<...>` syntax
+ |
+ = note: `#[warn(impl_trait_redundant_captures)]` on by default
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+ --> $DIR/redundant.rs:12:27
+ |
+LL | fn inherent(&self) -> impl use<'_> Sized {}
+ | ^^^^^-------^^^^^^
+ | |
+ | help: remove the `use<...>` syntax
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+ --> $DIR/redundant.rs:17:22
+ |
+LL | fn in_trait() -> impl use<'a, Self> Sized;
+ | ^^^^^-------------^^^^^^
+ | |
+ | help: remove the `use<...>` syntax
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+ --> $DIR/redundant.rs:21:22
+ |
+LL | fn in_trait() -> impl use<'a> Sized {}
+ | ^^^^^-------^^^^^^
+ | |
+ | help: remove the `use<...>` syntax
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr
index 499f9a7..d191411 100644
--- a/tests/ui/macros/nonterminal-matching.stderr
+++ b/tests/ui/macros/nonterminal-matching.stderr
@@ -1,8 +1,6 @@
error: no rules expected the token `enum E {}`
--> $DIR/nonterminal-matching.rs:19:10
|
-LL | macro complex_nonterminal($nt_item: item) {
- | --------------
LL | macro n(a $nt_item b) {
| --------------------- when calling this macro
...
diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr
index 6960760..665dcc7 100644
--- a/tests/ui/macros/trace_faulty_macros.stderr
+++ b/tests/ui/macros/trace_faulty_macros.stderr
@@ -73,14 +73,10 @@
--> $DIR/trace_faulty_macros.rs:49:37
|
LL | (let $p:pat = $e:expr) => {test!(($p,$e))};
- | ------- -- this is interpreted as expression, but it is expected to be pattern
- | |
- | this macro fragment matcher is expression
+ | -- this is interpreted as expression, but it is expected to be pattern
...
LL | (($p:pat, $e:pat)) => {let $p = $e;};
- | ------ ^^ expected expression
- | |
- | this macro fragment matcher is pattern
+ | ^^ expected expression
...
LL | test!(let x = 1+1);
| ------------------