diff options
Diffstat (limited to '')
23 files changed, 623 insertions, 867 deletions
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index c24180bac..fcbf96818 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [lib] -doctest = false [dependencies] bitflags = "1.2.1" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d86db8f8b..4ef43735a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1112,24 +1112,6 @@ pub struct Expr { } impl Expr { - /// Returns `true` if this expression would be valid somewhere that expects a value; - /// for example, an `if` condition. - pub fn returns(&self) -> bool { - if let ExprKind::Block(ref block, _) = self.kind { - match block.stmts.last().map(|last_stmt| &last_stmt.kind) { - // Implicit return - Some(StmtKind::Expr(_)) => true, - // Last statement is an explicit return? - Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)), - // This is a block that doesn't end in either an implicit or explicit return. - _ => false, - } - } else { - // This is not a block, it is a value. - true - } - } - /// Is this expr either `N`, or `{ N }`. /// /// If this is not the case, name resolution does not resolve `N` when using @@ -1338,14 +1320,13 @@ pub enum ExprKind { /// /// The `PathSegment` represents the method name and its generic arguments /// (within the angle brackets). - /// The first element of the vector of an `Expr` is the expression that evaluates - /// to the object on which the method is being called on (the receiver), - /// and the remaining elements are the rest of the arguments. - /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as - /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`. + /// The standalone `Expr` is the receiver expression. + /// The vector of `Expr` is the arguments. + /// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as + /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`. /// This `Span` is the span of the function, without the dot and receiver /// (e.g. `foo(a, b)` in `x.foo(a, b)` - MethodCall(PathSegment, Vec<P<Expr>>, Span), + MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(Vec<P<Expr>>), /// A binary operation (e.g., `a + b`, `a * b`). @@ -2957,7 +2938,7 @@ pub enum AssocItemKind { /// An associated function. Fn(Box<Fn>), /// An associated type. - TyAlias(Box<TyAlias>), + Type(Box<TyAlias>), /// A macro expanding to associated items. MacCall(P<MacCall>), } @@ -2967,7 +2948,7 @@ impl AssocItemKind { match *self { Self::Const(defaultness, ..) | Self::Fn(box Fn { defaultness, .. }) - | Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness, + | Self::Type(box TyAlias { defaultness, .. }) => defaultness, Self::MacCall(..) => Defaultness::Final, } } @@ -2978,7 +2959,7 @@ impl From<AssocItemKind> for ItemKind { match assoc_item_kind { AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c), AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind), - AssocItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), + AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), AssocItemKind::MacCall(a) => ItemKind::MacCall(a), } } @@ -2991,7 +2972,7 @@ impl TryFrom<ItemKind> for AssocItemKind { Ok(match item_kind { ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c), ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind), - ItemKind::TyAlias(ty_alias_kind) => AssocItemKind::TyAlias(ty_alias_kind), + ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind), ItemKind::MacCall(a) => AssocItemKind::MacCall(a), _ => return Err(item_kind), }) @@ -3043,14 +3024,13 @@ pub type ForeignItem = Item<ForeignItemKind>; mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; - // These are in alphabetical order, which is easy to maintain. + // tidy-alphabetical-start static_assert_size!(AssocItem, 104); static_assert_size!(AssocItemKind, 32); static_assert_size!(Attribute, 32); static_assert_size!(Block, 48); static_assert_size!(Expr, 104); static_assert_size!(ExprKind, 72); - #[cfg(not(bootstrap))] static_assert_size!(Fn, 184); static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItemKind, 24); @@ -3065,11 +3045,12 @@ mod size_asserts { static_assert_size!(Local, 72); static_assert_size!(Param, 40); static_assert_size!(Pat, 120); - static_assert_size!(PatKind, 96); static_assert_size!(Path, 40); static_assert_size!(PathSegment, 24); + static_assert_size!(PatKind, 96); static_assert_size!(Stmt, 32); static_assert_size!(StmtKind, 16); static_assert_size!(Ty, 96); static_assert_size!(TyKind, 72); + // tidy-alphabetical-end } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index bd7a85b07..eeb7e56e2 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -13,9 +13,7 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(if_let_guard)] -#![cfg_attr(bootstrap, feature(label_break_value))] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(slice_internals)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 9fd0b63c4..b970e57e0 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -152,6 +152,12 @@ pub trait MutVisitor: Sized { noop_visit_expr(e, self); } + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) { + self.visit_expr(ex) + } + fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> { noop_filter_map_expr(e, self) } @@ -1106,7 +1112,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>( visit_fn_sig(sig, visitor); visit_opt(body, |body| visitor.visit_block(body)); } - AssocItemKind::TyAlias(box TyAlias { + AssocItemKind::Type(box TyAlias { defaultness, generics, where_clauses, @@ -1297,10 +1303,11 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_expr(f); visit_exprs(args, vis); } - ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => { + ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => { vis.visit_ident(ident); vis.visit_id(id); visit_opt(args, |args| vis.visit_generic_args(args)); + vis.visit_method_receiver_expr(receiver); visit_exprs(exprs, vis); vis.visit_span(span); } @@ -1588,3 +1595,9 @@ impl DummyAstNode for Crate { } } } + +impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNodeWrapper<N, T> { + fn dummy() -> Self { + crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy()) + } +} diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 97dfb7837..83b10d906 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -13,7 +13,7 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, edition::Edition, Span, DUMMY_SP}; use std::borrow::Cow; -use std::{fmt, mem}; +use std::fmt; #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum CommentKind { @@ -256,10 +256,6 @@ pub enum TokenKind { Eof, } -// `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(TokenKind, 16); - #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, @@ -335,11 +331,6 @@ impl Token { Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span) } - /// Return this token by value and leave a dummy token in its place. - pub fn take(&mut self) -> Self { - mem::replace(self, Token::dummy()) - } - /// For interpolated tokens, returns a span of the fragment to which the interpolated /// token refers. For all other tokens this is just a regular span. /// It is particularly important to use this for identifiers and lifetimes @@ -354,17 +345,14 @@ impl Token { } pub fn is_op(&self) -> bool { - !matches!( - self.kind, - OpenDelim(..) - | CloseDelim(..) - | Literal(..) - | DocComment(..) - | Ident(..) - | Lifetime(..) - | Interpolated(..) - | Eof - ) + match self.kind { + Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_) + | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon + | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true, + + OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) + | Lifetime(..) | Interpolated(..) | Eof => false, + } } pub fn is_like_plus(&self) -> bool { @@ -733,6 +721,7 @@ impl Token { } impl PartialEq<TokenKind> for Token { + #[inline] fn eq(&self, rhs: &TokenKind) -> bool { self.kind == *rhs } @@ -756,10 +745,6 @@ pub enum Nonterminal { NtVis(P<ast::Visibility>), } -// `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Nonterminal, 16); - #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] pub enum NonterminalKind { Item, @@ -898,3 +883,17 @@ where panic!("interpolated tokens should not be present in the HIR") } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // tidy-alphabetical-start + static_assert_size!(Lit, 12); + static_assert_size!(LitKind, 2); + static_assert_size!(Nonterminal, 16); + static_assert_size!(Token, 24); + static_assert_size!(TokenKind, 16); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 875cd620d..015f5c1ee 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -47,10 +47,6 @@ pub enum TokenTree { Delimited(DelimSpan, Delimiter, TokenStream), } -// This type is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(TokenTree, 32); - // Ensure all fields of `TokenTree` is `Send` and `Sync`. #[cfg(parallel_compiler)] fn _dummy() @@ -249,12 +245,12 @@ impl AttrTokenStream { // properly implemented - we always synthesize fake tokens, // so we never reach this code. - let mut builder = TokenStreamBuilder::new(); + let mut stream = TokenStream::default(); for inner_attr in inner_attrs { - builder.push(inner_attr.tokens()); + stream.push_stream(inner_attr.tokens()); } - builder.push(delim_tokens.clone()); - *tree = TokenTree::Delimited(*span, *delim, builder.build()); + stream.push_stream(delim_tokens.clone()); + *tree = TokenTree::Delimited(*span, *delim, stream); found = true; break; } @@ -308,13 +304,20 @@ pub struct AttributesData { #[derive(Clone, Debug, Default, Encodable, Decodable)] pub struct TokenStream(pub(crate) Lrc<Vec<TokenTree>>); -// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(TokenStream, 8); - +/// Similar to `proc_macro::Spacing`, but for tokens. +/// +/// Note that all `ast::TokenTree::Token` instances have a `Spacing`, but when +/// we convert to `proc_macro::TokenTree` for proc macros only `Punct` +/// `TokenTree`s have a `proc_macro::Spacing`. #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum Spacing { + /// The token is not immediately followed by an operator token (as + /// determined by `Token::is_op`). E.g. a `+` token is `Alone` in `+ =`, + /// `+/*foo*/=`, `+ident`, and `+()`. Alone, + + /// The token is immediately followed by an operator token. E.g. a `+` + /// token is `Joint` in `+=` and `++`. Joint, } @@ -502,76 +505,49 @@ impl TokenStream { self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect() } -} -// 99.5%+ of the time we have 1 or 2 elements in this vector. -#[derive(Clone)] -pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>); - -impl TokenStreamBuilder { - pub fn new() -> TokenStreamBuilder { - TokenStreamBuilder(SmallVec::new()) - } - - pub fn push(&mut self, stream: TokenStream) { - self.0.push(stream); - } - - pub fn build(self) -> TokenStream { - let mut streams = self.0; - match streams.len() { - 0 => TokenStream::default(), - 1 => streams.pop().unwrap(), - _ => { - // We will extend the first stream in `streams` with the - // elements from the subsequent streams. This requires using - // `make_mut()` on the first stream, and in practice this - // doesn't cause cloning 99.9% of the time. - // - // One very common use case is when `streams` has two elements, - // where the first stream has any number of elements within - // (often 1, but sometimes many more) and the second stream has - // a single element within. - - // Determine how much the first stream will be extended. - // Needed to avoid quadratic blow up from on-the-fly - // reallocations (#57735). - let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum(); - - // Get the first stream, which will become the result stream. - // If it's `None`, create an empty stream. - let mut iter = streams.into_iter(); - let mut res_stream_lrc = iter.next().unwrap().0; - - // Append the subsequent elements to the result stream, after - // reserving space for them. - let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc); - res_vec_mut.reserve(num_appends); - for stream in iter { - let stream_iter = stream.0.iter().cloned(); - - // If (a) `res_mut_vec` is not empty and the last tree - // within it is a token tree marked with `Joint`, and (b) - // `stream` is not empty and the first tree within it is a - // token tree, and (c) the two tokens can be glued - // together... - if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = res_vec_mut.last() - && let Some(TokenTree::Token(tok, spacing)) = stream.0.first() - && let Some(glued_tok) = last_tok.glue(&tok) - { - // ...then overwrite the last token tree in - // `res_vec_mut` with the glued token, and skip the - // first token tree from `stream`. - *res_vec_mut.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing); - res_vec_mut.extend(stream_iter.skip(1)); - } else { - // Append all of `stream`. - res_vec_mut.extend(stream_iter); - } - } + // If `vec` is not empty, try to glue `tt` onto its last token. The return + // value indicates if gluing took place. + fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool { + if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last() + && let TokenTree::Token(tok, spacing) = tt + && let Some(glued_tok) = last_tok.glue(&tok) + { + // ...then overwrite the last token tree in `vec` with the + // glued token, and skip the first token tree from `stream`. + *vec.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing); + true + } else { + false + } + } - TokenStream(res_stream_lrc) - } + // Push `tt` onto the end of the stream, possibly gluing it to the last + // token. Uses `make_mut` to maximize efficiency. + pub fn push_tree(&mut self, tt: TokenTree) { + let vec_mut = Lrc::make_mut(&mut self.0); + + if Self::try_glue_to_last(vec_mut, &tt) { + // nothing else to do + } else { + vec_mut.push(tt); + } + } + + // Push `stream` onto the end of the stream, possibly gluing the first + // token tree to the last token. (No other token trees will be glued.) + // Uses `make_mut` to maximize efficiency. + pub fn push_stream(&mut self, stream: TokenStream) { + let vec_mut = Lrc::make_mut(&mut self.0); + + let stream_iter = stream.0.iter().cloned(); + + if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) { + // Now skip the first token tree from `stream`. + vec_mut.extend(stream_iter.skip(1)); + } else { + // Append all of `stream`. + vec_mut.extend(stream_iter); } } } @@ -664,3 +640,17 @@ impl DelimSpan { self.open.with_hi(self.close.hi()) } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // tidy-alphabetical-start + static_assert_size!(AttrTokenStream, 8); + static_assert_size!(AttrTokenTree, 32); + static_assert_size!(LazyAttrTokenStream, 8); + static_assert_size!(TokenStream, 8); + static_assert_size!(TokenTree, 32); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 6c5c7f66f..b40ad6f70 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -396,9 +396,9 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { contains_exterior_struct_lit(&x) } - ast::ExprKind::MethodCall(.., ref exprs, _) => { + ast::ExprKind::MethodCall(_, ref receiver, _, _) => { // X { y: 1 }.bar(...) - contains_exterior_struct_lit(&exprs[0]) + contains_exterior_struct_lit(&receiver) } _ => false, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1d0de5a4b..6f56c1ef0 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized { fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) } + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) { + self.visit_expr(ex) + } fn visit_expr_post(&mut self, _ex: &'ast Expr) {} fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) @@ -244,14 +249,12 @@ pub trait Visitor<'ast>: Sized { #[macro_export] macro_rules! walk_list { - ($visitor: expr, $method: ident, $list: expr) => { - for elem in $list { - $visitor.$method(elem) - } - }; - ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => { - for elem in $list { - $visitor.$method(elem, $($extra_args,)*) + ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => { + { + #[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))] + for elem in $list { + $visitor.$method(elem $(, $($extra_args,)* )?) + } } } } @@ -685,7 +688,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); visitor.visit_fn(kind, span, id); } - AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { + AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); walk_list!(visitor, visit_ty, ty); @@ -795,8 +798,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, ref arguments, _span) => { + ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => { visitor.visit_path_segment(segment); + visitor.visit_expr(receiver); walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 24672efc6..450cdf246 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -192,26 +192,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Sym { ref sym } => { - if !self.tcx.features().asm_sym { - feature_err( - &sess.parse_sess, - sym::asm_sym, - *op_sp, - "sym operands for inline assembly are unstable", - ) - .emit(); - } - let static_def_id = self .resolver .get_partial_res(sym.id) - .filter(|res| res.unresolved_segments() == 0) - .and_then(|res| { - if let Res::Def(DefKind::Static(_), def_id) = res.base_res() { - Some(def_id) - } else { - None - } + .and_then(|res| res.full_res()) + .and_then(|res| match res { + Res::Def(DefKind::Static(_), def_id) => Some(def_id), + _ => None, }); if let Some(def_id) = static_def_id { @@ -237,7 +224,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Wrap the expression in an AnonConst. let parent_def_id = self.current_hir_id_owner; let node_id = self.next_node_id(); - self.create_def(parent_def_id, node_id, DefPathData::AnonConst); + self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst); let anon_const = AnonConst { id: node_id, value: P(expr) }; hir::InlineAsmOperand::SymFn { anon_const: self.lower_anon_const(&anon_const), diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index c87d0ca96..157f46501 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,9 +1,9 @@ -use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay}; -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_errors::DiagnosticArgFromDisplay; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")] pub struct GenericTypeWithParentheses { #[primary_span] #[label] @@ -12,35 +12,42 @@ pub struct GenericTypeWithParentheses { pub sub: Option<UseAngleBrackets>, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] +#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")] pub struct UseAngleBrackets { + #[suggestion_part(code = "<")] pub open_param: Span, + #[suggestion_part(code = ">")] pub close_param: Span, } -impl AddSubdiagnostic for UseAngleBrackets { - fn add_to_diagnostic(self, diag: &mut Diagnostic) { - diag.multipart_suggestion( - fluent::ast_lowering::use_angle_brackets, - vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ); - } -} - -#[derive(SessionDiagnostic)] -#[help] -#[diag(ast_lowering::invalid_abi, code = "E0703")] +#[derive(Diagnostic)] +#[diag(ast_lowering_invalid_abi, code = "E0703")] +#[note] pub struct InvalidAbi { #[primary_span] #[label] pub span: Span, pub abi: Symbol, - pub valid_abis: String, + pub command: String, + #[subdiagnostic] + pub suggestion: Option<InvalidAbiSuggestion>, +} + +#[derive(Subdiagnostic)] +#[suggestion( + ast_lowering_invalid_abi_suggestion, + code = "{suggestion}", + applicability = "maybe-incorrect" +)] +pub struct InvalidAbiSuggestion { + #[primary_span] + pub span: Span, + pub suggestion: String, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::assoc_ty_parentheses)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_assoc_ty_parentheses)] pub struct AssocTyParentheses { #[primary_span] pub span: Span, @@ -48,123 +55,116 @@ pub struct AssocTyParentheses { pub sub: AssocTyParenthesesSub, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] pub enum AssocTyParenthesesSub { - Empty { parentheses_span: Span }, - NotEmpty { open_param: Span, close_param: Span }, -} - -impl AddSubdiagnostic for AssocTyParenthesesSub { - fn add_to_diagnostic(self, diag: &mut Diagnostic) { - match self { - Self::Empty { parentheses_span } => diag.multipart_suggestion( - fluent::ast_lowering::remove_parentheses, - vec![(parentheses_span, String::new())], - Applicability::MaybeIncorrect, - ), - Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion( - fluent::ast_lowering::use_angle_brackets, - vec![(open_param, String::from("<")), (close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ), - }; - } -} - -#[derive(SessionDiagnostic)] -#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")] + #[multipart_suggestion(ast_lowering_remove_parentheses)] + Empty { + #[suggestion_part(code = "")] + parentheses_span: Span, + }, + #[multipart_suggestion(ast_lowering_use_angle_brackets)] + NotEmpty { + #[suggestion_part(code = "<")] + open_param: Span, + #[suggestion_part(code = ">")] + close_param: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] pub struct MisplacedImplTrait<'a> { #[primary_span] pub span: Span, pub position: DiagnosticArgFromDisplay<'a>, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::rustc_box_attribute_error)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_rustc_box_attribute_error)] pub struct RustcBoxAttributeError { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::underscore_expr_lhs_assign)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_underscore_expr_lhs_assign)] pub struct UnderscoreExprLhsAssign { #[primary_span] #[label] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::base_expression_double_dot)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_base_expression_double_dot)] pub struct BaseExpressionDoubleDot { #[primary_span] #[label] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")] pub struct AwaitOnlyInAsyncFnAndBlocks { #[primary_span] #[label] pub dot_await_span: Span, - #[label(ast_lowering::this_not_async)] + #[label(ast_lowering_this_not_async)] pub item_span: Option<Span>, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_generator_too_many_parameters, code = "E0628")] pub struct GeneratorTooManyParameters { #[primary_span] pub fn_decl_span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")] pub struct ClosureCannotBeStatic { #[primary_span] pub fn_decl_span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] +#[derive(Diagnostic, Clone, Copy)] #[help] -#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")] +#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")] pub struct AsyncNonMoveClosureNotSupported { #[primary_span] pub fn_decl_span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::functional_record_update_destructuring_assignment)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_functional_record_update_destructuring_assignment)] pub struct FunctionalRecordUpdateDestructuringAssignemnt { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::async_generators_not_supported, code = "E0727")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_async_generators_not_supported, code = "E0727")] pub struct AsyncGeneratorsNotSupported { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")] pub struct InlineAsmUnsupportedTarget { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::att_syntax_only_x86)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_att_syntax_only_x86)] pub struct AttSyntaxOnlyX86 { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::abi_specified_multiple_times)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_abi_specified_multiple_times)] pub struct AbiSpecifiedMultipleTimes { #[primary_span] pub abi_span: Span, @@ -175,24 +175,24 @@ pub struct AbiSpecifiedMultipleTimes { pub equivalent: Option<()>, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::clobber_abi_not_supported)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_clobber_abi_not_supported)] pub struct ClobberAbiNotSupported { #[primary_span] pub abi_span: Span, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[note] -#[diag(ast_lowering::invalid_abi_clobber_abi)] +#[diag(ast_lowering_invalid_abi_clobber_abi)] pub struct InvalidAbiClobberAbi { #[primary_span] pub abi_span: Span, pub supported_abis: String, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_register)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_invalid_register)] pub struct InvalidRegister<'a> { #[primary_span] pub op_span: Span, @@ -200,8 +200,8 @@ pub struct InvalidRegister<'a> { pub error: &'a str, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_register_class)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_invalid_register_class)] pub struct InvalidRegisterClass<'a> { #[primary_span] pub op_span: Span, @@ -209,61 +209,61 @@ pub struct InvalidRegisterClass<'a> { pub error: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)] +#[derive(Diagnostic)] +#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)] pub struct InvalidAsmTemplateModifierRegClass { #[primary_span] - #[label(ast_lowering::template_modifier)] + #[label(ast_lowering_template_modifier)] pub placeholder_span: Span, - #[label(ast_lowering::argument)] + #[label(ast_lowering_argument)] pub op_span: Span, #[subdiagnostic] pub sub: InvalidAsmTemplateModifierRegClassSub, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub enum InvalidAsmTemplateModifierRegClassSub { - #[note(ast_lowering::support_modifiers)] + #[note(ast_lowering_support_modifiers)] SupportModifier { class_name: Symbol, modifiers: String }, - #[note(ast_lowering::does_not_support_modifiers)] + #[note(ast_lowering_does_not_support_modifiers)] DoesNotSupportModifier { class_name: Symbol }, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_asm_template_modifier_const)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_invalid_asm_template_modifier_const)] pub struct InvalidAsmTemplateModifierConst { #[primary_span] - #[label(ast_lowering::template_modifier)] + #[label(ast_lowering_template_modifier)] pub placeholder_span: Span, - #[label(ast_lowering::argument)] + #[label(ast_lowering_argument)] pub op_span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_asm_template_modifier_sym)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_invalid_asm_template_modifier_sym)] pub struct InvalidAsmTemplateModifierSym { #[primary_span] - #[label(ast_lowering::template_modifier)] + #[label(ast_lowering_template_modifier)] pub placeholder_span: Span, - #[label(ast_lowering::argument)] + #[label(ast_lowering_argument)] pub op_span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::register_class_only_clobber)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_register_class_only_clobber)] pub struct RegisterClassOnlyClobber { #[primary_span] pub op_span: Span, pub reg_class_name: Symbol, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::register_conflict)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_register_conflict)] pub struct RegisterConflict<'a> { #[primary_span] - #[label(ast_lowering::register1)] + #[label(ast_lowering_register1)] pub op_span1: Span, - #[label(ast_lowering::register2)] + #[label(ast_lowering_register2)] pub op_span2: Span, pub reg1_name: &'a str, pub reg2_name: &'a str, @@ -271,14 +271,14 @@ pub struct RegisterConflict<'a> { pub in_out: Option<Span>, } -#[derive(SessionDiagnostic, Clone, Copy)] +#[derive(Diagnostic, Clone, Copy)] #[help] -#[diag(ast_lowering::sub_tuple_binding)] +#[diag(ast_lowering_sub_tuple_binding)] pub struct SubTupleBinding<'a> { #[primary_span] #[label] #[suggestion_verbose( - ast_lowering::sub_tuple_binding_suggestion, + ast_lowering_sub_tuple_binding_suggestion, code = "..", applicability = "maybe-incorrect" )] @@ -288,57 +288,57 @@ pub struct SubTupleBinding<'a> { pub ctx: &'a str, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::extra_double_dot)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_extra_double_dot)] pub struct ExtraDoubleDot<'a> { #[primary_span] #[label] pub span: Span, - #[label(ast_lowering::previously_used_here)] + #[label(ast_lowering_previously_used_here)] pub prev_span: Span, pub ctx: &'a str, } -#[derive(SessionDiagnostic, Clone, Copy)] +#[derive(Diagnostic, Clone, Copy)] #[note] -#[diag(ast_lowering::misplaced_double_dot)] +#[diag(ast_lowering_misplaced_double_dot)] pub struct MisplacedDoubleDot { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::misplaced_relax_trait_bound)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_misplaced_relax_trait_bound)] pub struct MisplacedRelaxTraitBound { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)] pub struct NotSupportedForLifetimeBinderAsyncClosure { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::arbitrary_expression_in_pattern)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_arbitrary_expression_in_pattern)] pub struct ArbitraryExpressionInPattern { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::inclusive_range_with_no_end)] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_inclusive_range_with_no_end)] pub struct InclusiveRangeWithNoEnd { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic, Clone, Copy)] -#[diag(ast_lowering::trait_fn_async, code = "E0706")] +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_trait_fn_async, code = "E0706")] #[note] -#[note(ast_lowering::note2)] +#[note(note2)] pub struct TraitFnAsync { #[primary_span] pub fn_span: Span, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7b8070d3c..ec9c39350 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -60,7 +60,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Call(f, self.lower_exprs(args)) } } - ExprKind::MethodCall(ref seg, ref args, span) => { + ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => { let hir_seg = self.arena.alloc(self.lower_path_segment( e.span, seg, @@ -68,9 +68,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ParenthesizedGenericArgs::Err, &ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); - let receiver = self.lower_expr(&args[0]); + let receiver = self.lower_expr(receiver); let args = - self.arena.alloc_from_iter(args[1..].iter().map(|x| self.lower_expr_mut(x))); + self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x))); hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span)) } ExprKind::Binary(binop, ref lhs, ref rhs) => { @@ -359,7 +359,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // Add a definition for the in-band const def. - self.create_def(parent_def_id, node_id, DefPathData::AnonConst); + self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst); let anon_const = AnonConst { id: node_id, value: arg }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); @@ -387,32 +387,58 @@ impl<'hir> LoweringContext<'_, 'hir> { then: &Block, else_opt: Option<&Expr>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.lower_expr(cond); - let new_cond = self.manage_let_cond(lowered_cond); + let lowered_cond = self.lower_cond(cond); let then_expr = self.lower_block_expr(then); if let Some(rslt) = else_opt { - hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt))) + hir::ExprKind::If( + lowered_cond, + self.arena.alloc(then_expr), + Some(self.lower_expr(rslt)), + ) } else { - hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None) + hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None) } } - // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond` - // in a temporary block. - fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> { - fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool { - match expr.kind { - hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), - hir::ExprKind::Let(..) => true, + // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope + // so that temporaries created in the condition don't live beyond it. + fn lower_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> { + fn has_let_expr(expr: &Expr) -> bool { + match &expr.kind { + ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), + ExprKind::Let(..) => true, _ => false, } } - if has_let_expr(cond) { - cond - } else { - let reason = DesugaringKind::CondTemporary; - let span_block = self.mark_span_with_reason(reason, cond.span, None); - self.expr_drop_temps(span_block, cond, AttrVec::new()) + + // We have to take special care for `let` exprs in the condition, e.g. in + // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the + // condition in this case. + // + // In order to mantain the drop behavior for the non `let` parts of the condition, + // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially + // gets transformed into `if { let _t = foo; _t } && let pat = val` + match &cond.kind { + ExprKind::Binary(op @ Spanned { node: ast::BinOpKind::And, .. }, lhs, rhs) + if has_let_expr(cond) => + { + let op = self.lower_binop(*op); + let lhs = self.lower_cond(lhs); + let rhs = self.lower_cond(rhs); + + self.arena.alloc(self.expr( + cond.span, + hir::ExprKind::Binary(op, lhs, rhs), + AttrVec::new(), + )) + } + ExprKind::Let(..) => self.lower_expr(cond), + _ => { + let cond = self.lower_expr(cond); + let reason = DesugaringKind::CondTemporary; + let span_block = self.mark_span_with_reason(reason, cond.span, None); + self.expr_drop_temps(span_block, cond, AttrVec::new()) + } } } @@ -439,14 +465,13 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond)); - let new_cond = self.manage_let_cond(lowered_cond); + let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond)); let then = self.lower_block_expr(body); let expr_break = self.expr_break(span, AttrVec::new()); let stmt_break = self.stmt_expr(span, expr_break); let else_blk = self.block_all(span, arena_vec![self; stmt_break], None); let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new())); - let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr)); + let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr)); let if_expr = self.expr(span, if_kind, AttrVec::new()); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); @@ -1044,9 +1069,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a tuple struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if partial_res.unresolved_segments() == 0 - && !partial_res.base_res().expected_in_tuple_struct_pat() - { + if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() { return None; } } @@ -1066,9 +1089,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a unit struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if partial_res.unresolved_segments() == 0 - && !partial_res.base_res().expected_in_unit_struct_pat() - { + if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() { return None; } } @@ -1609,11 +1630,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into: - /// ```rust + /// ```ignore(illustrative) /// // If there is an enclosing `try {...}`: - /// break 'catch_target FromResidual::from_residual(Yeet(residual)), + /// break 'catch_target FromResidual::from_residual(Yeet(residual)); /// // Otherwise: - /// return FromResidual::from_residual(Yeet(residual)), + /// return FromResidual::from_residual(Yeet(residual)); /// ``` /// But to simplify this, there's a `from_yeet` lang item function which /// handles the combined `FromResidual::from_residual(Yeet(residual))`. diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 85846b567..f1851d7b4 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -24,7 +24,7 @@ pub(super) struct NodeCollector<'a, 'hir> { /// The parent of this node parent_node: hir::ItemLocalId, - owner: LocalDefId, + owner: OwnerId, definitions: &'a definitions::Definitions, } @@ -81,9 +81,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_diagnostic_string(span), node, - self.definitions.def_path(self.owner).to_string_no_crate_verbose(), + self.definitions.def_path(self.owner.def_id).to_string_no_crate_verbose(), self.owner, - self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), + self.definitions.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(), hir_id.owner, ) } @@ -112,19 +112,19 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); - self.insert_nested(item.def_id); + self.insert_nested(item.owner_id.def_id); } fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { - self.insert_nested(item_id.def_id); + self.insert_nested(item_id.owner_id.def_id); } fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { - self.insert_nested(item_id.def_id); + self.insert_nested(item_id.owner_id.def_id); } fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { - self.insert_nested(foreign_id.def_id); + self.insert_nested(foreign_id.owner_id.def_id); } fn visit_nested_body(&mut self, id: BodyId) { @@ -143,7 +143,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, i: &'hir Item<'hir>) { - debug_assert_eq!(i.def_id, self.owner); + debug_assert_eq!(i.owner_id, self.owner); self.with_parent(i.hir_id(), |this| { if let ItemKind::Struct(ref struct_def, _) = i.kind { // If this is a tuple or unit-like struct, register the constructor. @@ -157,7 +157,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { - debug_assert_eq!(fi.def_id, self.owner); + debug_assert_eq!(fi.owner_id, self.owner); self.with_parent(fi.hir_id(), |this| { intravisit::walk_foreign_item(this, fi); }); @@ -176,7 +176,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { - debug_assert_eq!(ti.def_id, self.owner); + debug_assert_eq!(ti.owner_id, self.owner); self.with_parent(ti.hir_id(), |this| { intravisit::walk_trait_item(this, ti); }); @@ -184,7 +184,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { - debug_assert_eq!(ii.def_id, self.owner); + debug_assert_eq!(ii.owner_id, self.owner); self.with_parent(ii.hir_id(), |this| { intravisit::walk_impl_item(this, ii); }); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 550833275..76316a574 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,4 +1,4 @@ -use super::errors::{InvalidAbi, MisplacedRelaxTraitBound}; +use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound}; use super::ResolverAstLoweringExt; use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; @@ -14,9 +14,10 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt}; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_target::spec::abi; use smallvec::{smallvec, SmallVec}; @@ -67,7 +68,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { bodies: Vec::new(), attrs: SortedMap::default(), children: FxHashMap::default(), - current_hir_id_owner: CRATE_DEF_ID, + current_hir_id_owner: hir::CRATE_OWNER_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_local_id: Default::default(), local_id_to_def_id: SortedMap::new(), @@ -176,7 +177,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { - let mut node_ids = smallvec![hir::ItemId { def_id: self.local_def_id(i.id) }]; + let mut node_ids = + smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }]; if let ItemKind::Use(ref use_tree) = &i.kind { self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids); } @@ -192,7 +194,9 @@ impl<'hir> LoweringContext<'_, 'hir> { match tree.kind { UseTreeKind::Nested(ref nested_vec) => { for &(ref nested, id) in nested_vec { - vec.push(hir::ItemId { def_id: self.local_def_id(id) }); + vec.push(hir::ItemId { + owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, + }); self.lower_item_id_use_tree(nested, id, vec); } } @@ -201,7 +205,9 @@ impl<'hir> LoweringContext<'_, 'hir> { for (_, &id) in iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2]) { - vec.push(hir::ItemId { def_id: self.local_def_id(id) }); + vec.push(hir::ItemId { + owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, + }); } } } @@ -214,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { - def_id: hir_id.expect_owner(), + owner_id: hir_id.expect_owner(), ident: self.lower_ident(ident), kind, vis_span, @@ -539,7 +545,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let ident = *ident; let mut path = path.clone(); for seg in &mut path.segments { - seg.id = self.next_node_id(); + // Give the cloned segment the same resolution information + // as the old one (this is needed for stability checking). + let new_id = self.next_node_id(); + self.resolver.clone_res(seg.id, new_id); + seg.id = new_id; } let span = path.span; @@ -552,7 +562,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let item = hir::Item { - def_id: new_id, + owner_id: hir::OwnerId { def_id: new_id }, ident: this.lower_ident(ident), kind, vis_span, @@ -608,7 +618,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // Give the segments new node-ids since they are being cloned. for seg in &mut prefix.segments { - seg.id = self.next_node_id(); + // Give the cloned segment the same resolution information + // as the old one (this is needed for stability checking). + let new_id = self.next_node_id(); + self.resolver.clone_res(seg.id, new_id); + seg.id = new_id; } // Each `use` import is an item and thus are owners of the @@ -626,7 +640,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let item = hir::Item { - def_id: new_hir_id, + owner_id: hir::OwnerId { def_id: new_hir_id }, ident: this.lower_ident(ident), kind, vis_span, @@ -646,10 +660,10 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = self.lower_node_id(i.id); - let def_id = hir_id.expect_owner(); + let owner_id = hir_id.expect_owner(); self.lower_attrs(hir_id, &i.attrs); let item = hir::ForeignItem { - def_id, + owner_id, ident: self.lower_ident(i.ident), kind: match i.kind { ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => { @@ -688,7 +702,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef { hir::ForeignItemRef { - id: hir::ForeignItemId { def_id: self.local_def_id(i.id) }, + id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), } @@ -798,7 +812,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } - AssocItemKind::TyAlias(box TyAlias { + AssocItemKind::Type(box TyAlias { ref generics, where_clauses, ref bounds, @@ -831,7 +845,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs(hir_id, &i.attrs); let item = hir::TraitItem { - def_id: trait_item_def_id, + owner_id: trait_item_def_id, ident: self.lower_ident(i.ident), generics, kind, @@ -844,13 +858,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { let kind = match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type, + AssocItemKind::Type(..) => hir::AssocItemKind::Type, AssocItemKind::Fn(box Fn { sig, .. }) => { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::MacCall(..) => unimplemented!(), }; - let id = hir::TraitItemId { def_id: self.local_def_id(i.id) }; + let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; hir::TraitItemRef { id, ident: self.lower_ident(i.ident), @@ -892,7 +906,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, hir::ImplItemKind::Fn(sig, body_id)) } - AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { + AssocItemKind::Type(box TyAlias { generics, where_clauses, ty, .. }) => { let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, false); self.lower_generics( @@ -902,11 +916,11 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| match ty { None => { let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err)); - hir::ImplItemKind::TyAlias(ty) + hir::ImplItemKind::Type(ty) } Some(ty) => { let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy); - hir::ImplItemKind::TyAlias(ty) + hir::ImplItemKind::Type(ty) } }, ) @@ -917,7 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); let item = hir::ImplItem { - def_id: hir_id.expect_owner(), + owner_id: hir_id.expect_owner(), ident: self.lower_ident(i.ident), generics, kind, @@ -930,18 +944,21 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { hir::ImplItemRef { - id: hir::ImplItemId { def_id: self.local_def_id(i.id) }, + id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type, + AssocItemKind::Type(..) => hir::AssocItemKind::Type, AssocItemKind::Fn(box Fn { sig, .. }) => { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::MacCall(..) => unimplemented!(), }, - trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()), + trait_item_def_id: self + .resolver + .get_partial_res(i.id) + .map(|r| r.expect_full_res().def_id()), } } @@ -1049,9 +1066,9 @@ impl<'hir> LoweringContext<'_, 'hir> { asyncness: Async, body: Option<&Block>, ) -> hir::BodyId { - let closure_id = match asyncness { - Async::Yes { closure_id, .. } => closure_id, - Async::No => return self.lower_fn_body_block(span, decl, body), + let (closure_id, body) = match (asyncness, body) { + (Async::Yes { closure_id, .. }, Some(body)) => (closure_id, body), + _ => return self.lower_fn_body_block(span, decl, body), }; self.lower_body(|this| { @@ -1193,16 +1210,15 @@ impl<'hir> LoweringContext<'_, 'hir> { parameters.push(new_parameter); } - let body_span = body.map_or(span, |b| b.span); let async_expr = this.make_async_expr( CaptureBy::Value, closure_id, None, - body_span, + body.span, hir::AsyncGeneratorKind::Fn, |this| { // Create a block from the user's function body: - let user_body = this.lower_block_expr_opt(body_span, body); + let user_body = this.lower_block_expr(body); // Transform into `drop-temps { <user-body> }`, an expression: let desugared_span = @@ -1234,7 +1250,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ( this.arena.alloc_from_iter(parameters), - this.expr(body_span, async_expr, AttrVec::new()), + this.expr(body.span, async_expr, AttrVec::new()), ) }) } @@ -1280,10 +1296,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn error_on_invalid_abi(&self, abi: StrLit) { + let abi_names = abi::enabled_names(self.tcx.features(), abi.span) + .iter() + .map(|s| Symbol::intern(s)) + .collect::<Vec<_>>(); + let suggested_name = find_best_match_for_name(&abi_names, abi.symbol_unescaped, None); self.tcx.sess.emit_err(InvalidAbi { + abi: abi.symbol_unescaped, span: abi.span, - abi: abi.symbol, - valid_abis: abi::all_names().join(", "), + suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion { + span: abi.span, + suggestion: format!("\"{suggested_name}\""), + }), + command: "rustc --print=calling-conventions".to_string(), }); } @@ -1335,9 +1360,9 @@ impl<'hir> LoweringContext<'_, 'hir> { match self .resolver .get_partial_res(bound_pred.bounded_ty.id) - .map(|d| (d.base_res(), d.unresolved_segments())) + .and_then(|r| r.full_res()) { - Some((Res::Def(DefKind::TyParam, def_id), 0)) + Some(Res::Def(DefKind::TyParam, def_id)) if bound_pred.bound_generic_params.is_empty() => { generics @@ -1464,6 +1489,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let bounded_ty = self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path)); Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + hir_id: self.next_id(), bounded_ty: self.arena.alloc(bounded_ty), bounds, span, @@ -1494,6 +1520,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ref bounds, span, }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + hir_id: self.next_id(), bound_generic_params: self.lower_generic_params(bound_generic_params), bounded_ty: self .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9012aa704..ff29d15f1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,7 +32,6 @@ #![feature(box_patterns)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] @@ -62,8 +61,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DesugaringKind; @@ -126,7 +125,7 @@ struct LoweringContext<'a, 'hir> { is_in_trait_impl: bool, is_in_dyn_type: bool, - current_hir_id_owner: LocalDefId, + current_hir_id_owner: hir::OwnerId, item_local_id_counter: hir::ItemLocalId, local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>, @@ -161,6 +160,10 @@ trait ResolverAstLoweringExt { fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>; fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>; fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>; + // Clones the resolution (if any) on 'source' and applies it + // to 'target'. Used when desugaring a `UseTreeKind::Nested` to + // multiple `UseTreeKind::Simple`s + fn clone_res(&mut self, source: NodeId, target: NodeId); fn get_label_res(&self, id: NodeId) -> Option<NodeId>; fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>; fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; @@ -176,12 +179,7 @@ impl ResolverAstLoweringExt for ResolverAstLowering { return None; } - let partial_res = self.partial_res_map.get(&expr.id)?; - if partial_res.unresolved_segments() != 0 { - return None; - } - - if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() { + if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? { // We only support cross-crate argument rewriting. Uses // within the same crate should be updated to use the new // const generics style. @@ -198,6 +196,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering { None } + fn clone_res(&mut self, source: NodeId, target: NodeId) { + if let Some(res) = self.partial_res_map.get(&source) { + self.partial_res_map.insert(target, *res); + } + } + /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> { self.partial_res_map.get(&id).copied() @@ -324,17 +328,20 @@ enum FnDeclKind { } impl FnDeclKind { - fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool { + fn impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool { match self { FnDeclKind::Fn | FnDeclKind::Inherent => true, FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true, + FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true, _ => false, } } - fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool { + fn async_fn_allowed(&self, tcx: TyCtxt<'_>) -> bool { match self { - FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true, + FnDeclKind::Fn | FnDeclKind::Inherent => true, + FnDeclKind::Impl if tcx.features().async_fn_in_trait => true, + FnDeclKind::Trait if tcx.features().async_fn_in_trait => true, _ => false, } } @@ -572,7 +579,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let current_trait_map = std::mem::take(&mut self.trait_map); - let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id); + let current_owner = + std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); let current_local_counter = std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); @@ -587,7 +595,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug_assert_eq!(_old, None); let item = f(self); - debug_assert_eq!(def_id, item.def_id()); + debug_assert_eq!(def_id, item.def_id().def_id); // `f` should have consumed all the elements in these vectors when constructing `item`. debug_assert!(self.impl_trait_defs.is_empty()); debug_assert!(self.impl_trait_bounds.is_empty()); @@ -753,12 +761,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> { - self.resolver.get_partial_res(id).map_or(Res::Err, |pr| { - if pr.unresolved_segments() != 0 { - panic!("path not fully resolved: {:?}", pr); - } - pr.base_res() - }) + self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res()) } fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> { @@ -786,7 +789,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { if self.tcx.sess.opts.unstable_opts.incremental_relative_spans { - span.with_parent(Some(self.current_hir_id_owner)) + span.with_parent(Some(self.current_hir_id_owner.def_id)) } else { // Do not make spans relative when not using incremental compilation. span @@ -812,7 +815,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, .. } => { // Late resolution delegates to us the creation of the `LocalDefId`. let _def_id = self.create_def( - self.current_hir_id_owner, + self.current_hir_id_owner.def_id, param, DefPathData::LifetimeNs(kw::UnderscoreLifetime), ); @@ -1060,9 +1063,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by // constructing the HIR for `impl bounds...` and then lowering that. - let parent_def_id = self.current_hir_id_owner; let impl_trait_node_id = self.next_node_id(); - self.create_def(parent_def_id, impl_trait_node_id, DefPathData::ImplTrait); self.with_dyn_type_scope(false, |this| { let node_id = this.next_node_id(); @@ -1140,8 +1141,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // type and value namespaces. If we resolved the path in the value namespace, we // transform it into a generic const argument. TyKind::Path(ref qself, ref path) => { - if let Some(partial_res) = self.resolver.get_partial_res(ty.id) { - let res = partial_res.base_res(); + if let Some(res) = self + .resolver + .get_partial_res(ty.id) + .and_then(|partial_res| partial_res.full_res()) + { if !res.matches_ns(Namespace::TypeNS) { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -1154,7 +1158,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let node_id = self.next_node_id(); // Add a definition for the in-band const def. - self.create_def(parent_def_id, node_id, DefPathData::AnonConst); + self.create_def( + parent_def_id.def_id, + node_id, + DefPathData::AnonConst, + ); let span = self.lower_span(ty.span); let path_expr = Expr { @@ -1204,8 +1212,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // by `ty_path`. if qself.is_none() && let Some(partial_res) = self.resolver.get_partial_res(t.id) - && partial_res.unresolved_segments() == 0 - && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() + && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef { @@ -1349,9 +1356,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { def_node_id, bounds, false, - &ImplTraitContext::TypeAliasesOpaqueTy, + itctx, ), ImplTraitContext::Universal => { + self.create_def( + self.current_hir_id_owner.def_id, + def_node_id, + DefPathData::ImplTrait, + ); let span = t.span; let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); let (param, bounds, path) = @@ -1445,7 +1457,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id); + let opaque_ty_def_id = match origin { + hir::OpaqueTyOrigin::TyAlias => self.create_def( + self.current_hir_id_owner.def_id, + opaque_ty_node_id, + DefPathData::ImplTrait, + ), + hir::OpaqueTyOrigin::FnReturn(fn_def_id) => { + self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait) + } + hir::OpaqueTyOrigin::AsyncFn(..) => bug!("unreachable"), + }; debug!(?opaque_ty_def_id); // Contains the new lifetime definitions created for the TAIT (if any). @@ -1551,7 +1573,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!(?lifetimes); // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. - hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait) + hir::TyKind::OpaqueDef( + hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, + lifetimes, + in_trait, + ) } /// Registers a new opaque type with the proper `NodeId`s and @@ -1567,7 +1593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Generate an `type Foo = impl Trait;` declaration. trace!("registering opaque type with id {:#?}", opaque_ty_id); let opaque_ty_item = hir::Item { - def_id: opaque_ty_id, + owner_id: hir::OwnerId { def_id: opaque_ty_id }, ident: Ident::empty(), kind: opaque_ty_item_kind, vis_span: self.lower_span(span.shrink_to_lo()), @@ -1701,62 +1727,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { })); let output = if let Some((ret_id, span)) = make_ret_async { - match kind { - FnDeclKind::Trait => { - if !kind.impl_trait_in_trait_allowed(self.tcx) { + if !kind.async_fn_allowed(self.tcx) { + match kind { + FnDeclKind::Trait | FnDeclKind::Impl => { self.tcx .sess .create_feature_err( TraitFnAsync { fn_span, span }, - sym::return_position_impl_trait_in_trait, + sym::async_fn_in_trait, ) .emit(); } - self.lower_async_fn_ret_ty( - &decl.output, - fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), - ret_id, - true, - ) - } - _ => { - if !kind.impl_trait_return_allowed(self.tcx) { - if kind == FnDeclKind::Impl { - self.tcx - .sess - .create_feature_err( - TraitFnAsync { fn_span, span }, - sym::return_position_impl_trait_in_trait, - ) - .emit(); - } else { - self.tcx.sess.emit_err(TraitFnAsync { fn_span, span }); - } + _ => { + self.tcx.sess.emit_err(TraitFnAsync { fn_span, span }); } - self.lower_async_fn_ret_ty( - &decl.output, - fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), - ret_id, - false, - ) } } + + self.lower_async_fn_ret_ty( + &decl.output, + fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), + ret_id, + matches!(kind, FnDeclKind::Trait), + ) } else { match decl.output { FnRetTy::Ty(ref ty) => { let mut context = match fn_node_id { - Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => { - let fn_def_id = self.local_def_id(fn_node_id); - ImplTraitContext::ReturnPositionOpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait: false, - } - } - Some(fn_node_id) if kind.impl_trait_in_trait_allowed(self.tcx) => { + Some(fn_node_id) if kind.impl_trait_allowed(self.tcx) => { let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait: true, + in_trait: matches!(kind, FnDeclKind::Trait), } } _ => ImplTraitContext::Disallowed(match kind { @@ -1950,9 +1952,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let future_bound = this.lower_async_fn_output_type_to_future_bound( output, span, - ImplTraitContext::ReturnPositionOpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait, + if in_trait && !this.tcx.features().return_position_impl_trait_in_trait { + ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn) + } else { + ImplTraitContext::ReturnPositionOpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + in_trait, + } }, ); @@ -2038,7 +2044,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // async fn, so the *type parameters* are inherited. It's // only the lifetime parameters that we must supply. let opaque_ty_ref = hir::TyKind::OpaqueDef( - hir::ItemId { def_id: opaque_ty_def_id }, + hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, generic_args, in_trait, ); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 1ea76fdbf..1af1633b5 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -239,7 +239,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { - match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) { + match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) { // `None` can occur in body-less function signatures res @ (None | Some(Res::Local(_))) => { let canonical_id = match res { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6bb1bb9ea..888776ccc 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -29,11 +29,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); + let base_res = partial_res.base_res(); + let unresolved_segments = partial_res.unresolved_segments(); let path_span_lo = p.span.shrink_to_lo(); - let proj_start = p.segments.len() - partial_res.unresolved_segments(); + let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { - res: self.lower_res(partial_res.base_res()), + res: self.lower_res(base_res), segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( |(i, segment)| { let param_mode = match (qself_position, param_mode) { @@ -46,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => param_mode, }; - let parenthesized_generic_args = match partial_res.base_res() { + let parenthesized_generic_args = match base_res { // `a::b::Trait(Args)` Res::Def(DefKind::Trait, _) if i + 1 == proj_start => { ParenthesizedGenericArgs::Ok @@ -83,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Simple case, either no projections, or only fully-qualified. // E.g., `std::mem::size_of` or `<I as Iterator>::Item`. - if partial_res.unresolved_segments() == 0 { + if unresolved_segments == 0 { return hir::QPath::Resolved(qself, path); } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b1d10e07a..036643244 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -14,6 +14,7 @@ use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; +use rustc_macros::Subdiagnostic; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -38,6 +39,13 @@ enum SelfSemantic { No, } +/// What is the context that prevents using `~const`? +enum DisallowTildeConstContext<'a> { + TraitObject, + ImplTrait, + Fn(FnKind<'a>), +} + struct AstValidator<'a> { session: &'a Session, @@ -56,7 +64,7 @@ struct AstValidator<'a> { /// e.g., `impl Iterator<Item = impl Debug>`. outer_impl_trait: Option<Span>, - is_tilde_const_allowed: bool, + disallow_tilde_const: Option<DisallowTildeConstContext<'a>>, /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` /// or `Foo::Bar<impl Trait>` @@ -93,18 +101,26 @@ impl<'a> AstValidator<'a> { self.is_impl_trait_banned = old; } - fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_tilde_const_allowed, allowed); + fn with_tilde_const( + &mut self, + disallowed: Option<DisallowTildeConstContext<'a>>, + f: impl FnOnce(&mut Self), + ) { + let old = mem::replace(&mut self.disallow_tilde_const, disallowed); f(self); - self.is_tilde_const_allowed = old; + self.disallow_tilde_const = old; } fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { - self.with_tilde_const(true, f) + self.with_tilde_const(None, f) } - fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) { - self.with_tilde_const(false, f) + fn with_banned_tilde_const( + &mut self, + ctx: DisallowTildeConstContext<'a>, + f: impl FnOnce(&mut Self), + ) { + self.with_tilde_const(Some(ctx), f) } fn with_let_management( @@ -154,7 +170,7 @@ impl<'a> AstValidator<'a> { DEPRECATED_WHERE_CLAUSE_LOCATION, id, where_clauses.0.1, - fluent::ast_passes::deprecated_where_clause_location, + fluent::ast_passes_deprecated_where_clause_location, BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( where_clauses.1.1.shrink_to_hi(), suggestion, @@ -172,7 +188,7 @@ impl<'a> AstValidator<'a> { fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.outer_impl_trait, outer); if outer.is_some() { - self.with_banned_tilde_const(f); + self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f); } else { f(self); } @@ -197,7 +213,10 @@ impl<'a> AstValidator<'a> { TyKind::ImplTrait(..) => { self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) } - TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)), + TyKind::TraitObject(..) => self + .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| { + visit::walk_ty(this, t) + }), TyKind::Path(ref qself, ref path) => { // We allow these: // - `Option<impl Trait>` @@ -233,20 +252,6 @@ impl<'a> AstValidator<'a> { } } - fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident { - if ident.name == kw::Underscore { - self.visit_vis(&field.vis); - self.visit_ident(ident); - self.visit_ty_common(&field.ty); - self.walk_ty(&field.ty); - walk_list!(self, visit_attribute, &field.attrs); - return; - } - } - self.visit_field_def(field); - } - fn err_handler(&self) -> &rustc_errors::Handler { &self.session.diagnostic() } @@ -987,8 +992,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_lifetime(self, lifetime); } - fn visit_field_def(&mut self, s: &'a FieldDef) { - visit::walk_field_def(self, s) + fn visit_field_def(&mut self, field: &'a FieldDef) { + visit::walk_field_def(self, field) } fn visit_item(&mut self, item: &'a Item) { @@ -1176,42 +1181,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_mod_file_item_asciionly(item.ident); } } - ItemKind::Struct(ref vdata, ref generics) => match vdata { - // Duplicating the `Visitor` logic allows catching all cases - // of `Anonymous(Struct, Union)` outside of a field struct or union. - // - // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it - // encounters, and only on `ItemKind::Struct` and `ItemKind::Union` - // it uses `visit_ty_common`, which doesn't contain that specific check. - VariantData::Struct(ref fields, ..) => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.visit_generics(generics); - self.with_banned_assoc_ty_bound(|this| { - walk_list!(this, visit_struct_field_def, fields); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; - } - _ => {} - }, - ItemKind::Union(ref vdata, ref generics) => { + ItemKind::Union(ref vdata, ..) => { if vdata.fields().is_empty() { self.err_handler().span_err(item.span, "unions cannot have zero fields"); } - match vdata { - VariantData::Struct(ref fields, ..) => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.visit_generics(generics); - self.with_banned_assoc_ty_bound(|this| { - walk_list!(this, visit_struct_field_def, fields); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; - } - _ => {} - } } ItemKind::Const(def, .., None) => { self.check_defaultness(item.span, def); @@ -1411,13 +1384,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); err.emit(); } - (_, TraitBoundModifier::MaybeConst) => { - if !self.is_tilde_const_allowed { - self.err_handler() - .struct_span_err(bound.span(), "`~const` is not allowed here") - .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions") - .emit(); - } + (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => { + let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here"); + match reason { + DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"), + DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"), + DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"), + DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"), + }; + err.emit(); } (_, TraitBoundModifier::MaybeConstMaybe) => { self.err_handler() @@ -1524,10 +1499,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } let tilde_const_allowed = - matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. })) + matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); - self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk)); + let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); + + self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { @@ -1557,7 +1534,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } } - AssocItemKind::TyAlias(box TyAlias { + AssocItemKind::Type(box TyAlias { generics, where_clauses, where_predicates_split, @@ -1596,7 +1573,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } match item.kind { - AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) + AssocItemKind::Type(box TyAlias { ref generics, ref bounds, ref ty, .. }) if ctxt == AssocCtxt::Trait => { self.visit_vis(&item.vis); @@ -1771,7 +1748,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> in_const_trait_impl: false, has_proc_macro_decls: false, outer_impl_trait: None, - is_tilde_const_allowed: false, + disallow_tilde_const: None, is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden), @@ -1783,15 +1760,17 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> } /// Used to forbid `let` expressions in certain syntactic locations. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator - NotSupportedOr(Span), + #[note(not_supported_or)] + NotSupportedOr(#[primary_span] Span), /// A let chain with invalid parentheses /// /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not - NotSupportedParentheses(Span), + #[note(not_supported_parentheses)] + NotSupportedParentheses(#[primary_span] Span), } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 4f3b09c58..59f582f10 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,13 +1,13 @@ //! Errors emitted by ast_passes. -use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::ast_validation::ForbiddenLetReason; -#[derive(SessionDiagnostic)] -#[diag(ast_passes::forbidden_let)] +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_let)] #[note] pub struct ForbiddenLet { #[primary_span] @@ -16,130 +16,116 @@ pub struct ForbiddenLet { pub(crate) reason: ForbiddenLetReason, } -impl AddSubdiagnostic for ForbiddenLetReason { - fn add_to_diagnostic(self, diag: &mut Diagnostic) { - match self { - Self::GenericForbidden => {} - Self::NotSupportedOr(span) => { - diag.span_note(span, fluent::ast_passes::not_supported_or); - } - Self::NotSupportedParentheses(span) => { - diag.span_note(span, fluent::ast_passes::not_supported_parentheses); - } - } - } -} - -#[derive(SessionDiagnostic)] -#[diag(ast_passes::forbidden_let_stable)] +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_let_stable)] #[note] pub struct ForbiddenLetStable { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::forbidden_assoc_constraint)] +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_assoc_constraint)] pub struct ForbiddenAssocConstraint { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::keyword_lifetime)] +#[derive(Diagnostic)] +#[diag(ast_passes_keyword_lifetime)] pub struct KeywordLifetime { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::invalid_label)] +#[derive(Diagnostic)] +#[diag(ast_passes_invalid_label)] pub struct InvalidLabel { #[primary_span] pub span: Span, pub name: Symbol, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::invalid_visibility, code = "E0449")] +#[derive(Diagnostic)] +#[diag(ast_passes_invalid_visibility, code = "E0449")] pub struct InvalidVisibility { #[primary_span] pub span: Span, - #[label(ast_passes::implied)] + #[label(implied)] pub implied: Option<Span>, #[subdiagnostic] pub note: Option<InvalidVisibilityNote>, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub enum InvalidVisibilityNote { - #[note(ast_passes::individual_impl_items)] + #[note(individual_impl_items)] IndividualImplItems, - #[note(ast_passes::individual_foreign_items)] + #[note(individual_foreign_items)] IndividualForeignItems, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::trait_fn_const, code = "E0379")] +#[derive(Diagnostic)] +#[diag(ast_passes_trait_fn_const, code = "E0379")] pub struct TraitFnConst { #[primary_span] #[label] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::forbidden_lifetime_bound)] +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_lifetime_bound)] pub struct ForbiddenLifetimeBound { #[primary_span] pub spans: Vec<Span>, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::forbidden_non_lifetime_param)] +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_non_lifetime_param)] pub struct ForbiddenNonLifetimeParam { #[primary_span] pub spans: Vec<Span>, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_param_too_many)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_param_too_many)] pub struct FnParamTooMany { #[primary_span] pub span: Span, pub max_num_args: usize, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_param_c_var_args_only)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_param_c_var_args_only)] pub struct FnParamCVarArgsOnly { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_param_c_var_args_not_last)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_param_c_var_args_not_last)] pub struct FnParamCVarArgsNotLast { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_param_doc_comment)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_param_doc_comment)] pub struct FnParamDocComment { #[primary_span] #[label] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_param_forbidden_attr)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_param_forbidden_attr)] pub struct FnParamForbiddenAttr { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_param_forbidden_self)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_param_forbidden_self)] #[note] pub struct FnParamForbiddenSelf { #[primary_span] @@ -147,8 +133,8 @@ pub struct FnParamForbiddenSelf { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::forbidden_default)] +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_default)] pub struct ForbiddenDefault { #[primary_span] pub span: Span, @@ -156,8 +142,8 @@ pub struct ForbiddenDefault { pub def_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::assoc_const_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_assoc_const_without_body)] pub struct AssocConstWithoutBody { #[primary_span] pub span: Span, @@ -165,8 +151,8 @@ pub struct AssocConstWithoutBody { pub replace_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::assoc_fn_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_assoc_fn_without_body)] pub struct AssocFnWithoutBody { #[primary_span] pub span: Span, @@ -174,8 +160,8 @@ pub struct AssocFnWithoutBody { pub replace_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::assoc_type_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_assoc_type_without_body)] pub struct AssocTypeWithoutBody { #[primary_span] pub span: Span, @@ -183,8 +169,8 @@ pub struct AssocTypeWithoutBody { pub replace_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::const_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_const_without_body)] pub struct ConstWithoutBody { #[primary_span] pub span: Span, @@ -192,8 +178,8 @@ pub struct ConstWithoutBody { pub replace_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::static_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_static_without_body)] pub struct StaticWithoutBody { #[primary_span] pub span: Span, @@ -201,8 +187,8 @@ pub struct StaticWithoutBody { pub replace_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::ty_alias_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_ty_alias_without_body)] pub struct TyAliasWithoutBody { #[primary_span] pub span: Span, @@ -210,8 +196,8 @@ pub struct TyAliasWithoutBody { pub replace_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(ast_passes::fn_without_body)] +#[derive(Diagnostic)] +#[diag(ast_passes_fn_without_body)] pub struct FnWithoutBody { #[primary_span] pub span: Span, @@ -227,8 +213,11 @@ pub struct ExternBlockSuggestion { pub abi: Option<Symbol>, } -impl AddSubdiagnostic for ExternBlockSuggestion { - fn add_to_diagnostic(self, diag: &mut Diagnostic) { +impl AddToDiagnostic for ExternBlockSuggestion { + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { let start_suggestion = if let Some(abi) = self.abi { format!("extern \"{}\" {{", abi) } else { @@ -237,7 +226,7 @@ impl AddSubdiagnostic for ExternBlockSuggestion { let end_suggestion = " }".to_owned(); diag.multipart_suggestion( - fluent::ast_passes::extern_block_suggestion, + fluent::extern_block_suggestion, vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)], Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index aeff73c5b..546010135 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,15 +1,15 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; -use rustc_ast::{PatKind, RangeEnd, VariantData}; +use rustc_ast::{PatKind, RangeEnd}; use rustc_errors::{struct_span_err, Applicability, StashKey}; -use rustc_feature::Features; -use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_session::parse::{feature_err, feature_warn}; +use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; +use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_target::spec::abi; macro_rules! gate_feature_fn { ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ @@ -84,210 +84,26 @@ impl<'a> PostExpansionVisitor<'a> { } } - match symbol_unescaped.as_str() { - // Stable - "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64" - | "system" => {} - "rust-intrinsic" => { - gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change"); - } - "platform-intrinsic" => { - gate_feature_post!( - &self, - platform_intrinsics, - span, - "platform intrinsics are experimental and possibly buggy" - ); - } - "vectorcall" => { - gate_feature_post!( - &self, - abi_vectorcall, - span, - "vectorcall is experimental and subject to change" - ); - } - "thiscall" => { - gate_feature_post!( - &self, - abi_thiscall, - span, - "thiscall is experimental and subject to change" - ); - } - "rust-call" => { - gate_feature_post!( - &self, - unboxed_closures, - span, - "rust-call ABI is subject to change" - ); - } - "rust-cold" => { - gate_feature_post!( - &self, - rust_cold_cc, - span, - "rust-cold is experimental and subject to change" - ); - } - "ptx-kernel" => { - gate_feature_post!( - &self, - abi_ptx, - span, - "PTX ABIs are experimental and subject to change" - ); - } - "unadjusted" => { - gate_feature_post!( - &self, - abi_unadjusted, - span, - "unadjusted ABI is an implementation detail and perma-unstable" - ); - } - "msp430-interrupt" => { - gate_feature_post!( - &self, - abi_msp430_interrupt, - span, - "msp430-interrupt ABI is experimental and subject to change" - ); - } - "x86-interrupt" => { - gate_feature_post!( - &self, - abi_x86_interrupt, - span, - "x86-interrupt ABI is experimental and subject to change" - ); - } - "amdgpu-kernel" => { - gate_feature_post!( - &self, - abi_amdgpu_kernel, - span, - "amdgpu-kernel ABI is experimental and subject to change" - ); - } - "avr-interrupt" | "avr-non-blocking-interrupt" => { - gate_feature_post!( - &self, - abi_avr_interrupt, - span, - "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change" - ); - } - "efiapi" => { - gate_feature_post!( - &self, - abi_efiapi, - span, - "efiapi ABI is experimental and subject to change" - ); - } - "C-cmse-nonsecure-call" => { - gate_feature_post!( - &self, - abi_c_cmse_nonsecure_call, + match abi::is_enabled(&self.features, span, symbol_unescaped.as_str()) { + Ok(()) => (), + Err(abi::AbiDisabled::Unstable { feature, explain }) => { + feature_err_issue( + &self.sess.parse_sess, + feature, span, - "C-cmse-nonsecure-call ABI is experimental and subject to change" - ); - } - "C-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "C-unwind ABI is experimental and subject to change" - ); - } - "stdcall-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "stdcall-unwind ABI is experimental and subject to change" - ); - } - "system-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "system-unwind ABI is experimental and subject to change" - ); - } - "thiscall-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "thiscall-unwind ABI is experimental and subject to change" - ); - } - "cdecl-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "cdecl-unwind ABI is experimental and subject to change" - ); - } - "fastcall-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "fastcall-unwind ABI is experimental and subject to change" - ); - } - "vectorcall-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "vectorcall-unwind ABI is experimental and subject to change" - ); - } - "aapcs-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "aapcs-unwind ABI is experimental and subject to change" - ); - } - "win64-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "win64-unwind ABI is experimental and subject to change" - ); - } - "sysv64-unwind" => { - gate_feature_post!( - &self, - c_unwind, - span, - "sysv64-unwind ABI is experimental and subject to change" - ); - } - "wasm" => { - gate_feature_post!( - &self, - wasm_abi, - span, - "wasm ABI is experimental and subject to change" - ); + GateIssue::Language, + explain, + ) + .emit(); } - abi => { + Err(abi::AbiDisabled::Unrecognized) => { if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { self.sess.parse_sess.span_diagnostic.delay_span_bug( span, - &format!("unrecognized ABI not caught in lowering: {}", abi), + &format!( + "unrecognized ABI not caught in lowering: {}", + symbol_unescaped.as_str() + ), ); } } @@ -300,46 +116,6 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { - let has_fields = variants.iter().any(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => true, - VariantData::Unit(..) => false, - }); - - let discriminant_spans = variants - .iter() - .filter(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => false, - VariantData::Unit(..) => true, - }) - .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) - .collect::<Vec<_>>(); - - if !discriminant_spans.is_empty() && has_fields { - let mut err = feature_err( - &self.sess.parse_sess, - sym::arbitrary_enum_discriminant, - discriminant_spans.clone(), - "custom discriminant values are not allowed in enums with tuple or struct variants", - ); - for sp in discriminant_spans { - err.span_label(sp, "disallowed custom discriminant"); - } - for variant in variants.iter() { - match &variant.data { - VariantData::Struct(..) => { - err.span_label(variant.span, "struct variant defined here"); - } - VariantData::Tuple(..) => { - err.span_label(variant.span, "tuple variant defined here"); - } - VariantData::Unit(..) => {} - } - } - err.emit(); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty) { struct ImplTraitVisitor<'a> { @@ -457,26 +233,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => { - for variant in variants { - match (&variant.data, &variant.disr_expr) { - (ast::VariantData::Unit(..), _) => {} - (_, Some(disr_expr)) => gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental" - ), - _ => {} - } - } - - let has_feature = self.features.arbitrary_enum_discriminant; - if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - self.maybe_report_invalid_custom_discriminants(&variants); - } - } - ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => { if let ast::ImplPolarity::Negative(span) = polarity { gate_feature_post!( @@ -645,7 +401,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind { gate_feature_post!( &self, - half_open_range_patterns, + half_open_range_patterns_in_slices, pat.span, "`X..` patterns in slices are experimental" ); @@ -701,7 +457,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match i.kind { ast::AssocItemKind::Fn(_) => true, - ast::AssocItemKind::TyAlias(box ast::TyAlias { ref ty, .. }) => { + ast::AssocItemKind::Type(box ast::TyAlias { ref ty, .. }) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, @@ -773,7 +529,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(generators, "yield syntax is experimental"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); - gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); + gate_all!( + half_open_range_patterns_in_slices, + "half-open range patterns in slices are unstable" + ); gate_all!(inline_const, "inline-const is experimental"); gate_all!(inline_const_pat, "inline-const in pattern position is experimental"); gate_all!(associated_const_equality, "associated const equality is incomplete"); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 8aa9d57f0..f58fffc91 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -9,7 +9,6 @@ #![feature(if_let_guard)] #![feature(iter_is_partitioned)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 5ad8714e9..a3e3e823b 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [lib] -doctest = false [dependencies] rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ead38caee..bcefa8ce0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -193,9 +193,13 @@ impl<'a> State<'a> { self.print_call_post(args) } - fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) { - let base_args = &args[1..]; - self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); + fn print_expr_method_call( + &mut self, + segment: &ast::PathSegment, + receiver: &ast::Expr, + base_args: &[P<ast::Expr>], + ) { + self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX); self.word("."); self.print_ident(segment.ident); if let Some(ref args) = segment.args { @@ -303,8 +307,8 @@ impl<'a> State<'a> { ast::ExprKind::Call(ref func, ref args) => { self.print_expr_call(func, &args); } - ast::ExprKind::MethodCall(ref segment, ref args, _) => { - self.print_expr_method_call(segment, &args); + ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => { + self.print_expr_method_call(segment, &receiver, &args); } ast::ExprKind::Binary(op, ref lhs, ref rhs) => { self.print_expr_binary(op, lhs, rhs); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 54bac29a6..159853c9e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -516,7 +516,7 @@ impl<'a> State<'a> { ast::AssocItemKind::Const(def, ty, body) => { self.print_item_const(ident, None, ty, body.as_deref(), vis, *def); } - ast::AssocItemKind::TyAlias(box ast::TyAlias { + ast::AssocItemKind::Type(box ast::TyAlias { defaultness, generics, where_clauses, |