diff options
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
43 files changed, 1292 insertions, 905 deletions
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index bc94e0b972b..4721e74b955 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -3,13 +3,13 @@ use crate::util::check_builtin_macro_attribute; use rustc_ast::ptr::P; use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind}; -use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe}; +use rustc_ast::{Fn, ItemKind, Safety, Stmt, TyKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand( +pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, _span: Span, meta_item: &ast::MetaItem, @@ -78,7 +78,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; let decl = cx.fn_decl(params, never); - let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() }; + let header = FnHeader { safety: Safety::Unsafe(span), ..FnHeader::default() }; let sig = FnSig { decl, header, span: span }; let body = Some(cx.block_expr(call)); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 0b2e63b403b..1a7961bf70c 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,23 +1,24 @@ +use crate::errors; +use crate::util::expr_to_spanned_string; +use ast::token::IdentIsRaw; +use lint::BuiltinLintDiag; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::PResult; -use rustc_expand::base::{self, *}; +use rustc_expand::base::*; use rustc_index::bit_set::GrowableBitSet; use rustc_parse::parser::Parser; use rustc_parse_format as parse; use rustc_session::lint; -use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{InnerSpan, Span}; +use rustc_span::{ErrorGuaranteed, InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; -use crate::errors; - pub struct AsmArgs { pub templates: Vec<P<ast::Expr>>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, @@ -29,25 +30,23 @@ pub struct AsmArgs { } fn parse_args<'a>( - ecx: &mut ExtCtxt<'a>, + ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream, is_global_asm: bool, ) -> PResult<'a, AsmArgs> { let mut p = ecx.new_parser_from_tts(tts); - let sess = &ecx.sess.parse_sess; - parse_asm_args(&mut p, sess, sp, is_global_asm) + parse_asm_args(&mut p, sp, is_global_asm) } // Primarily public for rustfmt consumption. // Internal consumers should continue to leverage `expand_asm`/`expand__global_asm` pub fn parse_asm_args<'a>( p: &mut Parser<'a>, - sess: &'a ParseSess, sp: Span, is_global_asm: bool, ) -> PResult<'a, AsmArgs> { - let dcx = &sess.dcx; + let dcx = &p.psess.dcx; if p.token == token::Eof { return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp })); @@ -166,6 +165,9 @@ pub fn parse_asm_args<'a>( path: path.clone(), }; ast::InlineAsmOperand::Sym { sym } + } else if !is_global_asm && p.eat_keyword(sym::label) { + let block = p.parse_block()?; + ast::InlineAsmOperand::Label { block } } else if allow_templates { let template = p.parse_expr()?; // If it can't possibly expand to a string, provide diagnostics here to include other @@ -188,7 +190,7 @@ pub fn parse_asm_args<'a>( args.templates.push(template); continue; } else { - return p.unexpected(); + p.unexpected_any()? }; allow_templates = false; @@ -242,6 +244,7 @@ pub fn parse_asm_args<'a>( let mut have_real_output = false; let mut outputs_sp = vec![]; let mut regclass_outputs = vec![]; + let mut labels_sp = vec![]; for (op, op_sp) in &args.operands { match op { ast::InlineAsmOperand::Out { reg, expr, .. } @@ -259,6 +262,9 @@ pub fn parse_asm_args<'a>( regclass_outputs.push(*op_sp); } } + ast::InlineAsmOperand::Label { .. } => { + labels_sp.push(*op_sp); + } _ => {} } } @@ -270,6 +276,9 @@ pub fn parse_asm_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } + if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() { + dcx.emit_err(errors::AsmMayUnwind { labels_sp }); + } if args.clobber_abis.len() > 0 { if is_global_asm { @@ -295,10 +304,10 @@ pub fn parse_asm_args<'a>( /// /// This function must be called immediately after the option token is parsed. /// Otherwise, the suggestion will be incorrect. -fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) { +fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { // Tool-only output let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; - p.sess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); + p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } /// Try to set the provided option in the provided `AsmArgs`. @@ -307,7 +316,7 @@ fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) { /// This function must be called immediately after the option token is parsed. /// Otherwise, the error will not point to the correct spot. fn try_set_option<'a>( - p: &mut Parser<'a>, + p: &Parser<'a>, args: &mut AsmArgs, symbol: Symbol, option: ast::InlineAsmOptions, @@ -370,7 +379,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - return Err(p.sess.dcx.create_err(errors::NonABI { span: p.token.span })); + return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span })); } let mut new_abis = Vec::new(); @@ -381,7 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, } Err(opt_lit) => { let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.sess.dcx.struct_span_err(span, "expected string literal"); + let mut err = p.psess.dcx.struct_span_err(span, "expected string literal"); err.span_label(span, "not a string literal"); return Err(err); } @@ -416,7 +425,7 @@ fn parse_reg<'a>( ) -> PResult<'a, ast::InlineAsmRegOrRegClass> { p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; let result = match p.token.uninterpolate().kind { - token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), + token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name), token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { *explicit_reg = true; ast::InlineAsmRegOrRegClass::Reg(symbol) @@ -432,7 +441,10 @@ fn parse_reg<'a>( Ok(result) } -fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::InlineAsm> { +fn expand_preparsed_asm( + ecx: &mut ExtCtxt<'_>, + args: AsmArgs, +) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> { let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be // referenced in the template string. @@ -454,16 +466,20 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl let msg = "asm template must be a string literal"; let template_sp = template_expr.span; - let (template_str, template_style, template_span) = - match expr_to_spanned_string(ecx, template_expr, msg) { + let (template_str, template_style, template_span) = { + let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else { + return ExpandResult::Retry(()); + }; + match mac { Ok(template_part) => template_part, Err(err) => { - if let Some((err, _)) = err { - err.emit(); - } - return None; + return ExpandResult::Ready(Err(match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + })); } - }; + } + }; let str_style = match template_style { ast::StrStyle::Cooked => None, @@ -494,19 +510,19 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl }; if template_str.contains(".intel_syntax") { - ecx.parse_sess().buffer_lint( + ecx.psess().buffer_lint( lint::builtin::BAD_ASM_STYLE, find_span(".intel_syntax"), ecx.current_expansion.lint_node_id, - "avoid using `.intel_syntax`, Intel syntax is the default", + BuiltinLintDiag::AvoidUsingIntelSyntax, ); } if template_str.contains(".att_syntax") { - ecx.parse_sess().buffer_lint( + ecx.psess().buffer_lint( lint::builtin::BAD_ASM_STYLE, find_span(".att_syntax"), ecx.current_expansion.lint_node_id, - "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead", + BuiltinLintDiag::AvoidUsingAttSyntax, ); } } @@ -550,8 +566,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end)); e.span_label(err_sp, label); } - e.emit(); - return None; + let guar = e.emit(); + return ExpandResult::Ready(Err(guar)); } curarg = parser.curarg; @@ -718,52 +734,57 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl } } - Some(ast::InlineAsm { + ExpandResult::Ready(Ok(ast::InlineAsm { template, template_strs: template_strs.into_boxed_slice(), operands: args.operands, clobber_abis: args.clobber_abis, options: args.options, line_spans, - }) + })) } pub(super) fn expand_asm<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { - match parse_args(ecx, sp, tts, false) { +) -> MacroExpanderResult<'cx> { + ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { Ok(args) => { - let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { - P(ast::Expr { + let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { + return ExpandResult::Retry(()); + }; + let expr = match mac { + Ok(inline_asm) => P(ast::Expr { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::InlineAsm(P(inline_asm)), span: sp, attrs: ast::AttrVec::new(), tokens: None, - }) - } else { - DummyResult::raw_expr(sp, true) + }), + Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } - } + }) } pub(super) fn expand_global_asm<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { - match parse_args(ecx, sp, tts, true) { +) -> MacroExpanderResult<'cx> { + ExpandResult::Ready(match parse_args(ecx, sp, tts, true) { Ok(args) => { - if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { - MacEager::items(smallvec![P(ast::Item { + let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { + return ExpandResult::Retry(()); + }; + match mac { + Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { ident: Ident::empty(), attrs: ast::AttrVec::new(), id: ast::DUMMY_NODE_ID, @@ -773,16 +794,15 @@ pub(super) fn expand_global_asm<'cx>( kind: ast::VisibilityKind::Inherited, tokens: None, }, - span: ecx.with_def_site_ctxt(sp), + span: sp, tokens: None, - })]) - } else { - DummyResult::any(sp) + })]), + Err(guar) => DummyResult::any(sp, guar), } } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } - } + }) } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 501d557f3ab..c75050f2701 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -9,22 +9,22 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp}; use rustc_ast_pretty::pprust; use rustc_errors::PResult; -use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_parse::parser::Parser; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use thin_vec::thin_vec; -pub fn expand_assert<'cx>( +pub(crate) fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, span: Span, tts: TokenStream, -) -> Box<dyn MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { Ok(assert) => assert, Err(err) => { - err.emit(); - return DummyResult::any(span); + let guar = err.emit(); + return ExpandResult::Ready(DummyResult::any(span, guar)); } }; @@ -92,7 +92,7 @@ pub fn expand_assert<'cx>( expr_if_not(cx, call_site_span, cond_expr, then, None) }; - MacEager::expr(expr) + ExpandResult::Ready(MacEager::expr(expr)) } struct Assert { @@ -111,7 +111,7 @@ fn expr_if_not( cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els) } -fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> { +fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> { let mut parser = cx.new_parser_from_tts(stream); if parser.token == token::Eof { @@ -151,7 +151,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes }; if parser.token != token::Eof { - return parser.unexpected(); + parser.unexpected()?; } Ok(Assert { cond_expr, custom_message }) diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index a98ed996df6..a98cb6f0f76 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,7 +1,6 @@ use rustc_ast::{ ptr::P, - token, - token::Delimiter, + token::{self, Delimiter, IdentIsRaw}, tokenstream::{DelimSpan, TokenStream, TokenTree}, BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, @@ -120,10 +119,13 @@ impl<'cx, 'a> Context<'cx, 'a> { thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)], ItemKind::Use(UseTree { prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])), - kind: UseTreeKind::Nested(thin_vec![ - nested_tree(self, sym::TryCaptureGeneric), - nested_tree(self, sym::TryCapturePrintable), - ]), + kind: UseTreeKind::Nested { + items: thin_vec![ + nested_tree(self, sym::TryCaptureGeneric), + nested_tree(self, sym::TryCapturePrintable), + ], + span: self.span, + }, span: self.span, }), ), @@ -150,7 +152,7 @@ impl<'cx, 'a> Context<'cx, 'a> { fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> { let escaped_expr_str = escape_to_fmt(expr_str); let initial = [ - TokenTree::token_joint_hidden( + TokenTree::token_joint( token::Literal(token::Lit { kind: token::LitKind::Str, symbol: Symbol::intern(&if self.fmt_string.is_empty() { @@ -169,7 +171,10 @@ impl<'cx, 'a> Context<'cx, 'a> { ]; let captures = self.capture_decls.iter().flat_map(|cap| { [ - TokenTree::token_joint_hidden(token::Ident(cap.ident.name, false), cap.ident.span), + TokenTree::token_joint( + token::Ident(cap.ident.name, IdentIsRaw::No), + cap.ident.span, + ), TokenTree::token_alone(token::Comma, self.span), ] }); @@ -242,7 +247,7 @@ impl<'cx, 'a> Context<'cx, 'a> { ExprKind::Let(_, local_expr, _, _) => { self.manage_cond_expr(local_expr); } - ExprKind::Match(local_expr, _) => { + ExprKind::Match(local_expr, ..) => { self.manage_cond_expr(local_expr); } ExprKind::MethodCall(call) => { @@ -300,7 +305,8 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Closure(_) | ExprKind::ConstBlock(_) | ExprKind::Continue(_) - | ExprKind::Err + | ExprKind::Dummy + | ExprKind::Err(_) | ExprKind::Field(_, _) | ExprKind::ForLoop { .. } | ExprKind::FormatArgs(_) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 581d390992a..827719d7944 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -8,17 +8,17 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::PResult; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::Span; -pub fn expand_cfg( +pub(crate) fn expand_cfg( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - match parse_cfg(cx, sp, tts) { + ExpandResult::Ready(match parse_cfg(cx, sp, tts) { Ok(cfg) => { let matches_cfg = attr::cfg_matches( &cfg, @@ -29,13 +29,13 @@ pub fn expand_cfg( MacEager::expr(cx.expr_bool(sp, matches_cfg)) } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } - } + }) } -fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { +fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index ceb5f861078..98c0ca3a526 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -10,7 +10,7 @@ use rustc_span::Span; pub(crate) struct Expander; -fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { +fn validate_input<'a>(ecx: &ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { use errors::CfgAccessibleInvalid::*; match mi.meta_item_list() { None => {} @@ -46,7 +46,7 @@ impl MultiItemModifier for Expander { ) -> ExpandResult<Vec<Annotatable>, Annotatable> { let template = AttributeTemplate { list: Some("path"), ..Default::default() }; validate_attr::check_builtin_meta_item( - &ecx.sess.parse_sess, + &ecx.sess.psess, meta_item, ast::AttrStyle::Outer, sym::cfg_accessible, diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index cfa94b0e780..03aff6f9633 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -1,5 +1,6 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; +use core::ops::ControlFlow; use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::ptr::P; @@ -17,6 +18,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; +use tracing::instrument; pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, @@ -87,41 +89,40 @@ fn flat_map_annotatable( } } -struct CfgFinder { - has_cfg_or_cfg_attr: bool, -} +fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { + struct CfgFinder; -impl CfgFinder { - fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { - let mut finder = CfgFinder { has_cfg_or_cfg_attr: false }; - match annotatable { - Annotatable::Item(item) => finder.visit_item(item), - Annotatable::TraitItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Trait), - Annotatable::ImplItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Impl), - Annotatable::ForeignItem(item) => finder.visit_foreign_item(item), - Annotatable::Stmt(stmt) => finder.visit_stmt(stmt), - Annotatable::Expr(expr) => finder.visit_expr(expr), - Annotatable::Arm(arm) => finder.visit_arm(arm), - Annotatable::ExprField(field) => finder.visit_expr_field(field), - Annotatable::PatField(field) => finder.visit_pat_field(field), - Annotatable::GenericParam(param) => finder.visit_generic_param(param), - Annotatable::Param(param) => finder.visit_param(param), - Annotatable::FieldDef(field) => finder.visit_field_def(field), - Annotatable::Variant(variant) => finder.visit_variant(variant), - Annotatable::Crate(krate) => finder.visit_crate(krate), - }; - finder.has_cfg_or_cfg_attr - } -} - -impl<'ast> visit::Visitor<'ast> for CfgFinder { - fn visit_attribute(&mut self, attr: &'ast Attribute) { - // We want short-circuiting behavior, so don't use the '|=' operator. - self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr - || attr + impl<'ast> visit::Visitor<'ast> for CfgFinder { + type Result = ControlFlow<()>; + fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> { + if attr .ident() - .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr); + .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } } + + let res = match annotatable { + Annotatable::Item(item) => CfgFinder.visit_item(item), + Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait), + Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl), + Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item), + Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt), + Annotatable::Expr(expr) => CfgFinder.visit_expr(expr), + Annotatable::Arm(arm) => CfgFinder.visit_arm(arm), + Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field), + Annotatable::PatField(field) => CfgFinder.visit_pat_field(field), + Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param), + Annotatable::Param(param) => CfgFinder.visit_param(param), + Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field), + Annotatable::Variant(variant) => CfgFinder.visit_variant(variant), + Annotatable::Crate(krate) => CfgFinder.visit_crate(krate), + }; + res.is_break() } impl CfgEval<'_, '_> { @@ -132,7 +133,7 @@ impl CfgEval<'_, '_> { fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> { // Tokenizing and re-parsing the `Annotatable` can have a significant // performance impact, so try to avoid it if possible - if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) { + if !has_cfg_or_cfg_attr(&annotatable) { return Some(annotatable); } @@ -195,8 +196,7 @@ impl CfgEval<'_, '_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) - let mut parser = - rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None); + let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, @@ -247,18 +247,18 @@ impl MutVisitor for CfgEval<'_, '_> { } fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { - mut_visit::noop_flat_map_assoc_item(configure!(self, item), self) + mut_visit::noop_flat_map_item(configure!(self, item), self) } fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { - mut_visit::noop_flat_map_assoc_item(configure!(self, item), self) + mut_visit::noop_flat_map_item(configure!(self, item), self) } fn flat_map_foreign_item( &mut self, foreign_item: P<ast::ForeignItem>, ) -> SmallVec<[P<ast::ForeignItem>; 1]> { - mut_visit::noop_flat_map_foreign_item(configure!(self, foreign_item), self) + mut_visit::noop_flat_map_item(configure!(self, foreign_item), self) } fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index d956c096d24..e9b63b4abeb 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -4,16 +4,17 @@ use crate::errors; use rustc_ast::attr::mk_attr; use rustc_ast::token; use rustc_ast::{self as ast, AttrItem, AttrStyle}; +use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) { +pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { - let mut parser = rustc_parse::new_parser_from_source_str( - parse_sess, + let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( + psess, FileName::cli_crate_attr_source_code(raw_attr), raw_attr.clone(), - ); + )); let start_span = parser.token.span; let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { @@ -25,12 +26,12 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) }; let end_span = parser.token.span; if parser.token != token::Eof { - parse_sess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); + psess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); continue; } krate.attrs.push(mk_attr( - &parse_sess.attr_id_generator, + &psess.attr_id_generator, AttrStyle::Inner, path, args, diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index f157575da79..a08e8b2819b 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -1,24 +1,26 @@ // The compiler code necessary to support the compile_error! extension. +use crate::util::get_single_str_from_tts; use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::Span; -pub fn expand_compile_error<'cx>( +pub(crate) fn expand_compile_error<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { - let Some(var) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else { - return DummyResult::any(sp); +) -> MacroExpanderResult<'cx> { + let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else { + return ExpandResult::Retry(()); + }; + let var = match mac { + Ok(var) => var, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; - #[expect( - rustc::diagnostic_outside_of_impl, - reason = "diagnostic message is specified by user" - )] + #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")] #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] - cx.dcx().span_err(sp, var.to_string()); + let guar = cx.dcx().span_err(sp, var.to_string()); - DummyResult::any(sp) + ExpandResult::Ready(DummyResult::any(sp, guar)) } diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index dade29593af..15af79ef67d 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -1,85 +1,85 @@ -use rustc_ast as ast; +use crate::errors; +use crate::util::get_exprs_from_tts; use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::{self, DummyResult}; +use rustc_ast::{ExprKind, LitKind, UnOp}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; -use crate::errors; - -pub fn expand_concat( - cx: &mut base::ExtCtxt<'_>, +pub(crate) fn expand_concat( + cx: &mut ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { - let Some(es) = base::get_exprs_from_tts(cx, tts) else { - return DummyResult::any(sp); +) -> MacroExpanderResult<'static> { + let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else { + return ExpandResult::Retry(()); + }; + let es = match mac { + Ok(es) => es, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; let mut accumulator = String::new(); let mut missing_literal = vec![]; - let mut has_errors = false; + let mut guar = None; for e in es { match e.kind { - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => { + ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Str(s, _) | LitKind::Float(s, _)) => { accumulator.push_str(s.as_str()); } - Ok(ast::LitKind::Char(c)) => { + Ok(LitKind::Char(c)) => { accumulator.push(c); } - Ok(ast::LitKind::Int(i, _)) => { + Ok(LitKind::Int(i, _)) => { accumulator.push_str(&i.to_string()); } - Ok(ast::LitKind::Bool(b)) => { + Ok(LitKind::Bool(b)) => { accumulator.push_str(&b.to_string()); } - Ok(ast::LitKind::CStr(..)) => { - cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span }); - has_errors = true; + Ok(LitKind::CStr(..)) => { + guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); } - Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { - cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); - has_errors = true; + Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => { + guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); } - Ok(ast::LitKind::Err) => { - has_errors = true; + Ok(LitKind::Err(guarantee)) => { + guar = Some(guarantee); } Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); - has_errors = true; + guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span)); } }, // We also want to allow negative numeric literals. - ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) - if let ast::ExprKind::Lit(token_lit) = expr.kind => - { - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), - Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), + ExprKind::Unary(UnOp::Neg, ref expr) if let ExprKind::Lit(token_lit) = expr.kind => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), + Ok(LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); - has_errors = true; + guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span)); } _ => missing_literal.push(e.span), } } - ast::ExprKind::IncludedBytes(..) => { + ExprKind::IncludedBytes(..) => { cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); } - ast::ExprKind::Err => { - has_errors = true; + ExprKind::Err(guarantee) => { + guar = Some(guarantee); } + ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literal.push(e.span); } } } - if !missing_literal.is_empty() { - cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); - return DummyResult::any(sp); - } else if has_errors { - return DummyResult::any(sp); - } - let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) + ExpandResult::Ready(if !missing_literal.is_empty() { + let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); + DummyResult::any(sp, guar) + } else if let Some(guar) = guar { + DummyResult::any(sp, guar) + } else { + let sp = cx.with_def_site_ctxt(sp); + MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) + }) } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index a01bbeac824..3130870df41 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,192 +1,185 @@ -use rustc_ast as ast; -use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_expand::base::{self, DummyResult}; -use rustc_session::errors::report_lit_error; -use rustc_span::Span; - use crate::errors; +use crate::util::get_exprs_from_tts; +use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; +use rustc_session::errors::report_lit_error; +use rustc_span::{ErrorGuaranteed, Span}; /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err( - cx: &mut base::ExtCtxt<'_>, - token_lit: ast::token::Lit, + cx: &ExtCtxt<'_>, + token_lit: token::Lit, span: Span, is_nested: bool, -) { +) -> ErrorGuaranteed { use errors::{ ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, }; let snippet = cx.sess.source_map().span_to_snippet(span).ok(); let dcx = cx.dcx(); - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::CStr(_, _)) => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::CStr(_, _)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. - dcx.emit_err(errors::ConcatCStrLit { span: span }); + dcx.emit_err(errors::ConcatCStrLit { span }) } - Ok(ast::LitKind::Char(_)) => { + Ok(LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) } - Ok(ast::LitKind::Str(_, _)) => { + Ok(LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested let sugg = if !is_nested { snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet }) } else { None }; - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) } - Ok(ast::LitKind::Float(_, _)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }); + Ok(LitKind::Float(_, _)) => { + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) } - Ok(ast::LitKind::Bool(_)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); + Ok(LitKind::Bool(_)) => { + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) } - Ok(ast::LitKind::Err) => {} - Ok(ast::LitKind::Int(_, _)) if !is_nested => { + Ok(LitKind::Int(_, _)) if !is_nested => { let sugg = - snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }); + snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) } - Ok(ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) => { + Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { assert!(val.get() > u8::MAX.into()); // must be an error - dcx.emit_err(ConcatBytesOob { span }); - } - Ok(ast::LitKind::Int(_, _)) => { - dcx.emit_err(ConcatBytesNonU8 { span }); - } - Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), - Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, span); + dcx.emit_err(ConcatBytesOob { span }) } + Ok(LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), + Ok(LitKind::ByteStr(..) | LitKind::Byte(_)) => unreachable!(), + Ok(LitKind::Err(guar)) => guar, + Err(err) => report_lit_error(&cx.sess.psess, err, token_lit, span), } } +/// Returns `expr` as a *single* byte literal if applicable. +/// +/// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or +/// updates `guar` accordingly. fn handle_array_element( - cx: &mut base::ExtCtxt<'_>, - has_errors: &mut bool, + cx: &ExtCtxt<'_>, + guar: &mut Option<ErrorGuaranteed>, missing_literals: &mut Vec<rustc_span::Span>, expr: &P<rustc_ast::Expr>, ) -> Option<u8> { let dcx = cx.dcx(); - match expr.kind { - ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); - } - *has_errors = true; - None - } - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) if val.get() <= u8::MAX.into() => Some(val.get() as u8), - Ok(ast::LitKind::Byte(val)) => Some(val), - Ok(ast::LitKind::ByteStr(..)) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }); + match expr.kind { + ExprKind::Lit(token_lit) => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Int( + val, + LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8), + )) if let Ok(val) = u8::try_from(val.get()) => { + return Some(val); } - *has_errors = true; - None - } - _ => { - if !*has_errors { - invalid_type_err(cx, token_lit, expr.span, true); + Ok(LitKind::Byte(val)) => return Some(val), + Ok(LitKind::ByteStr(..)) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) + }); } - *has_errors = true; - None - } - }, - ast::ExprKind::IncludedBytes(..) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); - } - *has_errors = true; - None + _ => { + guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, expr.span, true)); + } + }; } - _ => { - missing_literals.push(expr.span); - None + ExprKind::Array(_) | ExprKind::Repeat(_, _) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + }); } + ExprKind::IncludedBytes(..) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + }); + } + _ => missing_literals.push(expr.span), } + + None } -pub fn expand_concat_bytes( - cx: &mut base::ExtCtxt<'_>, - sp: rustc_span::Span, +pub(crate) fn expand_concat_bytes( + cx: &mut ExtCtxt<'_>, + sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { - let Some(es) = base::get_exprs_from_tts(cx, tts) else { - return DummyResult::any(sp); +) -> MacroExpanderResult<'static> { + let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else { + return ExpandResult::Retry(()); + }; + let es = match mac { + Ok(es) => es, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; let mut accumulator = Vec::new(); let mut missing_literals = vec![]; - let mut has_errors = false; + let mut guar = None; for e in es { match &e.kind { - ast::ExprKind::Array(exprs) => { + ExprKind::Array(exprs) => { for expr in exprs { if let Some(elem) = - handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + handle_array_element(cx, &mut guar, &mut missing_literals, expr) { accumulator.push(elem); } } } - ast::ExprKind::Repeat(expr, count) => { - if let ast::ExprKind::Lit(token_lit) = count.value.kind - && let Ok(ast::LitKind::Int(count_val, _)) = - ast::LitKind::from_token_lit(token_lit) + ExprKind::Repeat(expr, count) => { + if let ExprKind::Lit(token_lit) = count.value.kind + && let Ok(LitKind::Int(count_val, _)) = LitKind::from_token_lit(token_lit) { if let Some(elem) = - handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + handle_array_element(cx, &mut guar, &mut missing_literals, expr) { for _ in 0..count_val.get() { accumulator.push(elem); } } } else { - cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }); + guar = Some( + cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }), + ); } } - &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Byte(val)) => { + &ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Byte(val)) => { accumulator.push(val); } - Ok(ast::LitKind::ByteStr(ref bytes, _)) => { + Ok(LitKind::ByteStr(ref bytes, _)) => { accumulator.extend_from_slice(bytes); } _ => { - if !has_errors { - invalid_type_err(cx, token_lit, e.span, false); - } - has_errors = true; + guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); } }, - ast::ExprKind::IncludedBytes(bytes) => { + ExprKind::IncludedBytes(bytes) => { accumulator.extend_from_slice(bytes); } - ast::ExprKind::Err => { - has_errors = true; + ExprKind::Err(guarantee) => { + guar = Some(*guarantee); } + ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literals.push(e.span); } } } - if !missing_literals.is_empty() { - cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); - return base::MacEager::expr(DummyResult::raw_expr(sp, true)); - } else if has_errors { - return base::MacEager::expr(DummyResult::raw_expr(sp, true)); - } - let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_byte_str(sp, accumulator)) + ExpandResult::Ready(if !missing_literals.is_empty() { + let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); + MacEager::expr(DummyResult::raw_expr(sp, Some(guar))) + } else if let Some(guar) = guar { + MacEager::expr(DummyResult::raw_expr(sp, Some(guar))) + } else { + let sp = cx.with_def_site_ctxt(sp); + MacEager::expr(cx.expr_byte_str(sp, accumulator)) + }) } diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 17fd3901cc6..13729a9d250 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -1,21 +1,21 @@ -use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_expand::base::{self, *}; +use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; use crate::errors; -pub fn expand_concat_idents<'cx>( +pub(crate) fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { if tts.is_empty() { - cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); + return ExpandResult::Ready(DummyResult::any(sp, guar)); } let mut res_str = String::new(); @@ -24,8 +24,8 @@ pub fn expand_concat_idents<'cx>( match e { TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} _ => { - cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); + return ExpandResult::Ready(DummyResult::any(sp, guar)); } } } else { @@ -36,8 +36,8 @@ pub fn expand_concat_idents<'cx>( } } - cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); + return ExpandResult::Ready(DummyResult::any(sp, guar)); } } @@ -47,26 +47,26 @@ pub fn expand_concat_idents<'cx>( ident: Ident, } - impl base::MacResult for ConcatIdentsResult { - fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { - Some(P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), + impl MacResult for ConcatIdentsResult { + fn make_expr(self: Box<Self>) -> Option<P<Expr>> { + Some(P(Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::Path(None, Path::from_ident(self.ident)), span: self.ident.span, - attrs: ast::AttrVec::new(), + attrs: AttrVec::new(), tokens: None, })) } - fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { - Some(P(ast::Ty { - id: ast::DUMMY_NODE_ID, - kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), + fn make_ty(self: Box<Self>) -> Option<P<Ty>> { + Some(P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Path(None, Path::from_ident(self.ident)), span: self.ident.span, tokens: None, })) } } - Box::new(ConcatIdentsResult { ident }) + ExpandResult::Ready(Box::new(ConcatIdentsResult { ident })) } diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 7388e133c53..d14858e5c1d 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -3,14 +3,18 @@ use crate::errors; use rustc_ast as ast; use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; -use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; +use rustc_expand::base::{ + Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, +}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::{ErrorGuaranteed, Span}; -pub(crate) struct Expander(pub bool); +pub(crate) struct Expander { + pub is_const: bool, +} impl MultiItemModifier for Expander { fn expand( @@ -34,7 +38,7 @@ impl MultiItemModifier for Expander { let template = AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; validate_attr::check_builtin_meta_item( - &sess.parse_sess, + &sess.psess, meta_item, ast::AttrStyle::Outer, sym::derive, @@ -58,7 +62,12 @@ impl MultiItemModifier for Expander { report_path_args(sess, meta); meta.path.clone() }) - .map(|path| (path, dummy_annotatable(), None, self.0)) + .map(|path| DeriveResolution { + path, + item: dummy_annotatable(), + exts: None, + is_const: self.is_const, + }) .collect() } _ => vec![], @@ -67,15 +76,15 @@ impl MultiItemModifier for Expander { // Do not configure or clone items unless necessary. match &mut resolutions[..] { [] => {} - [(_, first_item, ..), others @ ..] => { - *first_item = cfg_eval( + [first, others @ ..] => { + first.item = cfg_eval( sess, features, item.clone(), ecx.current_expansion.lint_node_id, ); - for (_, item, _, _) in others { - *item = first_item.clone(); + for other in others { + other.item = first.item.clone(); } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 8027ca2e7bb..97e2344ff30 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -5,8 +5,8 @@ use rustc_ast::MetaItem; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::Span; -pub fn expand_deriving_copy( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_copy( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -28,8 +28,8 @@ pub fn expand_deriving_copy( trait_def.expand(cx, mitem, item, push); } -pub fn expand_deriving_const_param_ty( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_const_param_ty( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 7bf19f61166..abcb402a46f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -8,8 +8,8 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_clone( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_clone( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -94,7 +94,7 @@ pub fn expand_deriving_clone( fn cs_clone_simple( name: &str, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, is_union: bool, @@ -110,7 +110,9 @@ fn cs_clone_simple( && !seen_type_names.insert(name) { // Already produced an assertion for this type. - } else { + // Anonymous structs or unions must be eliminated as they cannot be + // type parameters. + } else if !field.ty.kind.is_anon_adt() { // let _: AssertParamIsClone<FieldTy>; super::assert_ty_bounds( cx, @@ -155,14 +157,14 @@ fn cs_clone_simple( fn cs_clone( name: &str, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, ) -> BlockOrExpr { let ctor_path; let all_fields; let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]); - let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| { + let subcall = |cx: &ExtCtxt<'_>, field: &FieldInfo| { let args = thin_vec![field.self_expr.clone()]; cx.expr_call_global(field.span, fn_path.clone(), args) }; @@ -179,8 +181,8 @@ fn cs_clone( all_fields = af; vdata = &variant.data; } - EnumTag(..) | AllFieldlessEnum(..) => { - cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",)) + EnumDiscr(..) | AllFieldlessEnum(..) => { + cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",)) } StaticEnum(..) | StaticStruct(..) => { cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`")) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index ce3fa1ab32c..53a15131605 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -9,8 +9,8 @@ use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_eq( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_eq( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -49,7 +49,7 @@ pub fn expand_deriving_eq( } fn cs_total_eq_assert( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, ) -> BlockOrExpr { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 0923acfeedd..8470d466a23 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -7,8 +7,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_ord( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_ord( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -39,7 +39,7 @@ pub fn expand_deriving_ord( trait_def.expand(cx, mitem, item, push) } -pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { +pub(crate) fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 006110cd4b1..a6457f4a433 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -8,15 +8,15 @@ use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_partial_eq( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_partial_eq( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { + fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let base = true; let expr = cs_fold( true, // use foldl @@ -31,7 +31,7 @@ pub fn expand_deriving_partial_eq( }; // We received arguments of type `&T`. Convert them to type `T` by stripping - // any leading `&` or adding `*`. This isn't necessary for type checking, but + // any leading `&`. This isn't necessary for type checking, but // it results in better error messages if something goes wrong. // // Note: for arguments that look like `&{ x }`, which occur with packed @@ -53,8 +53,7 @@ pub fn expand_deriving_partial_eq( inner.clone() } } else { - // No leading `&`: add a leading `*`. - cx.expr_deref(field.span, expr.clone()) + expr.clone() } }; cx.expr_binary( diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 6eccd67f8af..006e5a3d268 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -7,8 +7,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_partial_ord( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_partial_ord( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord( Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); // Order in which to perform matching - let tag_then_data = if let Annotatable::Item(item) = item + let discr_then_data = if let Annotatable::Item(item) = item && let ItemKind::Enum(def, _) = &item.kind { let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); match dataful.iter().filter(|&&b| b).count() { - // No data, placing the tag check first makes codegen simpler + // No data, placing the discriminant check first makes codegen simpler 0 => true, 1..=2 => false, _ => (0..dataful.len() - 1).any(|i| { @@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord( attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr, tag_then_data) + cs_partial_cmp(cx, span, substr, discr_then_data) })), }; @@ -69,10 +69,10 @@ pub fn expand_deriving_partial_ord( } fn cs_partial_cmp( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>, - tag_then_data: bool, + discr_then_data: bool, ) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); @@ -108,12 +108,12 @@ fn cs_partial_cmp( // cmp => cmp // } // ``` - // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` - // against the enum variants. This means that we begin by comparing the enum tags, + // where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match` + // against the enum variants. This means that we begin by comparing the enum discriminants, // before either inspecting their contents (if they match), or returning - // the `cmp::Ordering` of comparing the enum tags. + // the `cmp::Ordering` of comparing the enum discriminants. // ``` - // match partial_cmp(self_tag, other_tag) { + // match partial_cmp(self_discr, other_discr) { // Some(Ordering::Equal) => match (self, other) { // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), @@ -126,13 +126,13 @@ fn cs_partial_cmp( // ``` // match (self, other) { // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), - // _ => partial_cmp(self_tag, other_tag) + // _ => partial_cmp(self_discr, other_discr) // } // ``` // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 - if !tag_then_data - && let ExprKind::Match(_, arms) = &mut expr1.kind + if !discr_then_data + && let ExprKind::Match(_, arms, _) = &mut expr1.kind && let Some(last) = arms.last_mut() && let PatKind::Wild = last.pat.kind { diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index b11a1b6cda1..57ec0435e3e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -2,15 +2,14 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; -use ast::EnumDef; -use rustc_ast::{self as ast, MetaItem}; +use rustc_ast::{self as ast, EnumDef, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_debug( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_debug( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -46,15 +45,15 @@ pub fn expand_deriving_debug( trait_def.expand(cx, mitem, item, push) } -fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { +fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { // We want to make sure we have the ctxt set so that we can use unstable methods let span = cx.with_def_site_ctxt(span); let (ident, vdata, fields) = match substr.fields { Struct(vdata, fields) => (substr.type_ident, *vdata, fields), - EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), + EnumMatching(_, v, fields) => (v.ident, &v.data, fields), AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), - EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { + EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => { cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") } }; @@ -210,7 +209,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> /// } /// ``` fn show_fieldless_enum( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, span: Span, def: &EnumDef, substr: &Substructure<'_>, diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 97d6b82de98..e9851c87aea 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -10,8 +10,8 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_rustc_decodable( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_rustc_decodable( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -63,7 +63,7 @@ pub fn expand_deriving_rustc_decodable( } fn decodable_substructure( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, krate: Symbol, @@ -186,19 +186,19 @@ fn decodable_substructure( /// - `outer_pat_path` is the path to this enum variant/struct /// - `getarg` should retrieve the `usize`-th field with name `@str`. fn decode_static_fields<F>( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, outer_pat_path: ast::Path, fields: &StaticFields, mut getarg: F, ) -> P<Expr> where - F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>, + F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>, { match fields { Unnamed(fields, is_tuple) => { let path_expr = cx.expr_path(outer_pat_path); - if !*is_tuple { + if matches!(is_tuple, IsTuple::No) { path_expr } else { let fields = fields diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index d5a42566e19..577523a1d5a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,17 +1,19 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::errors; +use core::ops::ControlFlow; use rustc_ast as ast; -use rustc_ast::{attr, walk_list, EnumDef, VariantData}; +use rustc_ast::visit::visit_opt; +use rustc_ast::{attr, EnumDef, VariantData}; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_default( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_default( + cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, item: &Annotatable, @@ -52,7 +54,7 @@ pub fn expand_deriving_default( } fn default_struct_substructure( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, summary: &StaticFields, @@ -62,8 +64,8 @@ fn default_struct_substructure( let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new()); let expr = match summary { - Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident), - Unnamed(fields, true) => { + Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident), + Unnamed(fields, IsTuple::Yes) => { let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); cx.expr_call_ident(trait_span, substr.type_ident, exprs) } @@ -79,29 +81,32 @@ fn default_struct_substructure( } fn default_enum_substructure( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, enum_def: &EnumDef, ) -> BlockOrExpr { - let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) - && let Ok(_) = validate_default_attribute(cx, default_variant) - { - // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - cx.expr_path(cx.path( - default_variant.span, - vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], - )) - } else { - DummyResult::raw_expr(trait_span, true) + let expr = match try { + let default_variant = extract_default_variant(cx, enum_def, trait_span)?; + validate_default_attribute(cx, default_variant)?; + default_variant + } { + Ok(default_variant) => { + // We now know there is exactly one unit variant with exactly one `#[default]` attribute. + cx.expr_path(cx.path( + default_variant.span, + vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], + )) + } + Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)), }; BlockOrExpr::new_expr(expr) } fn extract_default_variant<'a>( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, enum_def: &'a EnumDef, trait_span: Span, -) -> Result<&'a rustc_ast::Variant, ()> { +) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> { let default_variants: SmallVec<[_; 1]> = enum_def .variants .iter() @@ -120,9 +125,9 @@ fn extract_default_variant<'a>( let suggs = possible_defaults .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) .collect(); - cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); + let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); - return Err(()); + return Err(guar); } [first, rest @ ..] => { let suggs = default_variants @@ -140,37 +145,37 @@ fn extract_default_variant<'a>( .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident }) }) .collect(); - cx.dcx().emit_err(errors::MultipleDefaults { + let guar = cx.dcx().emit_err(errors::MultipleDefaults { span: trait_span, first: first.span, additional: rest.iter().map(|v| v.span).collect(), suggs, }); - return Err(()); + return Err(guar); } }; if !matches!(variant.data, VariantData::Unit(..)) { - cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); - return Err(()); + let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); + return Err(guar); } if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { - cx.dcx().emit_err(errors::NonExhaustiveDefault { + let guar = cx.dcx().emit_err(errors::NonExhaustiveDefault { span: variant.ident.span, non_exhaustive: non_exhaustive_attr.span, }); - return Err(()); + return Err(guar); } Ok(variant) } fn validate_default_attribute( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, default_variant: &rustc_ast::Variant, -) -> Result<(), ()> { +) -> Result<(), ErrorGuaranteed> { let attrs: SmallVec<[_; 1]> = attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); @@ -183,7 +188,7 @@ fn validate_default_attribute( let sugg = errors::MultipleDefaultAttrsSugg { spans: rest.iter().map(|attr| attr.span).collect(), }; - cx.dcx().emit_err(errors::MultipleDefaultAttrs { + let guar = cx.dcx().emit_err(errors::MultipleDefaultAttrs { span: default_variant.ident.span, first: first.span, first_rest: rest[0].span, @@ -192,13 +197,13 @@ fn validate_default_attribute( sugg, }); - return Err(()); + return Err(guar); } }; if !attr.is_word() { - cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); + let guar = cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); - return Err(()); + return Err(guar); } Ok(()) } @@ -219,7 +224,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' self.visit_ident(v.ident); self.visit_vis(&v.vis); self.visit_variant_data(&v.data); - walk_list!(self, visit_anon_const, &v.disr_expr); + visit_opt!(self, visit_anon_const, &v.disr_expr); for attr in &v.attrs { rustc_ast::visit::walk_attribute(self, attr); } @@ -227,20 +232,19 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' } fn has_a_default_variant(item: &Annotatable) -> bool { - struct HasDefaultAttrOnVariant { - found: bool, - } + struct HasDefaultAttrOnVariant; impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant { - fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) { + type Result = ControlFlow<()>; + fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) -> ControlFlow<()> { if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) { - self.found = true; + ControlFlow::Break(()) + } else { + // no need to subrecurse. + ControlFlow::Continue(()) } - // no need to subrecurse. } } - let mut visitor = HasDefaultAttrOnVariant { found: false }; - item.visit_with(&mut visitor); - visitor.found + item.visit_with(&mut HasDefaultAttrOnVariant).is_break() } diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 14d93a8cc23..3bd74d8d019 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -94,8 +94,8 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_rustc_encodable( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_rustc_encodable( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -147,7 +147,7 @@ pub fn expand_deriving_rustc_encodable( } fn encodable_substructure( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, krate: Symbol, @@ -226,7 +226,7 @@ fn encodable_substructure( BlockOrExpr::new_expr(expr) } - EnumMatching(idx, _, variant, fields) => { + EnumMatching(idx, variant, fields) => { // We're not generating an AST that the borrow checker is expecting, // so we need to generate a unique local variable to take the // mutable loan out on, otherwise we get conflicts which don't diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6eeb028728c..ba289f9552e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -21,7 +21,7 @@ //! `struct T(i32, char)`). //! - `EnumMatching`, when `Self` is an enum and all the arguments are the //! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumTag` when `Self` is an enum, for comparing the enum tags. +//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants. //! - `StaticEnum` and `StaticStruct` for static methods, where the type //! being derived upon is either an enum or struct respectively. (Any //! argument with type Self is just grouped among the non-self @@ -143,11 +143,11 @@ //! ) //! ``` //! -//! For the tags, +//! For the discriminants, //! //! ```text -//! EnumTag( -//! &[<ident of self tag>, <ident of other tag>], +//! EnumDiscr( +//! &[<ident of self discriminant>, <ident of other discriminant>], //! <expr to combine with>, //! ) //! ``` @@ -174,13 +174,13 @@ //! ) //! ``` -pub use StaticFields::*; -pub use SubstructureFields::*; +pub(crate) use StaticFields::*; +pub(crate) use SubstructureFields::*; use crate::{deriving, errors}; use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Mutability, PatKind, TyKind, VariantData, }; use rustc_attr as attr; @@ -195,9 +195,9 @@ use std::vec; use thin_vec::{thin_vec, ThinVec}; use ty::{Bounds, Path, Ref, Self_, Ty}; -pub mod ty; +pub(crate) mod ty; -pub struct TraitDef<'a> { +pub(crate) struct TraitDef<'a> { /// The span for the current #[derive(Foo)] header. pub span: Span, @@ -224,7 +224,7 @@ pub struct TraitDef<'a> { pub is_const: bool, } -pub struct MethodDef<'a> { +pub(crate) struct MethodDef<'a> { /// name of the method pub name: Symbol, /// List of generics, e.g., `R: rand::Rng` @@ -248,7 +248,7 @@ pub struct MethodDef<'a> { /// How to handle fieldless enum variants. #[derive(PartialEq)] -pub enum FieldlessVariantsStrategy { +pub(crate) enum FieldlessVariantsStrategy { /// Combine fieldless variants into a single match arm. /// This assumes that relevant information has been handled /// by looking at the enum's discriminant. @@ -263,7 +263,7 @@ pub enum FieldlessVariantsStrategy { } /// All the data about the data structure/method being derived upon. -pub struct Substructure<'a> { +pub(crate) struct Substructure<'a> { /// ident of self pub type_ident: Ident, /// Verbatim access to any non-selflike arguments, i.e. arguments that @@ -273,7 +273,7 @@ pub struct Substructure<'a> { } /// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { +pub(crate) struct FieldInfo { pub span: Span, /// None for tuple structs/normal enum variants, Some for normal /// structs/struct enum variants. @@ -286,16 +286,22 @@ pub struct FieldInfo { pub other_selflike_exprs: Vec<P<Expr>>, } +#[derive(Copy, Clone)] +pub(crate) enum IsTuple { + No, + Yes, +} + /// Fields for a static method -pub enum StaticFields { +pub(crate) enum StaticFields { /// Tuple and unit structs/enum variants like this. - Unnamed(Vec<Span>, bool /*is tuple*/), + Unnamed(Vec<Span>, IsTuple), /// Normal structs/struct variants. Named(Vec<(Ident, Span)>), } /// A summary of the possible sets of fields. -pub enum SubstructureFields<'a> { +pub(crate) enum SubstructureFields<'a> { /// A non-static method where `Self` is a struct. Struct(&'a ast::VariantData, Vec<FieldInfo>), @@ -304,15 +310,15 @@ pub enum SubstructureFields<'a> { /// variants has any fields). AllFieldlessEnum(&'a ast::EnumDef), - /// Matching variants of the enum: variant index, variant count, ast::Variant, + /// Matching variants of the enum: variant index, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. - EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>), + EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>), - /// The tag of an enum. The first field is a `FieldInfo` for the tags, as + /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as /// if they were fields. The second field is the expression to combine the - /// tag expression with; it will be `None` if no match is necessary. - EnumTag(FieldInfo, Option<P<Expr>>), + /// discriminant expression with; it will be `None` if no match is necessary. + EnumDiscr(FieldInfo, Option<P<Expr>>), /// A static method where `Self` is a struct. StaticStruct(&'a ast::VariantData, StaticFields), @@ -323,10 +329,10 @@ pub enum SubstructureFields<'a> { /// Combine the values of all the fields together. The last argument is /// all the fields of all the structures. -pub type CombineSubstructureFunc<'a> = - Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; +pub(crate) type CombineSubstructureFunc<'a> = + Box<dyn FnMut(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; -pub fn combine_substructure( +pub(crate) fn combine_substructure( f: CombineSubstructureFunc<'_>, ) -> RefCell<CombineSubstructureFunc<'_>> { RefCell::new(f) @@ -343,7 +349,7 @@ struct TypeParameter { /// avoiding the insertion of any unnecessary blocks. /// /// The statements come before the expression. -pub struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>); +pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>); impl BlockOrExpr { pub fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr { @@ -406,6 +412,15 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { + let stack_len = self.bound_generic_params_stack.len(); + if let ast::TyKind::BareFn(bare_fn) = &ty.kind + && !bare_fn.generic_params.is_empty() + { + // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so + // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622 + self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned()); + } + if let ast::TyKind::Path(_, path) = &ty.kind && let Some(segment) = path.segments.first() && self.ty_param_names.contains(&segment.ident.name) @@ -416,7 +431,8 @@ fn find_type_parameters( }); } - visit::walk_ty(self, ty) + visit::walk_ty(self, ty); + self.bound_generic_params_stack.truncate(stack_len); } // Place bound generic params on a stack, to extract them when a type is encountered. @@ -448,7 +464,7 @@ fn find_type_parameters( impl<'a> TraitDef<'a> { pub fn expand( self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, item: &'a Annotatable, push: &mut dyn FnMut(Annotatable), @@ -458,7 +474,7 @@ impl<'a> TraitDef<'a> { pub fn expand_ext( self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, item: &'a Annotatable, push: &mut dyn FnMut(Annotatable), @@ -571,7 +587,7 @@ impl<'a> TraitDef<'a> { /// therefore does not get bound by the derived trait. fn create_derived_impl( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, type_ident: Ident, generics: &Generics, field_tys: Vec<P<ast::Ty>>, @@ -595,11 +611,7 @@ impl<'a> TraitDef<'a> { kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { defaultness: ast::Defaultness::Final, generics: Generics::default(), - where_clauses: ( - ast::TyAliasWhereClause::default(), - ast::TyAliasWhereClause::default(), - ), - where_predicates_split: 0, + where_clauses: ast::TyAliasWhereClauses::default(), bounds: Vec::new(), ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)), })), @@ -786,7 +798,7 @@ impl<'a> TraitDef<'a> { Ident::empty(), attrs, ast::ItemKind::Impl(Box::new(ast::Impl { - unsafety: ast::Unsafe::No, + safety: ast::Safety::Default, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, @@ -800,7 +812,7 @@ impl<'a> TraitDef<'a> { fn expand_struct_def( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, struct_def: &'a VariantData, type_ident: Ident, generics: &Generics, @@ -854,7 +866,7 @@ impl<'a> TraitDef<'a> { fn expand_enum_def( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, enum_def: &'a EnumDef, type_ident: Ident, generics: &Generics, @@ -912,7 +924,7 @@ impl<'a> TraitDef<'a> { impl<'a> MethodDef<'a> { fn call_substructure_method( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, type_ident: Ident, nonselflike_args: &[P<Expr>], @@ -927,7 +939,7 @@ impl<'a> MethodDef<'a> { fn get_ret_ty( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, generics: &Generics, type_ident: Ident, @@ -948,7 +960,7 @@ impl<'a> MethodDef<'a> { // `&self`. fn extract_arg_details( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, @@ -984,7 +996,7 @@ impl<'a> MethodDef<'a> { fn create_method( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, @@ -1075,7 +1087,7 @@ impl<'a> MethodDef<'a> { /// ``` fn expand_struct_method_body<'b>( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'b>, struct_def: &'b VariantData, type_ident: Ident, @@ -1098,7 +1110,7 @@ impl<'a> MethodDef<'a> { fn expand_static_struct_method_body( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, struct_def: &VariantData, type_ident: Ident, @@ -1135,9 +1147,9 @@ impl<'a> MethodDef<'a> { /// impl ::core::cmp::PartialEq for A { /// #[inline] /// fn eq(&self, other: &A) -> bool { - /// let __self_tag = ::core::intrinsics::discriminant_value(self); - /// let __arg1_tag = ::core::intrinsics::discriminant_value(other); - /// __self_tag == __arg1_tag + /// let __self_discr = ::core::intrinsics::discriminant_value(self); + /// let __arg1_discr = ::core::intrinsics::discriminant_value(other); + /// __self_discr == __arg1_discr /// && match (self, other) { /// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0, /// _ => true, @@ -1146,13 +1158,13 @@ impl<'a> MethodDef<'a> { /// } /// ``` /// - /// Creates a tag check combined with a match for a tuple of all + /// Creates a discriminant check combined with a match for a tuple of all /// `selflike_args`, with an arm for each variant with fields, possibly an /// arm for each fieldless variant (if `unify_fieldless_variants` is not /// `Unify`), and possibly a default arm. fn expand_enum_method_body<'b>( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'b>, enum_def: &'b EnumDef, type_ident: Ident, @@ -1167,7 +1179,7 @@ impl<'a> MethodDef<'a> { let span = trait_.span; let variants = &enum_def.variants; - // Traits that unify fieldless variants always use the tag(s). + // Traits that unify fieldless variants always use the discriminant(s). let unify_fieldless_variants = self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify; @@ -1197,25 +1209,25 @@ impl<'a> MethodDef<'a> { // // e.g. for `PartialEq::eq` builds two statements: // ``` - // let __self_tag = ::core::intrinsics::discriminant_value(self); - // let __arg1_tag = ::core::intrinsics::discriminant_value(other); + // let __self_discr = ::core::intrinsics::discriminant_value(self); + // let __arg1_discr = ::core::intrinsics::discriminant_value(other); // ``` - let get_tag_pieces = |cx: &ExtCtxt<'_>| { - let tag_idents: Vec<_> = prefixes + let get_discr_pieces = |cx: &ExtCtxt<'_>| { + let discr_idents: Vec<_> = prefixes .iter() - .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span)) + .map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span)) .collect(); - let mut tag_exprs: Vec<_> = tag_idents + let mut discr_exprs: Vec<_> = discr_idents .iter() .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident))) .collect(); - let self_expr = tag_exprs.remove(0); - let other_selflike_exprs = tag_exprs; - let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; + let self_expr = discr_exprs.remove(0); + let other_selflike_exprs = discr_exprs; + let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; - let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args) + let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { let variant_value = deriving::call_intrinsic( cx, @@ -1227,7 +1239,7 @@ impl<'a> MethodDef<'a> { }) .collect(); - (tag_field, tag_let_stmts) + (discr_field, discr_let_stmts) }; // There are some special cases involving fieldless enums where no @@ -1237,19 +1249,19 @@ impl<'a> MethodDef<'a> { if variants.len() > 1 { match self.fieldless_variants_strategy { FieldlessVariantsStrategy::Unify => { - // If the type is fieldless and the trait uses the tag and + // If the type is fieldless and the trait uses the discriminant and // there are multiple variants, we need just an operation on - // the tag(s). - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - let mut tag_check = self.call_substructure_method( + // the discriminant(s). + let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx); + let mut discr_check = self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumTag(tag_field, None), + &EnumDiscr(discr_field, None), ); - tag_let_stmts.append(&mut tag_check.0); - return BlockOrExpr(tag_let_stmts, tag_check.1); + discr_let_stmts.append(&mut discr_check.0); + return BlockOrExpr(discr_let_stmts, discr_check.1); } FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => { return self.call_substructure_method( @@ -1264,13 +1276,13 @@ impl<'a> MethodDef<'a> { } } else if variants.len() == 1 { // If there is a single variant, we don't need an operation on - // the tag(s). Just use the most degenerate result. + // the discriminant(s). Just use the most degenerate result. return self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumMatching(0, 1, &variants[0], Vec::new()), + &EnumMatching(0, &variants[0], Vec::new()), ); } } @@ -1316,7 +1328,7 @@ impl<'a> MethodDef<'a> { // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, variants.len(), variant, fields); + let substructure = EnumMatching(index, variant, fields); let arm_expr = self .call_substructure_method( cx, @@ -1344,7 +1356,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, nonselflike_args, - &EnumMatching(0, variants.len(), v, Vec::new()), + &EnumMatching(0, v, Vec::new()), ) .into_expr(cx, span), ) @@ -1378,22 +1390,22 @@ impl<'a> MethodDef<'a> { cx.expr_match(span, match_arg, match_arms) }; - // If the trait uses the tag and there are multiple variants, we need - // to add a tag check operation before the match. Otherwise, the match + // If the trait uses the discriminant and there are multiple variants, we need + // to add a discriminant check operation before the match. Otherwise, the match // is enough. if unify_fieldless_variants && variants.len() > 1 { - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); + let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx); - // Combine a tag check with the match. - let mut tag_check_plus_match = self.call_substructure_method( + // Combine a discriminant check with the match. + let mut discr_check_plus_match = self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumTag(tag_field, Some(get_match_expr(selflike_args))), + &EnumDiscr(discr_field, Some(get_match_expr(selflike_args))), ); - tag_let_stmts.append(&mut tag_check_plus_match.0); - BlockOrExpr(tag_let_stmts, tag_check_plus_match.1) + discr_let_stmts.append(&mut discr_check_plus_match.0); + BlockOrExpr(discr_let_stmts, discr_check_plus_match.1) } else { BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args))) } @@ -1401,7 +1413,7 @@ impl<'a> MethodDef<'a> { fn expand_static_enum_method_body( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, enum_def: &EnumDef, type_ident: Ident, @@ -1428,7 +1440,7 @@ impl<'a> MethodDef<'a> { // general helper methods. impl<'a> TraitDef<'a> { - fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields { + fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); for field in struct_def.fields() { @@ -1439,7 +1451,10 @@ impl<'a> TraitDef<'a> { } } - let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..)); + let is_tuple = match struct_def { + ast::VariantData::Tuple(..) => IsTuple::Yes, + _ => IsTuple::No, + }; match (just_spans.is_empty(), named_idents.is_empty()) { (false, false) => cx .dcx() @@ -1455,7 +1470,7 @@ impl<'a> TraitDef<'a> { fn create_struct_patterns( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, struct_path: ast::Path, struct_def: &'a VariantData, prefixes: &[String], @@ -1474,11 +1489,7 @@ impl<'a> TraitDef<'a> { struct_field.ident, cx.pat( path.span, - PatKind::Ident( - BindingAnnotation(by_ref, Mutability::Not), - path, - None, - ), + PatKind::Ident(BindingMode(by_ref, Mutability::Not), path, None), ), ) }); @@ -1548,7 +1559,7 @@ impl<'a> TraitDef<'a> { fn create_struct_pattern_fields( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, struct_def: &'a VariantData, prefixes: &[String], ) -> Vec<FieldInfo> { @@ -1565,7 +1576,7 @@ impl<'a> TraitDef<'a> { fn create_struct_field_access_fields( &self, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, selflike_args: &[P<Expr>], struct_def: &'a VariantData, is_packed: bool, @@ -1598,9 +1609,10 @@ impl<'a> TraitDef<'a> { // Once use of `icu4x-0.9.0` has dropped sufficiently, this // exception should be removed. let is_simple_path = |ty: &P<ast::Ty>, sym| { - if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind && - let [seg] = segments.as_slice() && - seg.ident.name == sym && seg.args.is_none() + if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind + && let [seg] = segments.as_slice() + && seg.ident.name == sym + && seg.args.is_none() { true } else { @@ -1608,8 +1620,8 @@ impl<'a> TraitDef<'a> { } }; - let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind && - is_simple_path(ty, sym::u8) + let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind + && is_simple_path(ty, sym::u8) { Some("byte") } else if is_simple_path(&struct_field.ty, sym::str) { @@ -1619,14 +1631,13 @@ impl<'a> TraitDef<'a> { }; if let Some(ty) = exception { - cx.sess.parse_sess.buffer_lint_with_diagnostic( + cx.sess.psess.buffer_lint( BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, sp, ast::CRATE_NODE_ID, - format!( - "{ty} slice in a packed struct that derives a built-in trait" - ), - rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive + rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive { + ty: ty.to_string(), + }, ); } else { // Wrap the expression in `{...}`, causing a copy. @@ -1645,7 +1656,7 @@ impl<'a> TraitDef<'a> { /// The function passed to `cs_fold` is called repeatedly with a value of this /// type. It describes one part of the code generation. The result is always an /// expression. -pub enum CsFold<'a> { +pub(crate) enum CsFold<'a> { /// The basic case: a field expression for one or more selflike args. E.g. /// for `PartialEq::eq` this is something like `self.x == other.x`. Single(&'a FieldInfo), @@ -1660,15 +1671,15 @@ pub enum CsFold<'a> { /// Folds over fields, combining the expressions for each field in a sequence. /// Statics may not be folded over. -pub fn cs_fold<F>( +pub(crate) fn cs_fold<F>( use_foldl: bool, - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, trait_span: Span, substructure: &Substructure<'_>, mut f: F, ) -> P<Expr> where - F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>, + F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P<Expr>, { match substructure.fields { EnumMatching(.., all_fields) | Struct(_, all_fields) => { @@ -1695,16 +1706,16 @@ where rest.iter().rfold(base_expr, op) } } - EnumTag(tag_field, match_expr) => { - let tag_check_expr = f(cx, CsFold::Single(tag_field)); + EnumDiscr(discr_field, match_expr) => { + let discr_check_expr = f(cx, CsFold::Single(discr_field)); if let Some(match_expr) = match_expr { if use_foldl { - f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone())) + f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone())) } else { - f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr)) + f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr)) } } else { - tag_check_expr + discr_check_expr } } StaticEnum(..) | StaticStruct(..) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 603cefdd386..f01d586033e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -1,28 +1,27 @@ //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use //! when specifying impls to be derived. -pub use Ty::*; +pub(crate) use Ty::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; use rustc_expand::base::ExtCtxt; use rustc_span::source_map::respan; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::Span; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use thin_vec::ThinVec; /// A path, e.g., `::std::option::Option::<i32>` (global). Has support /// for type parameters. #[derive(Clone)] -pub struct Path { +pub(crate) struct Path { path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind, } #[derive(Clone)] -pub enum PathKind { +pub(crate) enum PathKind { Local, Global, Std, @@ -73,7 +72,7 @@ impl Path { /// A type. Supports pointers, Self, and literals. #[derive(Clone)] -pub enum Ty { +pub(crate) enum Ty { Self_, /// A reference. Ref(Box<Ty>, ast::Mutability), @@ -84,7 +83,7 @@ pub enum Ty { Unit, } -pub fn self_ref() -> Ty { +pub(crate) fn self_ref() -> Ty { Ref(Box::new(Self_), ast::Mutability::Not) } @@ -164,7 +163,7 @@ fn mk_ty_param( /// Bounds on type parameters. #[derive(Clone)] -pub struct Bounds { +pub(crate) struct Bounds { pub bounds: Vec<(Symbol, Vec<Path>)>, } @@ -197,7 +196,7 @@ impl Bounds { } } -pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) { +pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) { // This constructs a fresh `self` path. let self_path = cx.expr_self(span); let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index dd6149cf614..dcd92819865 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -7,8 +7,8 @@ use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_hash( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_deriving_hash( + cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, item: &Annotatable, @@ -46,11 +46,7 @@ pub fn expand_deriving_hash( hash_trait_def.expand(cx, mitem, item, push); } -fn hash_substructure( - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, -) -> BlockOrExpr { +fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let [state_expr] = substr.nonselflike_args else { cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"); }; @@ -70,9 +66,9 @@ fn hash_substructure( fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect(); (stmts, None) } - EnumTag(tag_field, match_expr) => { - assert!(tag_field.other_selflike_exprs.is_empty()); - let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; + EnumDiscr(discr_field, match_expr) => { + assert!(discr_field.other_selflike_exprs.is_empty()); + let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())]; (stmts, match_expr.clone()) } _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"), diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index a6f3252e7be..e3a93ae13e4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -20,27 +20,27 @@ macro path_std($($x:tt)*) { generic::ty::Path::new( pathvec_std!( $($x)* ) ) } -pub mod bounds; -pub mod clone; -pub mod debug; -pub mod decodable; -pub mod default; -pub mod encodable; -pub mod hash; +pub(crate) mod bounds; +pub(crate) mod clone; +pub(crate) mod debug; +pub(crate) mod decodable; +pub(crate) mod default; +pub(crate) mod encodable; +pub(crate) mod hash; #[path = "cmp/eq.rs"] -pub mod eq; +pub(crate) mod eq; #[path = "cmp/ord.rs"] -pub mod ord; +pub(crate) mod ord; #[path = "cmp/partial_eq.rs"] -pub mod partial_eq; +pub(crate) mod partial_eq; #[path = "cmp/partial_ord.rs"] -pub mod partial_ord; +pub(crate) mod partial_ord; -pub mod generic; +pub(crate) mod generic; pub(crate) type BuiltinDeriveFn = - fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); + fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn); @@ -117,12 +117,14 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { } fn assert_ty_bounds( - cx: &mut ExtCtxt<'_>, + cx: &ExtCtxt<'_>, stmts: &mut ThinVec<ast::Stmt>, ty: P<ast::Ty>, span: Span, assert_path: &[Symbol], ) { + // Deny anonymous structs or unions to avoid weird errors. + assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters"); // Generate statement `let _: assert_path<ty>;`. let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]); diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index 1e1dadab480..cc385bade47 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -16,11 +16,11 @@ use rustc_span::Span; /// /// `$crate` will refer to either the `std` or `core` crate depending on which /// one we're expanding from. -pub fn expand_panic<'cx>( +pub(crate) fn expand_panic<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 }; expand(mac, cx, sp, tts) } @@ -29,24 +29,24 @@ pub fn expand_panic<'cx>( /// - `$crate::panic::unreachable_2015!(...)` or /// - `$crate::panic::unreachable_2021!(...)` /// depending on the edition. -pub fn expand_unreachable<'cx>( +pub(crate) fn expand_unreachable<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 }; expand(mac, cx, sp, tts) } fn expand<'cx>( mac: rustc_span::Symbol, - cx: &'cx mut ExtCtxt<'_>, + cx: &'cx ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { let sp = cx.with_call_site_ctxt(sp); - MacEager::expr( + ExpandResult::Ready(MacEager::expr( cx.expr( sp, ExprKind::MacCall(P(MacCall { @@ -66,10 +66,10 @@ fn expand<'cx>( }), })), ), - ) + )) } -pub fn use_panic_2021(mut span: Span) -> bool { +pub(crate) fn use_panic_2021(mut span: Span) -> bool { // To determine the edition, we check the first span up the expansion // stack that does not have #[allow_internal_unstable(edition_panic)]. // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index a0fd0e3f9be..b03e14cf263 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -3,38 +3,44 @@ // interface. // +use crate::errors; +use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts}; +use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{self as ast, AstDeref, GenericArg}; -use rustc_expand::base::{self, *}; +use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::env; +use std::env::VarError; use thin_vec::thin_vec; -use crate::errors; - -fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Option<Symbol> { +fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> { let var = var.as_str(); if let Some(value) = cx.sess.opts.logical_env.get(var) { - return Some(Symbol::intern(value)); + return Ok(Symbol::intern(value)); } // If the environment variable was not defined with the `--env-set` option, we try to retrieve it // from rustc's environment. - env::var(var).ok().as_deref().map(Symbol::intern) + Ok(Symbol::intern(&env::var(var)?)) } -pub fn expand_option_env<'cx>( +pub(crate) fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { - let Some(var) = get_single_str_from_tts(cx, sp, tts, "option_env!") else { - return DummyResult::any(sp); +) -> MacroExpanderResult<'cx> { + let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "option_env!") else { + return ExpandResult::Retry(()); + }; + let var = match mac { + Ok(var) => var, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; let sp = cx.with_def_site_ctxt(sp); - let value = lookup_env(cx, var); - cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); + let value = lookup_env(cx, var).ok(); + cx.sess.psess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); @@ -46,7 +52,7 @@ pub fn expand_option_env<'cx>( sp, cx.ty_ident(sp, Ident::new(sym::str, sp)), Some(lt), - ast::Mutability::Not, + Mutability::Not, ))], )) } @@ -56,71 +62,91 @@ pub fn expand_option_env<'cx>( thin_vec![cx.expr_str(sp, value)], ), }; - MacEager::expr(e) + ExpandResult::Ready(MacEager::expr(e)) } -pub fn expand_env<'cx>( +pub(crate) fn expand_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { - let mut exprs = match get_exprs_from_tts(cx, tts) { - Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { - cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); - return DummyResult::any(sp); +) -> MacroExpanderResult<'cx> { + let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else { + return ExpandResult::Retry(()); + }; + let mut exprs = match mac { + Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { + let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); + return ExpandResult::Ready(DummyResult::any(sp, guar)); } - None => return DummyResult::any(sp), - Some(exprs) => exprs.into_iter(), + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), + Ok(exprs) => exprs.into_iter(), }; let var_expr = exprs.next().unwrap(); - let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { - return DummyResult::any(sp); + let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal") + else { + return ExpandResult::Retry(()); + }; + let var = match mac { + Ok((var, _)) => var, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; let custom_msg = match exprs.next() { None => None, - Some(second) => match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::any(sp), - Some((s, _)) => Some(s), - }, + Some(second) => { + let ExpandResult::Ready(mac) = expr_to_string(cx, second, "expected string literal") + else { + return ExpandResult::Retry(()); + }; + match mac { + Ok((s, _)) => Some(s), + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), + } + } }; let span = cx.with_def_site_ctxt(sp); let value = lookup_env(cx, var); - cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); + cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); let e = match value { - None => { - let ast::ExprKind::Lit(ast::token::Lit { - kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..), - symbol, - .. + Err(err) => { + let ExprKind::Lit(token::Lit { + kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. }) = &var_expr.kind else { unreachable!("`expr_to_string` ensures this is a string lit") }; - if let Some(msg_from_user) = custom_msg { - cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }); - } else if is_cargo_env_var(var.as_str()) { - cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { - span, - var: *symbol, - var_expr: var_expr.ast_deref(), - }); - } else { - cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { - span, - var: *symbol, - var_expr: var_expr.ast_deref(), - }); - } + let guar = match err { + VarError::NotPresent => { + if let Some(msg_from_user) = custom_msg { + cx.dcx() + .emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }) + } else if is_cargo_env_var(var.as_str()) { + cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { + span, + var: *symbol, + var_expr: var_expr.ast_deref(), + }) + } else { + cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { + span, + var: *symbol, + var_expr: var_expr.ast_deref(), + }) + } + } + VarError::NotUnicode(_) => { + cx.dcx().emit_err(errors::EnvNotUnicode { span, var: *symbol }) + } + }; - return DummyResult::any(sp); + return ExpandResult::Ready(DummyResult::any(sp, guar)); } - Some(value) => cx.expr_str(span, value), + Ok(value) => cx.expr_str(span, value), }; - MacEager::expr(e) + ExpandResult::Ready(MacEager::expr(e)) } /// Returns `true` if an environment variable from `env!` is one used by Cargo. diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 8d2e06bf30d..d157703723b 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - codes::*, AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee, - IntoDiagnostic, Level, MultiSpan, SingleLabelManySpans, SubdiagnosticMessageOp, + codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -137,27 +137,6 @@ pub(crate) struct BenchSig { } #[derive(Diagnostic)] -#[diag(builtin_macros_test_arg_non_lifetime)] -pub(crate) struct TestArgNonLifetime { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_should_panic)] -pub(crate) struct ShouldPanic { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_test_args)] -pub(crate) struct TestArgs { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] #[diag(builtin_macros_alloc_must_statics)] pub(crate) struct AllocMustStatics { #[primary_span] @@ -446,14 +425,14 @@ pub(crate) struct EnvNotDefinedWithUserMessage { } // Hand-written implementation to support custom user messages. -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage { +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { #[track_caller] - fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { #[expect( rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" )] - let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string()); + let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string()); diag.span(self.span); diag } @@ -480,6 +459,14 @@ pub(crate) enum EnvNotDefined<'a> { } #[derive(Diagnostic)] +#[diag(builtin_macros_env_not_unicode)] +pub(crate) struct EnvNotUnicode { + #[primary_span] + pub(crate) span: Span, + pub(crate) var: Symbol, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_format_requires_string)] pub(crate) struct FormatRequiresString { #[primary_span] @@ -592,7 +579,7 @@ pub(crate) struct FormatUnknownTrait<'a> { style = "tool-only", applicability = "maybe-incorrect" )] -pub struct FormatUnknownTraitSugg { +pub(crate) struct FormatUnknownTraitSugg { #[primary_span] pub span: Span, pub fmt: &'static str, @@ -610,8 +597,12 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. -impl AddToDiagnostic for FormatUnusedArg { - fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { +impl Subdiagnostic for FormatUnusedArg { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { diag.arg("named", self.named); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); diag.span_label(self.span, msg); @@ -784,6 +775,13 @@ pub(crate) struct AsmNoReturn { } #[derive(Diagnostic)] +#[diag(builtin_macros_asm_mayunwind)] +pub(crate) struct AsmMayUnwind { + #[primary_span] + pub(crate) labels_sp: Vec<Span>, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_global_asm_clobber_abi)] pub(crate) struct GlobalAsmClobberAbi { #[primary_span] @@ -795,8 +793,8 @@ pub(crate) struct AsmClobberNoReg { pub(crate) clobbers: Vec<Span>, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { - fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { + fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { // eager translation as `span_labels` takes `AsRef<str>` let lbl1 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_abi, @@ -806,14 +804,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { crate::fluent_generated::builtin_macros_asm_clobber_outputs, [].into_iter(), ); - DiagnosticBuilder::new( - dcx, - level, - crate::fluent_generated::builtin_macros_asm_clobber_no_reg, - ) - .with_span(self.spans.clone()) - .with_span_labels(self.clobbers, &lbl1) - .with_span_labels(self.spans, &lbl2) + Diag::new(dcx, level, crate::fluent_generated::builtin_macros_asm_clobber_no_reg) + .with_span(self.spans.clone()) + .with_span_labels(self.clobbers, &lbl1) + .with_span_labels(self.spans, &lbl2) } } @@ -848,3 +842,26 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister { #[primary_span] pub(crate) span: Span, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_expected_comma_in_list)] +pub(crate) struct ExpectedCommaInList { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_only_one_argument)] +pub(crate) struct OnlyOneArgument<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_takes_no_arguments)] +pub(crate) struct TakesNoArguments<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index b66f7111ff0..5cb0407bd59 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,3 +1,5 @@ +use crate::errors; +use crate::util::expr_to_spanned_string; use parse::Position::ArgumentNamed; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; @@ -5,17 +7,16 @@ use rustc_ast::{token, StmtKind}; use rustc_ast::{ Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, - FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, + FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans}; -use rustc_expand::base::{self, *}; +use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; +use rustc_expand::base::*; +use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; +use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{BytePos, InnerSpan, Span}; - -use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; +use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span}; // The format_args!() macro is expanded in three steps: // 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, @@ -37,8 +38,7 @@ enum PositionUsedAs { } use PositionUsedAs::*; -use crate::errors; - +#[derive(Debug)] struct MacroInput { fmtstr: P<Expr>, args: FormatArguments, @@ -63,7 +63,7 @@ struct MacroInput { /// ```text /// Ok((fmtstr, parsed arguments)) /// ``` -fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> { +fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> { let mut args = FormatArguments::new(); let mut p = ecx.new_parser_from_tts(tts); @@ -111,9 +111,8 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< _ => return Err(err), } } - Ok(recovered) => { - assert!(recovered); - } + Ok(Recovered::Yes(_)) => (), + Ok(Recovered::No) => unreachable!(), } } first = false; @@ -160,51 +159,61 @@ fn make_format_args( ecx: &mut ExtCtxt<'_>, input: MacroInput, append_newline: bool, -) -> Result<FormatArgs, ()> { +) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> { let msg = "format argument must be a string literal"; let unexpanded_fmt_span = input.fmtstr.span; let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input; - let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt.clone(), msg) { - Ok(mut fmt) if append_newline => { - fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); - fmt - } - Ok(fmt) => fmt, - Err(err) => { - if let Some((mut err, suggested)) = err { - if !suggested { - if let ExprKind::Block(block, None) = &efmt.kind - && block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind - && let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() - { - err.multipart_suggestion( - "quote your inlined format argument to use as string literal", - vec![ - (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), - (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } else { - let sugg_fmt = match args.explicit_args().len() { - 0 => "{}".to_string(), - _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), - }; - err.span_suggestion( - unexpanded_fmt_span.shrink_to_lo(), - "you might be missing a string literal to format with", - format!("\"{sugg_fmt}\", "), - Applicability::MaybeIncorrect, - ); + let (fmt_str, fmt_style, fmt_span) = { + let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else { + return ExpandResult::Retry(()); + }; + match mac { + Ok(mut fmt) if append_newline => { + fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); + fmt + } + Ok(fmt) => fmt, + Err(err) => { + let guar = match err { + Ok((mut err, suggested)) => { + if !suggested { + if let ExprKind::Block(block, None) = &efmt.kind + && block.stmts.len() == 1 + && let StmtKind::Expr(expr) = &block.stmts[0].kind + && let ExprKind::Path(None, path) = &expr.kind + && path.is_potential_trivial_const_arg() + { + err.multipart_suggestion( + "quote your inlined format argument to use as string literal", + vec![ + (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), + (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + let sugg_fmt = match args.explicit_args().len() { + 0 => "{}".to_string(), + _ => { + format!("{}{{}}", "{} ".repeat(args.explicit_args().len())) + } + }; + err.span_suggestion( + unexpanded_fmt_span.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{sugg_fmt}\", "), + Applicability::MaybeIncorrect, + ); + } + } + err.emit() } - } - err.emit(); + Err(guar) => guar, + }; + return ExpandResult::Ready(Err(guar)); } - return Err(()); } }; @@ -293,11 +302,11 @@ fn make_format_args( } } } - ecx.dcx().emit_err(e); - return Err(()); + let guar = ecx.dcx().emit_err(e); + return ExpandResult::Ready(Err(guar)); } - let to_span = |inner_span: rustc_parse_format::InnerSpan| { + let to_span = |inner_span: parse::InnerSpan| { is_source_literal.then(|| { fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }) }) @@ -305,7 +314,7 @@ fn make_format_args( let mut used = vec![false; args.explicit_args().len()]; let mut invalid_refs = Vec::new(); - let mut numeric_refences_to_named_arg = Vec::new(); + let mut numeric_references_to_named_arg = Vec::new(); enum ArgRef<'a> { Index(usize), @@ -326,7 +335,7 @@ fn make_format_args( used[index] = true; if arg.kind.ident().is_some() { // This was a named argument, but it was used as a positional argument. - numeric_refences_to_named_arg.push((index, span, used_as)); + numeric_references_to_named_arg.push((index, span, used_as)); } Ok(index) } else { @@ -353,9 +362,9 @@ fn make_format_args( } else { // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); + let guar = ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); unnamed_arg_after_named_arg = true; - DummyResult::raw_expr(span, true) + DummyResult::raw_expr(span, Some(guar)) }; Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) } @@ -534,7 +543,7 @@ fn make_format_args( // Only check for unused named argument names if there are no other errors to avoid causing // too much noise in output errors, such as when a named argument is entirely unused. if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg { - for &(index, span, used_as) in &numeric_refences_to_named_arg { + for &(index, span, used_as) in &numeric_references_to_named_arg { let (position_sp_to_replace, position_sp_for_msg) = match used_as { Placeholder(pspan) => (span, pspan), Precision => { @@ -547,10 +556,9 @@ fn make_format_args( let arg_name = args.explicit_args()[index].kind.ident().unwrap(); ecx.buffered_early_lint.push(BufferedEarlyLint { span: arg_name.span.into(), - msg: format!("named argument `{}` is not used by name", arg_name.name).into(), node_id: rustc_ast::CRATE_NODE_ID, lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY), - diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally { + diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, position_sp_for_msg, named_arg_sp: arg_name.span, @@ -561,13 +569,13 @@ fn make_format_args( } } - Ok(FormatArgs { span: fmt_span, template, arguments: args }) + ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args })) } fn invalid_placeholder_type_error( ecx: &ExtCtxt<'_>, ty: &str, - ty_span: Option<rustc_parse_format::InnerSpan>, + ty_span: Option<parse::InnerSpan>, fmt_span: Span, ) { let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); @@ -593,7 +601,7 @@ fn invalid_placeholder_type_error( } fn report_missing_placeholders( - ecx: &mut ExtCtxt<'_>, + ecx: &ExtCtxt<'_>, unused: Vec<(Span, bool)>, used: &[bool], args: &FormatArguments, @@ -723,11 +731,11 @@ fn report_missing_placeholders( /// This function detects and reports unused format!() arguments that are /// redundant due to implicit captures (e.g. `format!("{x}", x)`). fn report_redundant_format_arguments<'a>( - ecx: &mut ExtCtxt<'a>, + ecx: &ExtCtxt<'a>, args: &FormatArguments, used: &[bool], placeholders: Vec<(Span, &str)>, -) -> Option<DiagnosticBuilder<'a>> { +) -> Option<Diag<'a>> { let mut fmt_arg_indices = vec![]; let mut args_spans = vec![]; let mut fmt_spans = vec![]; @@ -795,7 +803,7 @@ fn report_redundant_format_arguments<'a>( /// there are named arguments or numbered positional arguments in the /// format string. fn report_invalid_references( - ecx: &mut ExtCtxt<'_>, + ecx: &ExtCtxt<'_>, invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)], template: &[FormatArgsPiece], fmt_span: Span, @@ -969,35 +977,39 @@ fn expand_format_args_impl<'cx>( mut sp: Span, tts: TokenStream, nl: bool, -) -> Box<dyn base::MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { sp = ecx.with_def_site_ctxt(sp); - match parse_args(ecx, sp, tts) { + ExpandResult::Ready(match parse_args(ecx, sp, tts) { Ok(input) => { - if let Ok(format_args) = make_format_args(ecx, input, nl) { - MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) - } else { - MacEager::expr(DummyResult::raw_expr(sp, true)) + let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else { + return ExpandResult::Retry(()); + }; + match mac { + Ok(format_args) => { + MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) + } + Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))), } } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } - } + }) } -pub fn expand_format_args<'cx>( +pub(crate) fn expand_format_args<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { expand_format_args_impl(ecx, sp, tts, false) } -pub fn expand_format_args_nl<'cx>( +pub(crate) fn expand_format_args_nl<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { expand_format_args_impl(ecx, sp, tts, true) } diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 307e582d65e..bc2c6def68a 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -263,13 +263,13 @@ pub(crate) mod printf { } impl Num { - fn from_str(s: &str, arg: Option<&str>) -> Self { + fn from_str(s: &str, arg: Option<&str>) -> Option<Self> { if let Some(arg) = arg { - Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`"))) + arg.parse().ok().map(|arg| Num::Arg(arg)) } else if s == "*" { - Num::Next + Some(Num::Next) } else { - Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`"))) + s.parse().ok().map(|num| Num::Num(num)) } } @@ -421,7 +421,10 @@ pub(crate) mod printf { state = Prec; parameter = None; flags = ""; - width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + width = at.slice_between(end).and_then(|num| Num::from_str(num, None)); + if width.is_none() { + return fallback(); + } move_to!(end); } // It's invalid, is what it is. @@ -452,7 +455,10 @@ pub(crate) mod printf { '1'..='9' => { let end = at_next_cp_while(next, char::is_ascii_digit); state = Prec; - width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + width = at.slice_between(end).and_then(|num| Num::from_str(num, None)); + if width.is_none() { + return fallback(); + } move_to!(end); } _ => { @@ -468,7 +474,7 @@ pub(crate) mod printf { match end.next_cp() { Some(('$', end2)) => { state = Prec; - width = Some(Num::from_str("", Some(at.slice_between(end).unwrap()))); + width = Num::from_str("", at.slice_between(end)); move_to!(end2); } _ => { @@ -500,7 +506,7 @@ pub(crate) mod printf { match end.next_cp() { Some(('$', end2)) => { state = Length; - precision = Some(Num::from_str("*", next.slice_between(end))); + precision = Num::from_str("*", next.slice_between(end)); move_to!(end2); } _ => { @@ -513,7 +519,7 @@ pub(crate) mod printf { '0'..='9' => { let end = at_next_cp_while(next, char::is_ascii_digit); state = Length; - precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + precision = at.slice_between(end).and_then(|num| Num::from_str(num, None)); move_to!(end); } _ => return fallback(), diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 099defd511b..b44ff979303 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -6,13 +6,13 @@ use rustc_ast::expand::allocator::{ }; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind}; -use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; +use rustc_ast::{Fn, ItemKind, Mutability, Safety, Stmt, Ty, TyKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand( +pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, _span: Span, meta_item: &ast::MetaItem, @@ -73,7 +73,7 @@ impl AllocFnFactory<'_, '_> { let result = self.call_allocator(method.name, args); let output_ty = self.ret_ty(&method.output); let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); - let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; + let header = FnHeader { safety: Safety::Unsafe(self.span), ..FnHeader::default() }; let sig = FnSig { decl, header, span: self.span }; let body = Some(self.cx.block_expr(result)); let kind = ItemKind::Fn(Box::new(Fn { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index d30ccab2394..744c7f9d090 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -15,14 +15,11 @@ #![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] +#![feature(try_blocks)] extern crate proc_macro; -#[macro_use] -extern crate tracing; - use crate::deriving::*; - use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::symbol::sym; @@ -45,17 +42,17 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; +mod pattern_type; mod source_util; mod test; mod trace_macros; -mod type_ascribe; -mod util; pub mod asm; pub mod cmdline_attrs; pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; +pub mod util; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -95,10 +92,10 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, option_env: env::expand_option_env, + pattern_type: pattern_type::expand, std_panic: edition_panic::expand_panic, stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, - type_ascribe: type_ascribe::expand_type_ascribe, unreachable: edition_panic::expand_unreachable, // tidy-alphabetical-end } @@ -108,8 +105,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, - derive: derive::Expander(false), - derive_const: derive::Expander(true), + derive: derive::Expander { is_const: false }, + derive_const: derive::Expander { is_const: true }, global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, diff --git a/compiler/rustc_builtin_macros/src/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs index ede34a76125..205f21ae7c9 100644 --- a/compiler/rustc_builtin_macros/src/log_syntax.rs +++ b/compiler/rustc_builtin_macros/src/log_syntax.rs @@ -1,14 +1,14 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_expand::base; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -pub fn expand_log_syntax<'cx>( - _cx: &'cx mut base::ExtCtxt<'_>, +pub(crate) fn expand_log_syntax<'cx>( + _cx: &'cx mut ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { println!("{}", pprust::tts_to_string(&tts)); // any so that `log_syntax` can be invoked as an expression and item. - base::DummyResult::any_valid(sp) + ExpandResult::Ready(DummyResult::any_valid(sp)) } diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs new file mode 100644 index 00000000000..31f5656df13 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -0,0 +1,29 @@ +use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_span::{sym, Span}; + +pub(crate) fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let (ty, pat) = match parse_pat_ty(cx, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat)))) +} + +fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> { + let mut parser = cx.new_parser_from_tts(stream); + + let ty = parser.parse_ty()?; + parser.eat_keyword(sym::is); + let pat = parser.parse_pat_no_top_alt(None, None)?; + + Ok((ty, pat)) +} diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 43d13569d1e..dc1d82df0c3 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,17 +1,25 @@ +use crate::util::{ + check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, +}; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_expand::base::{self, *}; +use rustc_data_structures::sync::Lrc; +use rustc_expand::base::{ + resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, +}; use rustc_expand::module::DirOwnership; -use rustc_parse::new_parser_from_file; +use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; use rustc_span::{Pos, Span}; - use smallvec::SmallVec; +use std::path::{Path, PathBuf}; use std::rc::Rc; // These macros all relate to the file system; they either return @@ -19,102 +27,106 @@ use std::rc::Rc; // a given file into the current one. /// line!(): expands to the current line number -pub fn expand_line( +pub(crate) fn expand_line( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "line!"); + check_zero_tts(cx, sp, tts, "line!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) + ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32))) } /* column!(): expands to the current column number */ -pub fn expand_column( +pub(crate) fn expand_column( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "column!"); + check_zero_tts(cx, sp, tts, "column!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)) + ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))) } /// file!(): expands to the current filename */ /// The source_file (`loc.file`) contains a bunch more information we could spit /// out if we wanted. -pub fn expand_file( +pub(crate) fn expand_file( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "file!"); + check_zero_tts(cx, sp, tts, "file!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; - base::MacEager::expr(cx.expr_str( + ExpandResult::Ready(MacEager::expr(cx.expr_str( topmost, Symbol::intern( &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), ), - )) + ))) } -pub fn expand_stringify( +pub(crate) fn expand_stringify( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); let s = pprust::tts_to_string(&tts); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) + ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))) } -pub fn expand_mod( +pub(crate) fn expand_mod( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "module_path!"); + check_zero_tts(cx, sp, tts, "module_path!"); let mod_path = &cx.current_expansion.module.mod_path; let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::"); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))) + ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))) } /// include! : parse the given file as an expr /// This is generally a bad idea because it's going to behave /// unhygienically. -pub fn expand_include<'cx>( +pub(crate) fn expand_include<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'cx> { +) -> MacroExpanderResult<'cx> { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include!") else { - return DummyResult::any(sp); + let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else { + return ExpandResult::Retry(()); + }; + let file = match mac { + Ok(file) => file, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; // The file will be added to the code map by the parser let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return ExpandResult::Ready(DummyResult::any(sp, guar)); } }; - let p = new_parser_from_file(cx.parse_sess(), &file, Some(sp)); + let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp))); // If in the included file we have e.g., `mod bar;`, // then the path of `bar.rs` should be relative to the directory of `file`. @@ -124,25 +136,25 @@ pub fn expand_include<'cx>( cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path)); cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None }; - struct ExpandResult<'a> { + struct ExpandInclude<'a> { p: Parser<'a>, node_id: ast::NodeId, } - impl<'a> base::MacResult for ExpandResult<'a> { - fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> { - let r = base::parse_expr(&mut self.p)?; + impl<'a> MacResult for ExpandInclude<'a> { + fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> { + let expr = parse_expr(&mut self.p).ok()?; if self.p.token != token::Eof { - self.p.sess.buffer_lint( + self.p.psess.buffer_lint( INCOMPLETE_INCLUDE, self.p.token.span, self.node_id, - "include macro expected single expression in source", + BuiltinLintDiag::IncompleteInclude, ); } - Some(r) + Some(expr) } - fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> { + fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> { let mut ret = SmallVec::new(); loop { match self.p.parse_item(ForceCollect::No) { @@ -166,68 +178,166 @@ pub fn expand_include<'cx>( } } - Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id }) + ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id })) } /// `include_str!`: read the given file, insert it as a literal string expr -pub fn expand_include_str( +pub(crate) fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { - return DummyResult::any(sp); + let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_str!") + else { + return ExpandResult::Retry(()); }; - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, - Err(err) => { - err.emit(); - return DummyResult::any(sp); - } + let (path, path_span) = match mac { + Ok(res) => res, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; - match cx.source_map().load_binary_file(&file) { - Ok(bytes) => match std::str::from_utf8(&bytes) { + ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { + Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); - base::MacEager::expr(cx.expr_str(sp, interned_src)) + MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } Err(_) => { - cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); + DummyResult::any(sp, guar) } }, - Err(e) => { - cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp) - } - } + Err(dummy) => dummy, + }) } -pub fn expand_include_bytes( +pub(crate) fn expand_include_bytes( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else { - return DummyResult::any(sp); + let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_bytes!") + else { + return ExpandResult::Retry(()); }; - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, + let (path, path_span) = match mac { + Ok(res) => res, + Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), + }; + ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { + Ok((bytes, _bsp)) => { + // Don't care about getting the span for the raw bytes, + // because the console can't really show them anyway. + let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); + MacEager::expr(expr) + } + Err(dummy) => dummy, + }) +} + +fn load_binary_file( + cx: &ExtCtxt<'_>, + original_path: &Path, + macro_span: Span, + path_span: Span, +) -> Result<(Lrc<[u8]>, Span), Box<dyn MacResult>> { + let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) { + Ok(path) => path, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return Err(DummyResult::any(macro_span, guar)); } }; - match cx.source_map().load_binary_file(&file) { - Ok(bytes) => { - let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); - base::MacEager::expr(expr) + match cx.source_map().load_binary_file(&resolved_path) { + Ok(data) => Ok(data), + Err(io_err) => { + let mut err = cx.dcx().struct_span_err( + macro_span, + format!("couldn't read `{}`: {io_err}", resolved_path.display()), + ); + + if original_path.is_relative() { + let source_map = cx.sess.source_map(); + let new_path = source_map + .span_to_filename(macro_span.source_callsite()) + .into_local_path() + .and_then(|src| find_path_suggestion(source_map, src.parent()?, original_path)) + .and_then(|path| path.into_os_string().into_string().ok()); + + if let Some(new_path) = new_path { + err.span_suggestion( + path_span, + "there is a file with the same name in a different directory", + format!("\"{}\"", new_path.replace('\\', "/").escape_debug()), + rustc_lint_defs::Applicability::MachineApplicable, + ); + } + } + let guar = err.emit(); + Err(DummyResult::any(macro_span, guar)) } - Err(e) => { - cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp) + } +} + +fn find_path_suggestion( + source_map: &SourceMap, + base_dir: &Path, + wanted_path: &Path, +) -> Option<PathBuf> { + // Fix paths that assume they're relative to cargo manifest dir + let mut base_c = base_dir.components(); + let mut wanted_c = wanted_path.components(); + let mut without_base = None; + while let Some(wanted_next) = wanted_c.next() { + if wanted_c.as_path().file_name().is_none() { + break; + } + // base_dir may be absolute + while let Some(base_next) = base_c.next() { + if base_next == wanted_next { + without_base = Some(wanted_c.as_path()); + break; + } } } + let root_absolute = without_base.into_iter().map(PathBuf::from); + + let base_dir_components = base_dir.components().count(); + // Avoid going all the way to the root dir + let max_parent_components = if base_dir.is_relative() { + base_dir_components + 1 + } else { + base_dir_components.saturating_sub(1) + }; + + // Try with additional leading ../ + let mut prefix = PathBuf::new(); + let add = std::iter::from_fn(|| { + prefix.push(".."); + Some(prefix.join(wanted_path)) + }) + .take(max_parent_components.min(3)); + + // Try without leading directories + let mut trimmed_path = wanted_path; + let remove = std::iter::from_fn(|| { + let mut components = trimmed_path.components(); + let removed = components.next()?; + trimmed_path = components.as_path(); + let _ = trimmed_path.file_name()?; // ensure there is a file name left + Some([ + Some(trimmed_path.to_path_buf()), + (removed != std::path::Component::ParentDir) + .then(|| Path::new("..").join(trimmed_path)), + ]) + }) + .flatten() + .flatten() + .take(4); + + root_absolute + .chain(add) + .chain(remove) + .find(|new_path| source_map.file_exists(&base_dir.join(&new_path))) } diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 3ee3112f021..9bcd793c450 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -17,7 +17,7 @@ pub fn inject( features: &Features, ) -> usize { let orig_num_items = krate.items.len(); - let edition = sess.parse_sess.edition; + let edition = sess.psess.edition; // the first name in this list is the crate name of the crate with the prelude let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 0631f796894..8f96070d149 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -5,13 +5,14 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast::ptr::P; use rustc_ast::{self as ast, attr, GenericParamKind}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, DiagnosticBuilder, Level}; +use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; use std::assert_matches::assert_matches; use std::iter; use thin_vec::{thin_vec, ThinVec}; +use tracing::debug; /// #[test_case] is used by custom test authors to mark tests /// When building for test, it needs to make the item public and gensym the name @@ -20,7 +21,7 @@ use thin_vec::{thin_vec, ThinVec}; /// /// We mark item with an inert attribute "rustc_test_marker" which the test generation /// logic will pick up on. -pub fn expand_test_case( +pub(crate) fn expand_test_case( ecx: &mut ExtCtxt<'_>, attr_sp: Span, meta_item: &ast::MetaItem, @@ -73,7 +74,7 @@ pub fn expand_test_case( vec![ret] } -pub fn expand_test( +pub(crate) fn expand_test( cx: &mut ExtCtxt<'_>, attr_sp: Span, meta_item: &ast::MetaItem, @@ -84,7 +85,7 @@ pub fn expand_test( expand_test_or_bench(cx, attr_sp, item, false) } -pub fn expand_bench( +pub(crate) fn expand_bench( cx: &mut ExtCtxt<'_>, attr_sp: Span, meta_item: &ast::MetaItem, @@ -95,8 +96,8 @@ pub fn expand_bench( expand_test_or_bench(cx, attr_sp, item, true) } -pub fn expand_test_or_bench( - cx: &mut ExtCtxt<'_>, +pub(crate) fn expand_test_or_bench( + cx: &ExtCtxt<'_>, attr_sp: Span, item: Annotatable, is_bench: bool, @@ -410,7 +411,7 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) Some(ast::ItemKind::MacCall(_)) => Level::Warning, _ => Level::Error, }; - let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg); + let mut err = Diag::<()>::new(dcx, level, msg); err.span(attr_sp); if let Some(item) = item { err.span_label( @@ -548,7 +549,7 @@ fn check_test_signature( let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let dcx = cx.dcx(); - if let ast::Unsafe::Yes(span) = f.sig.header.unsafety { + if let ast::Safety::Unsafe(span) = f.sig.header.safety { return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" })); } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index dc28cd2ea31..38ac2f15fe7 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -9,6 +9,7 @@ use rustc_ast::{attr, ModKind}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; +use rustc_lint_defs::BuiltinLintDiag; use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; use rustc_session::Session; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; @@ -159,11 +160,11 @@ struct InnerItemLinter<'a> { impl<'a> Visitor<'a> for InnerItemLinter<'_> { fn visit_item(&mut self, i: &'a ast::Item) { if let Some(attr) = attr::find_by_name(&i.attrs, sym::rustc_test_marker) { - self.sess.parse_sess.buffer_lint( + self.sess.psess.buffer_lint( UNNAMEABLE_TEST_ITEMS, attr.span, i.id, - crate::fluent_generated::builtin_macros_unnameable_test_items, + BuiltinLintDiag::UnnameableTestItems, ); } } @@ -200,7 +201,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { let allow_dead_code = attr::mk_attr_nested_word( - &self.sess.parse_sess.attr_id_generator, + &self.sess.psess.attr_id_generator, ast::AttrStyle::Outer, sym::allow, sym::dead_code, @@ -266,7 +267,7 @@ fn generate_test_harness( /// /// By default this expands to /// -/// ```ignore UNSOLVED (I think I still need guidance for this one. Is it correct? Do we try to make it run? How do we nicely fill it out?) +/// ```ignore (messes with test internals) /// #[rustc_main] /// pub fn main() { /// extern crate test; diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs index e076aa6da73..4833ec32f76 100644 --- a/compiler/rustc_builtin_macros/src/trace_macros.rs +++ b/compiler/rustc_builtin_macros/src/trace_macros.rs @@ -1,14 +1,14 @@ use crate::errors; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_expand::base::{self, ExtCtxt}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::symbol::kw; use rustc_span::Span; -pub fn expand_trace_macros( +pub(crate) fn expand_trace_macros( cx: &mut ExtCtxt<'_>, sp: Span, tt: TokenStream, -) -> Box<dyn base::MacResult + 'static> { +) -> MacroExpanderResult<'static> { let mut cursor = tt.trees(); let mut err = false; let value = match &cursor.next() { @@ -26,5 +26,5 @@ pub fn expand_trace_macros( cx.set_trace_macros(value); } - base::DummyResult::any_valid(sp) + ExpandResult::Ready(DummyResult::any_valid(sp)) } diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs deleted file mode 100644 index 564797012ae..00000000000 --- a/compiler/rustc_builtin_macros/src/type_ascribe.rs +++ /dev/null @@ -1,35 +0,0 @@ -use rustc_ast::ptr::P; -use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{token, Expr, ExprKind, Ty}; -use rustc_errors::PResult; -use rustc_expand::base::{self, DummyResult, ExtCtxt, MacEager}; -use rustc_span::Span; - -pub fn expand_type_ascribe( - cx: &mut ExtCtxt<'_>, - span: Span, - tts: TokenStream, -) -> Box<dyn base::MacResult + 'static> { - let (expr, ty) = match parse_ascribe(cx, tts) { - Ok(parsed) => parsed, - Err(err) => { - err.emit(); - return DummyResult::any(span); - } - }; - - let asc_expr = cx.expr(span, ExprKind::Type(expr, ty)); - - return MacEager::expr(asc_expr); -} - -fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> { - let mut parser = cx.new_parser_from_tts(stream); - - let expr = parser.parse_expr()?; - parser.expect(&token::Comma)?; - - let ty = parser.parse_ty()?; - - Ok((expr, ty)) -} diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index eeaf00004e6..652e34268ea 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,15 +1,20 @@ -use rustc_ast::{attr, AttrStyle, Attribute, MetaItem}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use crate::errors; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{self as ast, attr, ptr::P, token, AttrStyle, Attribute, MetaItem}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; +use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; +use rustc_expand::expand::AstFragment; use rustc_feature::AttributeTemplate; -use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; -use rustc_parse::validate_attr; -use rustc_span::Symbol; +use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag}; +use rustc_parse::{parser, validate_attr}; +use rustc_session::errors::report_lit_error; +use rustc_span::{BytePos, Span, Symbol}; -pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { +pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { // All the built-in macro attributes are "words" at the moment. let template = AttributeTemplate { word: true, ..Default::default() }; validate_attr::check_builtin_meta_item( - &ecx.sess.parse_sess, + &ecx.sess.psess, meta_item, AttrStyle::Outer, name, @@ -19,7 +24,7 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na /// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when /// an attribute may have been mistakenly duplicated. -pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) { +pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) { let attrs: Option<&[Attribute]> = match item { Annotatable::Item(item) => Some(&item.attrs), Annotatable::TraitItem(item) => Some(&item.attrs), @@ -37,12 +42,187 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: }; if let Some(attrs) = attrs { if let Some(attr) = attr::find_by_name(attrs, name) { - ecx.parse_sess().buffer_lint( + ecx.psess().buffer_lint( DUPLICATE_MACRO_ATTRIBUTES, attr.span, ecx.current_expansion.lint_node_id, - "duplicated attribute", + BuiltinLintDiag::DuplicateMacroAttribute, ); } } } + +/// `Ok` represents successfully retrieving the string literal at the correct +/// position, e.g., `println("abc")`. +type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>; + +/// - `Ok` is returned when the conversion to a string literal is unsuccessful, +/// but another type of expression is obtained instead. +/// - `Err` is returned when the conversion process fails. +type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>; + +/// Extracts a string literal from the macro expanded version of `expr`, +/// returning a diagnostic error of `err_msg` if `expr` is not a string literal. +/// The returned bool indicates whether an applicable suggestion has already been +/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))` +/// indicates that an ast error was encountered. +// FIXME(Nilstrieb) Make this function setup translatable +#[allow(rustc::untranslatable_diagnostic)] +pub(crate) fn expr_to_spanned_string<'a>( + cx: &'a mut ExtCtxt<'_>, + expr: P<ast::Expr>, + err_msg: &'static str, +) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> { + if !cx.force_mode + && let ast::ExprKind::MacCall(m) = &expr.kind + && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() + { + return ExpandResult::Retry(()); + } + + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + + ExpandResult::Ready(Err(match expr.kind { + ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Str(s, style)) => { + return ExpandResult::Ready(Ok((s, style, expr.span))); + } + Ok(ast::LitKind::ByteStr(..)) => { + let mut err = cx.dcx().struct_span_err(expr.span, err_msg); + let span = expr.span.shrink_to_lo(); + err.span_suggestion( + span.with_hi(span.lo() + BytePos(1)), + "consider removing the leading `b`", + "", + Applicability::MaybeIncorrect, + ); + Ok((err, true)) + } + Ok(ast::LitKind::Err(guar)) => Err(guar), + Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)), + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), + }, + ast::ExprKind::Err(guar) => Err(guar), + ast::ExprKind::Dummy => { + cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") + } + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), + })) +} + +/// Extracts a string literal from the macro expanded version of `expr`, +/// emitting `err_msg` if `expr` is not a string literal. This does not stop +/// compilation on error, merely emits a non-fatal error and returns `Err`. +pub(crate) fn expr_to_string( + cx: &mut ExtCtxt<'_>, + expr: P<ast::Expr>, + err_msg: &'static str, +) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> { + expr_to_spanned_string(cx, expr, err_msg).map(|res| { + res.map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }) + .map(|(symbol, style, _)| (symbol, style)) + }) +} + +/// Non-fatally assert that `tts` is empty. Note that this function +/// returns even when `tts` is non-empty, macros that *need* to stop +/// compilation should call `cx.diagnostic().abort_if_errors()` +/// (this should be done as rarely as possible). +pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) { + if !tts.is_empty() { + cx.dcx().emit_err(errors::TakesNoArguments { span, name }); + } +} + +/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`. +pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<P<ast::Expr>, ErrorGuaranteed> { + let guar = match p.parse_expr() { + Ok(expr) => return Ok(expr), + Err(err) => err.emit(), + }; + while p.token != token::Eof { + p.bump(); + } + Err(guar) +} + +/// Interpreting `tts` as a comma-separated sequence of expressions, +/// expect exactly one string literal, or emit an error and return `Err`. +pub(crate) fn get_single_str_from_tts( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, + name: &str, +) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> { + get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s)) +} + +pub(crate) fn get_single_str_spanned_from_tts( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, + name: &str, +) -> ExpandResult<Result<(Symbol, Span), ErrorGuaranteed>, ()> { + let mut p = cx.new_parser_from_tts(tts); + if p.token == token::Eof { + let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + return ExpandResult::Ready(Err(guar)); + } + let ret = match parse_expr(&mut p) { + Ok(ret) => ret, + Err(guar) => return ExpandResult::Ready(Err(guar)), + }; + let _ = p.eat(&token::Comma); + + if p.token != token::Eof { + cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + } + expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| { + res.map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }) + .map(|(symbol, _style, span)| (symbol, span)) + }) +} + +/// Extracts comma-separated expressions from `tts`. +/// On error, emit it, and return `Err`. +pub(crate) fn get_exprs_from_tts( + cx: &mut ExtCtxt<'_>, + tts: TokenStream, +) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> { + let mut p = cx.new_parser_from_tts(tts); + let mut es = Vec::new(); + while p.token != token::Eof { + let expr = match parse_expr(&mut p) { + Ok(expr) => expr, + Err(guar) => return ExpandResult::Ready(Err(guar)), + }; + if !cx.force_mode + && let ast::ExprKind::MacCall(m) = &expr.kind + && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() + { + return ExpandResult::Retry(()); + } + + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + + es.push(expr); + if p.eat(&token::Comma) { + continue; + } + if p.token != token::Eof { + let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span }); + return ExpandResult::Ready(Err(guar)); + } + } + ExpandResult::Ready(Ok(es)) +} |
