From 5363f350887b1e5b5dd21a86f88c8af9d7fea6da Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:25 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- .../src/alloc_error_handler.rs | 93 +++++++++ compiler/rustc_builtin_macros/src/asm.rs | 8 +- compiler/rustc_builtin_macros/src/assert.rs | 10 +- .../rustc_builtin_macros/src/assert/context.rs | 71 ++++--- .../rustc_builtin_macros/src/cfg_accessible.rs | 7 +- compiler/rustc_builtin_macros/src/concat.rs | 28 +-- compiler/rustc_builtin_macros/src/concat_bytes.rs | 108 ++++++---- compiler/rustc_builtin_macros/src/derive.rs | 59 +++--- .../rustc_builtin_macros/src/deriving/bounds.rs | 4 +- .../rustc_builtin_macros/src/deriving/clone.rs | 22 +- .../rustc_builtin_macros/src/deriving/cmp/eq.rs | 15 +- .../rustc_builtin_macros/src/deriving/cmp/ord.rs | 6 +- .../src/deriving/cmp/partial_eq.rs | 6 +- .../src/deriving/cmp/partial_ord.rs | 6 +- .../rustc_builtin_macros/src/deriving/debug.rs | 3 +- .../rustc_builtin_macros/src/deriving/decodable.rs | 23 ++- .../rustc_builtin_macros/src/deriving/default.rs | 21 +- .../rustc_builtin_macros/src/deriving/encodable.rs | 11 +- .../src/deriving/generic/mod.rs | 225 ++++++++------------- .../src/deriving/generic/ty.rs | 9 +- compiler/rustc_builtin_macros/src/deriving/hash.rs | 3 +- compiler/rustc_builtin_macros/src/deriving/mod.rs | 43 ++-- compiler/rustc_builtin_macros/src/edition_panic.rs | 36 ++-- compiler/rustc_builtin_macros/src/env.rs | 2 +- .../rustc_builtin_macros/src/format_foreign.rs | 34 ++-- .../src/format_foreign/printf/tests.rs | 2 +- .../src/format_foreign/shell/tests.rs | 2 +- .../rustc_builtin_macros/src/global_allocator.rs | 36 ++-- compiler/rustc_builtin_macros/src/lib.rs | 7 +- .../rustc_builtin_macros/src/proc_macro_harness.rs | 14 +- compiler/rustc_builtin_macros/src/source_util.rs | 7 +- .../src/standard_library_imports.rs | 4 +- compiler/rustc_builtin_macros/src/test.rs | 142 ++++++------- compiler/rustc_builtin_macros/src/test_harness.rs | 23 +-- compiler/rustc_builtin_macros/src/type_ascribe.rs | 35 ++++ compiler/rustc_builtin_macros/src/util.rs | 11 +- 36 files changed, 620 insertions(+), 516 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/alloc_error_handler.rs create mode 100644 compiler/rustc_builtin_macros/src/type_ascribe.rs (limited to 'compiler/rustc_builtin_macros/src') diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs new file mode 100644 index 000000000..95e38e4b0 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -0,0 +1,93 @@ +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_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; +use thin_vec::thin_vec; + +pub fn expand( + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler); + + let orig_item = item.clone(); + + // Allow using `#[alloc_error_handler]` on an item statement + // FIXME - if we get deref patterns, use them to reduce duplication here + let (item, is_stmt, sig_span) = + if let Annotatable::Item(item) = &item + && let ItemKind::Fn(fn_kind) = &item.kind + { + (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } else if let Annotatable::Stmt(stmt) = &item + && let StmtKind::Item(item) = &stmt.kind + && let ItemKind::Fn(fn_kind) = &item.kind + { + (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } else { + ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function"); + return vec![orig_item.clone()]; + }; + + // Generate a bunch of new items using the AllocFnFactory + let span = ecx.with_def_site_ctxt(item.span); + + // Generate item statements for the allocator methods. + let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)]; + + // Generate anonymous constant serving as container for the allocator methods. + let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new())); + let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + } else { + Annotatable::Item(const_item) + }; + + // Return the original item and the new methods. + vec![orig_item, const_item] +} + +// #[rustc_std_internal_symbol] +// unsafe fn __rg_oom(size: usize, align: usize) -> ! { +// handler(core::alloc::Layout::from_size_align_unchecked(size, align)) +// } +fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { + let usize = cx.path_ident(span, Ident::new(sym::usize, span)); + let ty_usize = cx.ty_path(usize); + let size = Ident::from_str_and_span("size", span); + let align = Ident::from_str_and_span("align", span); + + let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); + let layout_new = cx.expr_path(cx.path(span, layout_new)); + let layout = + cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]); + + let call = cx.expr_call_ident(sig_span, handler, vec![layout]); + + let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); + let params = 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 sig = FnSig { decl, header, span: span }; + + let body = Some(cx.block_expr(call)); + let kind = ItemKind::Fn(Box::new(Fn { + defaultness: ast::Defaultness::Final, + sig, + generics: Generics::default(), + body, + })); + + let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; + + let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind); + cx.stmt_item(sig_span, item) +} diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index a1051d990..900c44274 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -172,7 +172,11 @@ pub fn parse_asm_args<'a>( // If it can't possibly expand to a string, provide diagnostics here to include other // things it could have been. match template.kind { - ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {} + ast::ExprKind::Lit(token_lit) + if matches!( + token_lit.kind, + token::LitKind::Str | token::LitKind::StrRaw(_) + ) => {} ast::ExprKind::MacCall(..) => {} _ => { let errstr = if is_global_asm { @@ -560,7 +564,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option( call_site_span, ExprKind::MacCall(P(MacCall { path: panic_path(), - args: P(MacArgs::Delimited( - DelimSpan::from_single(call_site_span), - MacDelimiter::Parenthesis, + args: P(DelimArgs { + dspan: DelimSpan::from_single(call_site_span), + delim: MacDelimiter::Parenthesis, tokens, - )), + }), prior_type_ascription: None, })), ); diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index bb6839360..93b07801e 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,10 +1,9 @@ use rustc_ast::{ - attr, ptr::P, token, tokenstream::{DelimSpan, TokenStream, TokenTree}, - BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, - Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, + BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MacDelimiter, MethodCall, + Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -107,7 +106,7 @@ impl<'cx, 'a> Context<'cx, 'a> { ( UseTree { prefix: this.cx.path(this.span, vec![Ident::with_dummy_span(sym)]), - kind: UseTreeKind::Simple(None, DUMMY_NODE_ID, DUMMY_NODE_ID), + kind: UseTreeKind::Simple(None), span: this.span, }, DUMMY_NODE_ID, @@ -118,10 +117,7 @@ impl<'cx, 'a> Context<'cx, 'a> { self.cx.item( self.span, Ident::empty(), - thin_vec![self.cx.attribute(attr::mk_list_item( - Ident::new(sym::allow, self.span), - vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))], - ))], + 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(vec![ @@ -181,11 +177,11 @@ impl<'cx, 'a> Context<'cx, 'a> { self.span, ExprKind::MacCall(P(MacCall { path: panic_path, - args: P(MacArgs::Delimited( - DelimSpan::from_single(self.span), - MacDelimiter::Parenthesis, - initial.into_iter().chain(captures).collect::(), - )), + args: P(DelimArgs { + dspan: DelimSpan::from_single(self.span), + delim: MacDelimiter::Parenthesis, + tokens: initial.into_iter().chain(captures).collect::(), + }), prior_type_ascription: None, })), ) @@ -195,19 +191,19 @@ impl<'cx, 'a> Context<'cx, 'a> { /// /// See [Self::manage_initial_capture] and [Self::manage_try_capture] fn manage_cond_expr(&mut self, expr: &mut P) { - match (*expr).kind { - ExprKind::AddrOf(_, mutability, ref mut local_expr) => { + match &mut expr.kind { + ExprKind::AddrOf(_, mutability, local_expr) => { self.with_is_consumed_management( matches!(mutability, Mutability::Mut), |this| this.manage_cond_expr(local_expr) ); } - ExprKind::Array(ref mut local_exprs) => { + ExprKind::Array(local_exprs) => { for local_expr in local_exprs { self.manage_cond_expr(local_expr); } } - ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => { + ExprKind::Binary(op, lhs, rhs) => { self.with_is_consumed_management( matches!( op.node, @@ -230,56 +226,56 @@ impl<'cx, 'a> Context<'cx, 'a> { } ); } - ExprKind::Call(_, ref mut local_exprs) => { + ExprKind::Call(_, local_exprs) => { for local_expr in local_exprs { self.manage_cond_expr(local_expr); } } - ExprKind::Cast(ref mut local_expr, _) => { + ExprKind::Cast(local_expr, _) => { self.manage_cond_expr(local_expr); } - ExprKind::Index(ref mut prefix, ref mut suffix) => { + ExprKind::Index(prefix, suffix) => { self.manage_cond_expr(prefix); self.manage_cond_expr(suffix); } - ExprKind::MethodCall(_, _,ref mut local_exprs, _) => { - for local_expr in local_exprs.iter_mut() { - self.manage_cond_expr(local_expr); + ExprKind::MethodCall(call) => { + for arg in &mut call.args { + self.manage_cond_expr(arg); } } - ExprKind::Path(_, Path { ref segments, .. }) if let &[ref path_segment] = &segments[..] => { + ExprKind::Path(_, Path { segments, .. }) if let [path_segment] = &segments[..] => { let path_ident = path_segment.ident; self.manage_initial_capture(expr, path_ident); } - ExprKind::Paren(ref mut local_expr) => { + ExprKind::Paren(local_expr) => { self.manage_cond_expr(local_expr); } - ExprKind::Range(ref mut prefix, ref mut suffix, _) => { - if let Some(ref mut elem) = prefix { + ExprKind::Range(prefix, suffix, _) => { + if let Some(elem) = prefix { self.manage_cond_expr(elem); } - if let Some(ref mut elem) = suffix { + if let Some(elem) = suffix { self.manage_cond_expr(elem); } } - ExprKind::Repeat(ref mut local_expr, ref mut elem) => { + ExprKind::Repeat(local_expr, elem) => { self.manage_cond_expr(local_expr); self.manage_cond_expr(&mut elem.value); } - ExprKind::Struct(ref mut elem) => { + ExprKind::Struct(elem) => { for field in &mut elem.fields { self.manage_cond_expr(&mut field.expr); } - if let StructRest::Base(ref mut local_expr) = elem.rest { + if let StructRest::Base(local_expr) = &mut elem.rest { self.manage_cond_expr(local_expr); } } - ExprKind::Tup(ref mut local_exprs) => { + ExprKind::Tup(local_exprs) => { for local_expr in local_exprs { self.manage_cond_expr(local_expr); } } - ExprKind::Unary(un_op, ref mut local_expr) => { + ExprKind::Unary(un_op, local_expr) => { self.with_is_consumed_management( matches!(un_op, UnOp::Neg | UnOp::Not), |this| this.manage_cond_expr(local_expr) @@ -296,17 +292,18 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Block(_, _) | ExprKind::Box(_) | ExprKind::Break(_, _) - | ExprKind::Closure(_, _, _, _, _, _, _) + | ExprKind::Closure(_) | ExprKind::ConstBlock(_) | ExprKind::Continue(_) | ExprKind::Err | ExprKind::Field(_, _) | ExprKind::ForLoop(_, _, _, _) | ExprKind::If(_, _, _) + | ExprKind::IncludedBytes(..) | ExprKind::InlineAsm(_) | ExprKind::Let(_, _, _) | ExprKind::Lit(_) - | ExprKind::Loop(_, _) + | ExprKind::Loop(_, _, _) | ExprKind::MacCall(_) | ExprKind::Match(_, _) | ExprKind::Path(_, _) @@ -441,12 +438,12 @@ fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P) -> P { fn expr_method_call( cx: &ExtCtxt<'_>, - path: PathSegment, + seg: PathSegment, receiver: P, args: Vec>, span: Span, ) -> P { - cx.expr(span, ExprKind::MethodCall(path, receiver, args, span)) + cx.expr(span, ExprKind::MethodCall(Box::new(MethodCall { seg, receiver, args, span }))) } fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P) -> P { diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index cb5359dd1..4e4cafc71 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -34,12 +34,13 @@ impl MultiItemModifier for Expander { span: Span, meta_item: &ast::MetaItem, item: Annotatable, + _is_derive_const: bool, ) -> ExpandResult, Annotatable> { let template = AttributeTemplate { list: Some("path"), ..Default::default() }; - let attr = &ecx.attribute(meta_item.clone()); - validate_attr::check_builtin_attribute( + validate_attr::check_builtin_meta_item( &ecx.sess.parse_sess, - attr, + &meta_item, + ast::AttrStyle::Outer, sym::cfg_accessible, template, ); diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 41f4e8c23..e2d71825d 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -1,6 +1,7 @@ use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; use rustc_expand::base::{self, DummyResult}; +use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; use std::string::String; @@ -18,31 +19,34 @@ pub fn expand_concat( let mut has_errors = false; for e in es { match e.kind { - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _) => { + ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => { accumulator.push_str(s.as_str()); } - ast::LitKind::Char(c) => { + Ok(ast::LitKind::Char(c)) => { accumulator.push(c); } - ast::LitKind::Int( - i, - ast::LitIntType::Unsigned(_) - | ast::LitIntType::Signed(_) - | ast::LitIntType::Unsuffixed, - ) => { + Ok(ast::LitKind::Int(i, _)) => { accumulator.push_str(&i.to_string()); } - ast::LitKind::Bool(b) => { + Ok(ast::LitKind::Bool(b)) => { accumulator.push_str(&b.to_string()); } - ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => { + Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { cx.span_err(e.span, "cannot concatenate a byte string literal"); + has_errors = true; + } + Ok(ast::LitKind::Err) => { + has_errors = true; } - ast::LitKind::Err => { + Err(err) => { + report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); has_errors = true; } }, + ast::ExprKind::IncludedBytes(..) => { + cx.span_err(e.span, "cannot concatenate a byte string literal") + } ast::ExprKind::Err => { has_errors = true; } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 66e86bf21..d1124145d 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -2,18 +2,22 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; use rustc_errors::Applicability; use rustc_expand::base::{self, DummyResult}; +use rustc_session::errors::report_lit_error; +use rustc_span::Span; /// Emits errors for literal expressions that are invalid inside and outside of an array. -fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_nested: bool) { - let ast::ExprKind::Lit(lit) = &expr.kind else { - unreachable!(); - }; - match lit.kind { - ast::LitKind::Char(_) => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { +fn invalid_type_err( + cx: &mut base::ExtCtxt<'_>, + token_lit: ast::token::Lit, + span: Span, + is_nested: bool, +) { + match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Char(_)) => { + let mut err = cx.struct_span_err(span, "cannot concatenate character literals"); + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { err.span_suggestion( - expr.span, + span, "try using a byte character", format!("b{}", snippet), Applicability::MachineApplicable, @@ -21,13 +25,13 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne .emit(); } } - ast::LitKind::Str(_, _) => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals"); + Ok(ast::LitKind::Str(_, _)) => { + let mut err = cx.struct_span_err(span, "cannot concatenate string literals"); // suggestion would be invalid if we are nested if !is_nested { - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { err.span_suggestion( - expr.span, + span, "try using a byte string", format!("b{}", snippet), Applicability::MachineApplicable, @@ -36,18 +40,18 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne } err.emit(); } - ast::LitKind::Float(_, _) => { - cx.span_err(expr.span, "cannot concatenate float literals"); + Ok(ast::LitKind::Float(_, _)) => { + cx.span_err(span, "cannot concatenate float literals"); } - ast::LitKind::Bool(_) => { - cx.span_err(expr.span, "cannot concatenate boolean literals"); + Ok(ast::LitKind::Bool(_)) => { + cx.span_err(span, "cannot concatenate boolean literals"); } - ast::LitKind::Err => {} - ast::LitKind::Int(_, _) if !is_nested => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + Ok(ast::LitKind::Err) => {} + Ok(ast::LitKind::Int(_, _)) if !is_nested => { + let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals"); + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { err.span_suggestion( - expr.span, + span, "try wrapping the number in an array", format!("[{}]", snippet), Applicability::MachineApplicable, @@ -55,17 +59,20 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne } err.emit(); } - ast::LitKind::Int( + Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - ) => { + )) => { assert!(val > u8::MAX.into()); // must be an error - cx.span_err(expr.span, "numeric literal is out of bounds"); + cx.span_err(span, "numeric literal is out of bounds"); + } + Ok(ast::LitKind::Int(_, _)) => { + cx.span_err(span, "numeric literal is not a `u8`"); } - ast::LitKind::Int(_, _) => { - cx.span_err(expr.span, "numeric literal is not a `u8`"); + Ok(ast::LitKind::ByteStr(_) | ast::LitKind::Byte(_)) => unreachable!(), + Err(err) => { + report_lit_error(&cx.sess.parse_sess, err, token_lit, span); } - _ => unreachable!(), } } @@ -83,14 +90,14 @@ fn handle_array_element( *has_errors = true; None } - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Int( + 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 <= u8::MAX.into() => Some(val as u8), + )) if val <= u8::MAX.into() => Some(val as u8), - ast::LitKind::Byte(val) => Some(val), - ast::LitKind::ByteStr(_) => { + Ok(ast::LitKind::Byte(val)) => Some(val), + Ok(ast::LitKind::ByteStr(_)) => { if !*has_errors { cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") .note("byte strings are treated as arrays of bytes") @@ -102,12 +109,22 @@ fn handle_array_element( } _ => { if !*has_errors { - invalid_type_err(cx, expr, true); + invalid_type_err(cx, token_lit, expr.span, true); } *has_errors = true; None } }, + ast::ExprKind::IncludedBytes(..) => { + if !*has_errors { + cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") + .note("byte strings are treated as arrays of bytes") + .help("try flattening the array") + .emit(); + } + *has_errors = true; + None + } _ => { missing_literals.push(expr.span); None @@ -127,8 +144,8 @@ pub fn expand_concat_bytes( let mut missing_literals = vec![]; let mut has_errors = false; for e in es { - match e.kind { - ast::ExprKind::Array(ref exprs) => { + match &e.kind { + ast::ExprKind::Array(exprs) => { for expr in exprs { if let Some(elem) = handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) @@ -137,10 +154,10 @@ pub fn expand_concat_bytes( } } } - ast::ExprKind::Repeat(ref expr, ref count) => { - if let ast::ExprKind::Lit(ast::Lit { - kind: ast::LitKind::Int(count_val, _), .. - }) = count.value.kind + 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) { if let Some(elem) = handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) @@ -153,20 +170,23 @@ pub fn expand_concat_bytes( cx.span_err(count.value.span, "repeat count is not a positive number"); } } - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Byte(val) => { + &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Byte(val)) => { accumulator.push(val); } - ast::LitKind::ByteStr(ref bytes) => { + Ok(ast::LitKind::ByteStr(ref bytes)) => { accumulator.extend_from_slice(&bytes); } _ => { if !has_errors { - invalid_type_err(cx, &e, false); + invalid_type_err(cx, token_lit, e.span, false); } has_errors = true; } }, + ast::ExprKind::IncludedBytes(bytes) => { + accumulator.extend_from_slice(bytes); + } ast::ExprKind::Err => { has_errors = true; } diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index e0fb7affb..fa5a45730 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,7 +1,7 @@ use crate::cfg_eval::cfg_eval; use rustc_ast as ast; -use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast::{token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; @@ -10,7 +10,7 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -pub(crate) struct Expander; +pub(crate) struct Expander(pub bool); impl MultiItemModifier for Expander { fn expand( @@ -19,6 +19,7 @@ impl MultiItemModifier for Expander { span: Span, meta_item: &ast::MetaItem, item: Annotatable, + _: bool, ) -> ExpandResult, Annotatable> { let sess = ecx.sess; if report_bad_target(sess, &item, span) { @@ -32,46 +33,48 @@ impl MultiItemModifier for Expander { ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { let template = AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; - let attr = - attr::mk_attr_outer(&sess.parse_sess.attr_id_generator, meta_item.clone()); - validate_attr::check_builtin_attribute( + validate_attr::check_builtin_meta_item( &sess.parse_sess, - &attr, + &meta_item, + ast::AttrStyle::Outer, sym::derive, template, ); - let mut resolutions: Vec<_> = attr - .meta_item_list() - .unwrap_or_default() - .into_iter() - .filter_map(|nested_meta| match nested_meta { - NestedMetaItem::MetaItem(meta) => Some(meta), - NestedMetaItem::Literal(lit) => { - // Reject `#[derive("Debug")]`. - report_unexpected_literal(sess, &lit); - None - } - }) - .map(|meta| { - // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the paths. - report_path_args(sess, &meta); - meta.path - }) - .map(|path| (path, dummy_annotatable(), None)) - .collect(); + let mut resolutions = match &meta_item.kind { + MetaItemKind::List(list) => { + list.iter() + .filter_map(|nested_meta| match nested_meta { + NestedMetaItem::MetaItem(meta) => Some(meta), + NestedMetaItem::Lit(lit) => { + // Reject `#[derive("Debug")]`. + report_unexpected_meta_item_lit(sess, &lit); + None + } + }) + .map(|meta| { + // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the + // paths. + report_path_args(sess, &meta); + meta.path.clone() + }) + .map(|path| (path, dummy_annotatable(), None, self.0)) + .collect() + } + _ => vec![], + }; // Do not configure or clone items unless necessary. match &mut resolutions[..] { [] => {} - [(_, first_item, _), others @ ..] => { + [(_, first_item, ..), others @ ..] => { *first_item = cfg_eval( sess, features, item.clone(), ecx.current_expansion.lint_node_id, ); - for (_, item, _) in others { + for (_, item, _, _) in others { *item = first_item.clone(); } } @@ -126,7 +129,7 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { bad_target } -fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) { +fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { let help_msg = match lit.token_lit.kind { token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => { format!("try using `#[derive({})]`", lit.token_lit.symbol) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 7bd344467..240167146 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -1,4 +1,3 @@ -use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; @@ -12,16 +11,17 @@ pub fn expand_deriving_copy( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let trait_def = TraitDef { span, path: path_std!(marker::Copy), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: true, methods: Vec::new(), associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index fa8685f5f..d59b3b8c8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -14,6 +14,7 @@ pub fn expand_deriving_clone( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { // The simple form is `fn clone(&self) -> Self { *self }`, possibly with // some additional `AssertParamIsClone` assertions. @@ -31,10 +32,10 @@ pub fn expand_deriving_clone( let bounds; let substructure; let is_simple; - match *item { - Annotatable::Item(ref annitem) => match annitem.kind { - ItemKind::Struct(_, Generics { ref params, .. }) - | ItemKind::Enum(_, Generics { ref params, .. }) => { + match item { + Annotatable::Item(annitem) => match &annitem.kind { + ItemKind::Struct(_, Generics { params, .. }) + | ItemKind::Enum(_, Generics { params, .. }) => { let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let has_derive_copy = cx.resolver.has_derive_copy(container_id); if has_derive_copy @@ -67,14 +68,12 @@ pub fn expand_deriving_clone( _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), } - let inline = cx.meta_word(span, sym::inline); - let attrs = thin_vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let trait_def = TraitDef { span, path: path_std!(clone::Clone), skip_path_as_bound: false, additional_bounds: bounds, - generics: Bounds::empty(), supports_unions: true, methods: vec![MethodDef { name: sym::clone, @@ -87,6 +86,7 @@ pub fn expand_deriving_clone( combine_substructure: substructure, }], associated_types: Vec::new(), + is_const, }; trait_def.expand_ext(cx, mitem, item, push, is_simple) @@ -166,13 +166,13 @@ fn cs_clone( }; let vdata; - match *substr.fields { - Struct(vdata_, ref af) => { + match substr.fields { + Struct(vdata_, af) => { ctor_path = cx.path(trait_span, vec![substr.type_ident]); all_fields = af; - vdata = vdata_; + vdata = *vdata_; } - EnumMatching(.., variant, ref af) => { + EnumMatching(.., variant, af) => { ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]); all_fields = af; vdata = &variant.data; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index eab67b0d3..f861d47ed 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -5,7 +5,7 @@ use crate::deriving::path_std; use rustc_ast::{self as ast, MetaItem}; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::thin_vec; @@ -15,19 +15,19 @@ pub fn expand_deriving_eq( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let span = cx.with_def_site_ctxt(span); - let inline = cx.meta_word(span, sym::inline); - let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); - let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); - let no_coverage = cx.meta_word(span, sym::no_coverage); - let attrs = thin_vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)]; + let attrs = thin_vec![ + cx.attr_word(sym::inline, span), + cx.attr_nested_word(sym::doc, sym::hidden, span), + cx.attr_word(sym::no_coverage, span) + ]; let trait_def = TraitDef { span, path: path_std!(cmp::Eq), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: true, methods: vec![MethodDef { name: sym::assert_receiver_is_total_eq, @@ -42,6 +42,7 @@ pub fn expand_deriving_eq( })), }], associated_types: Vec::new(), + is_const, }; super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push); diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 7f117981a..96d18c7af 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -13,15 +13,14 @@ pub fn expand_deriving_ord( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { - let inline = cx.meta_word(span, sym::inline); - let attrs = thin_vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let trait_def = TraitDef { span, path: path_std!(cmp::Ord), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::cmp, @@ -34,6 +33,7 @@ pub fn expand_deriving_ord( combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) 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 236cbccaf..7f95551fc 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -14,6 +14,7 @@ pub fn expand_deriving_partial_eq( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let base = true; @@ -67,8 +68,7 @@ pub fn expand_deriving_partial_eq( // No need to generate `ne`, the default suffices, and not generating it is // faster. - let inline = cx.meta_word(span, sym::inline); - let attrs = thin_vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let methods = vec![MethodDef { name: sym::eq, generics: Bounds::empty(), @@ -85,10 +85,10 @@ pub fn expand_deriving_partial_eq( path: path_std!(cmp::PartialEq), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods, associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } 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 4173403a1..5c4e5b7f8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -13,13 +13,13 @@ pub fn expand_deriving_partial_ord( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let ordering_ty = Path(path_std!(cmp::Ordering)); let ret_ty = Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); - let inline = cx.meta_word(span, sym::inline); - let attrs = thin_vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let partial_cmp_def = MethodDef { name: sym::partial_cmp, @@ -39,10 +39,10 @@ pub fn expand_deriving_partial_ord( path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, additional_bounds: vec![], - generics: Bounds::empty(), supports_unions: false, methods: vec![partial_cmp_def], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 2cf614ed9..544d971b2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -13,6 +13,7 @@ pub fn expand_deriving_debug( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { // &mut ::std::fmt::Formatter let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut); @@ -22,7 +23,6 @@ pub fn expand_deriving_debug( path: path_std!(fmt::Debug), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::fmt, @@ -37,6 +37,7 @@ pub fn expand_deriving_debug( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index d669f6168..62af02c2b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -16,6 +16,7 @@ pub fn expand_deriving_rustc_decodable( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let krate = sym::rustc_serialize; let typaram = sym::__D; @@ -25,7 +26,6 @@ pub fn expand_deriving_rustc_decodable( path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::decode, @@ -55,6 +55,7 @@ pub fn expand_deriving_rustc_decodable( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) @@ -77,11 +78,11 @@ fn decodable_substructure( let blkarg = Ident::new(sym::_d, trait_span); let blkdecoder = cx.expr_ident(trait_span, blkarg); - let expr = match *substr.fields { - StaticStruct(_, ref summary) => { - let nfields = match *summary { - Unnamed(ref fields, _) => fields.len(), - Named(ref fields) => fields.len(), + let expr = match substr.fields { + StaticStruct(_, summary) => { + let nfields = match summary { + Unnamed(fields, _) => fields.len(), + Named(fields) => fields.len(), }; let fn_read_struct_field_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]); @@ -118,7 +119,7 @@ fn decodable_substructure( ], ) } - StaticEnum(_, ref fields) => { + StaticEnum(_, fields) => { let variant = Ident::new(sym::i, trait_span); let mut arms = Vec::with_capacity(fields.len() + 1); @@ -193,10 +194,10 @@ fn decode_static_fields( where F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P, { - match *fields { - Unnamed(ref fields, is_tuple) => { + match fields { + Unnamed(fields, is_tuple) => { let path_expr = cx.expr_path(outer_pat_path); - if !is_tuple { + if !*is_tuple { path_expr } else { let fields = fields @@ -208,7 +209,7 @@ where cx.expr_call(trait_span, path_expr, fields) } } - Named(ref fields) => { + Named(fields) => { // use the field's span to get nicer error messages. let fields = fields .iter() diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 17df9fb27..eb66c4a69 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -16,17 +16,16 @@ pub fn expand_deriving_default( mitem: &ast::MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); - let inline = cx.meta_word(span, sym::inline); - let attrs = thin_vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attr_word(sym::inline, span)]; let trait_def = TraitDef { span, path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: kw::Default, @@ -47,6 +46,7 @@ pub fn expand_deriving_default( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) } @@ -62,15 +62,12 @@ fn default_struct_substructure( let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); let expr = match summary { - Unnamed(ref fields, is_tuple) => { - if !is_tuple { - cx.expr_ident(trait_span, substr.type_ident) - } else { - let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); - cx.expr_call_ident(trait_span, substr.type_ident, exprs) - } + Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident), + Unnamed(fields, true) => { + let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); + cx.expr_call_ident(trait_span, substr.type_ident, exprs) } - Named(ref fields) => { + Named(fields) => { let default_fields = fields .iter() .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) @@ -145,7 +142,7 @@ fn extract_default_variant<'a>( let suggestion = default_variants .iter() .filter_map(|v| { - if v.ident == variant.ident { + if v.span == variant.span { None } else { Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new())) diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index f83f58b97..68bc0ff2e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -100,6 +100,7 @@ pub fn expand_deriving_rustc_encodable( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let krate = sym::rustc_serialize; let typaram = sym::__S; @@ -109,7 +110,6 @@ pub fn expand_deriving_rustc_encodable( path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::encode, @@ -139,6 +139,7 @@ pub fn expand_deriving_rustc_encodable( })), }], associated_types: Vec::new(), + is_const, }; trait_def.expand(cx, mitem, item, push) @@ -163,8 +164,8 @@ fn encodable_substructure( ], )); - match *substr.fields { - Struct(_, ref fields) => { + match substr.fields { + Struct(_, fields) => { let fn_emit_struct_field_path = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]); let mut stmts = Vec::new(); @@ -223,7 +224,7 @@ fn encodable_substructure( BlockOrExpr::new_expr(expr) } - EnumMatching(idx, _, variant, ref 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 @@ -273,7 +274,7 @@ fn encodable_substructure( vec![ blkencoder, name, - cx.expr_usize(trait_span, idx), + cx.expr_usize(trait_span, *idx), cx.expr_usize(trait_span, fields.len()), blk, ], diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 16ee3aa89..beac591bf 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -171,7 +171,7 @@ use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; use std::iter; use std::ops::Not; @@ -195,15 +195,14 @@ pub struct TraitDef<'a> { /// other than the current trait pub additional_bounds: Vec, - /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder` - pub generics: Bounds, - /// Can this trait be derived for unions? pub supports_unions: bool, pub methods: Vec>, pub associated_types: Vec<(Ident, Ty)>, + + pub is_const: bool, } pub struct MethodDef<'a> { @@ -301,12 +300,12 @@ struct TypeParameter { ty: P, } -// The code snippets built up for derived code are sometimes used as blocks -// (e.g. in a function body) and sometimes used as expressions (e.g. in a match -// arm). This structure avoids committing to either form until necessary, -// avoiding the insertion of any unnecessary blocks. -// -// The statements come before the expression. +/// The code snippets built up for derived code are sometimes used as blocks +/// (e.g. in a function body) and sometimes used as expressions (e.g. in a match +/// arm). This structure avoids committing to either form until necessary, +/// avoiding the insertion of any unnecessary blocks. +/// +/// The statements come before the expression. pub struct BlockOrExpr(Vec, Option>); impl BlockOrExpr { @@ -370,15 +369,14 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { - if let ast::TyKind::Path(_, ref path) = ty.kind { - if let Some(segment) = path.segments.first() { - if self.ty_param_names.contains(&segment.ident.name) { - self.type_params.push(TypeParameter { - bound_generic_params: self.bound_generic_params_stack.clone(), - ty: P(ty.clone()), - }); - } - } + if let ast::TyKind::Path(_, path) = &ty.kind + && let Some(segment) = path.segments.first() + && self.ty_param_names.contains(&segment.ident.name) + { + self.type_params.push(TypeParameter { + bound_generic_params: self.bound_generic_params_stack.clone(), + ty: P(ty.clone()), + }); } visit::walk_ty(self, ty) @@ -429,8 +427,8 @@ impl<'a> TraitDef<'a> { push: &mut dyn FnMut(Annotatable), from_scratch: bool, ) { - match *item { - Annotatable::Item(ref item) => { + match item { + Annotatable::Item(item) => { let is_packed = item.attrs.iter().any(|attr| { for r in attr::find_repr_attrs(&cx.sess, attr) { if let attr::ReprPacked(_) = r { @@ -439,38 +437,37 @@ impl<'a> TraitDef<'a> { } false }); - let has_no_type_params = match item.kind { - ast::ItemKind::Struct(_, ref generics) - | ast::ItemKind::Enum(_, ref generics) - | ast::ItemKind::Union(_, ref generics) => !generics + let has_no_type_params = match &item.kind { + ast::ItemKind::Struct(_, generics) + | ast::ItemKind::Enum(_, generics) + | ast::ItemKind::Union(_, generics) => !generics .params .iter() .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), _ => unreachable!(), }; let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); + let copy_fields = + is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id); - let newitem = match item.kind { - ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def( + let newitem = match &item.kind { + ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( cx, &struct_def, item.ident, generics, from_scratch, - is_packed, - always_copy, + copy_fields, ), - ast::ItemKind::Enum(ref enum_def, ref generics) => { - // We ignore `is_packed`/`always_copy` here, because - // `repr(packed)` enums cause an error later on. + ast::ItemKind::Enum(enum_def, generics) => { + // We ignore `is_packed` here, because `repr(packed)` + // enums cause an error later on. // // This can only cause further compilation errors - // downstream in blatantly illegal code, so it - // is fine. + // downstream in blatantly illegal code, so it is fine. self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch) } - ast::ItemKind::Union(ref struct_def, ref generics) => { + ast::ItemKind::Union(struct_def, generics) => { if self.supports_unions { self.expand_struct_def( cx, @@ -478,8 +475,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - is_packed, - always_copy, + copy_fields, ) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -581,19 +577,21 @@ impl<'a> TraitDef<'a> { }) }); - let Generics { mut params, mut where_clause, .. } = - self.generics.to_generics(cx, self.span, type_ident, generics); + let mut where_clause = ast::WhereClause::default(); where_clause.span = generics.where_clause.span; let ctxt = self.span.ctxt(); let span = generics.span.with_ctxt(ctxt); // Create the generic parameters - params.extend(generics.params.iter().map(|param| match ¶m.kind { - GenericParamKind::Lifetime { .. } => param.clone(), - GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = + let params: Vec<_> = generics + .params + .iter() + .map(|param| match ¶m.kind { + GenericParamKind::Lifetime { .. } => param.clone(), + GenericParamKind::Type { .. } => { + // I don't think this can be moved out of the loop, since + // a GenericBound requires an ast id + let bounds: Vec<_> = // extra restrictions on the generics parameters to the // type being derived upon self.additional_bounds.iter().map(|p| { @@ -606,21 +604,22 @@ impl<'a> TraitDef<'a> { param.bounds.iter().cloned() ).collect(); - cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) - } - GenericParamKind::Const { ty, kw_span, .. } => { - let const_nodefault_kind = GenericParamKind::Const { - ty: ty.clone(), - kw_span: kw_span.with_ctxt(ctxt), - - // We can't have default values inside impl block - default: None, - }; - let mut param_clone = param.clone(); - param_clone.kind = const_nodefault_kind; - param_clone - } - })); + cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) + } + GenericParamKind::Const { ty, kw_span, .. } => { + let const_nodefault_kind = GenericParamKind::Const { + ty: ty.clone(), + kw_span: kw_span.with_ctxt(ctxt), + + // We can't have default values inside impl block + default: None, + }; + let mut param_clone = param.clone(); + param_clone.kind = const_nodefault_kind; + param_clone + } + }) + .collect(); // and similarly for where clauses where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { @@ -663,12 +662,11 @@ impl<'a> TraitDef<'a> { for field_ty_param in field_ty_params { // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].ident.name) - { - continue; - }; + if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind + && let [sole_segment] = &*p.segments + && ty_param_names.contains(&sole_segment.ident.name) + { + continue; } let mut bounds: Vec<_> = self .additional_bounds @@ -718,7 +716,7 @@ impl<'a> TraitDef<'a> { let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); - let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived)); + let attr = cx.attr_word(sym::automatically_derived, self.span); let attrs = thin_vec![attr]; let opt_trait_ref = Some(trait_ref); @@ -730,7 +728,7 @@ impl<'a> TraitDef<'a> { unsafety: ast::Unsafe::No, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, - constness: ast::Const::No, + constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, generics: trait_generics, of_trait: opt_trait_ref, self_ty: self_type, @@ -746,8 +744,7 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, from_scratch: bool, - is_packed: bool, - always_copy: bool, + copy_fields: bool, ) -> P { let field_tys: Vec> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); @@ -775,8 +772,7 @@ impl<'a> TraitDef<'a> { type_ident, &selflike_args, &nonselflike_args, - is_packed, - always_copy, + copy_fields, ) }; @@ -1014,19 +1010,9 @@ impl<'a> MethodDef<'a> { /// } /// } /// ``` - /// If the struct doesn't impl `Copy`, we use let-destructuring with `ref`: - /// ``` - /// # struct A { x: u8, y: u8 } - /// impl PartialEq for A { - /// fn eq(&self, other: &A) -> bool { - /// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self; - /// let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other; - /// *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1 - /// } - /// } - /// ``` - /// This latter case only works if the fields match the alignment required - /// by the `packed(N)` attribute. (We'll get errors later on if not.) + /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This + /// only works if the fields match the alignment required by the + /// `packed(N)` attribute. (We'll get errors later on if not.) fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, @@ -1035,54 +1021,19 @@ impl<'a> MethodDef<'a> { type_ident: Ident, selflike_args: &[P], nonselflike_args: &[P], - is_packed: bool, - always_copy: bool, + copy_fields: bool, ) -> BlockOrExpr { - let span = trait_.span; assert!(selflike_args.len() == 1 || selflike_args.len() == 2); - let mk_body = |cx, selflike_fields| { - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &Struct(struct_def, selflike_fields), - ) - }; - - if !is_packed { - let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, false); - mk_body(cx, selflike_fields) - } else if always_copy { - let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, true); - mk_body(cx, selflike_fields) - } else { - // Neither packed nor copy. Need to use ref patterns. - let prefixes: Vec<_> = - (0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect(); - let addr_of = always_copy; - let selflike_fields = - trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of); - let mut body = mk_body(cx, selflike_fields); - - let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); - let by_ref = ByRef::from(is_packed && !always_copy); - let patterns = - trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref); - - // Do the let-destructuring. - let mut stmts: Vec<_> = iter::zip(selflike_args, patterns) - .map(|(selflike_arg_expr, pat)| { - let selflike_arg_expr = cx.expr_deref(span, selflike_arg_expr.clone()); - cx.stmt_let_pat(span, pat, selflike_arg_expr) - }) - .collect(); - stmts.extend(std::mem::take(&mut body.0)); - BlockOrExpr(stmts, body.1) - } + let selflike_fields = + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields); + self.call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &Struct(struct_def, selflike_fields), + ) } fn expand_static_struct_method_body( @@ -1252,9 +1203,7 @@ impl<'a> MethodDef<'a> { // A single arm has form (&VariantK, &VariantK, ...) => BodyK // (see "Final wrinkle" note below for why.) - let addr_of = false; // because enums can't be repr(packed) - let fields = - trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of); + let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes); let sp = variant.span.with_ctxt(trait_.span.ctxt()); let variant_path = cx.path(sp, vec![type_ident, variant.ident]); @@ -1517,15 +1466,13 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt<'_>, struct_def: &'a VariantData, prefixes: &[String], - addr_of: bool, ) -> Vec { self.create_fields(struct_def, |i, _struct_field, sp| { prefixes .iter() .map(|prefix| { let ident = self.mk_pattern_ident(prefix, i); - let expr = cx.expr_path(cx.path_ident(sp, ident)); - if addr_of { cx.expr_addr_of(sp, expr) } else { expr } + cx.expr_path(cx.path_ident(sp, ident)) }) .collect() }) @@ -1536,7 +1483,7 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt<'_>, selflike_args: &[P], struct_def: &'a VariantData, - copy: bool, + copy_fields: bool, ) -> Vec { self.create_fields(struct_def, |i, struct_field, sp| { selflike_args @@ -1555,7 +1502,7 @@ impl<'a> TraitDef<'a> { }), ), ); - if copy { + if copy_fields { field_expr = cx.expr_block( cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), ); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 36e2e2930..eaa488190 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -115,7 +115,7 @@ impl Ty { self_ty: Ident, generics: &Generics, ) -> ast::Path { - match *self { + match self { Self_ => { let params: Vec<_> = generics .params @@ -135,7 +135,7 @@ impl Ty { cx.path_all(span, false, vec![self_ty], params) } - Path(ref p) => p.to_path(cx, span, self_ty, generics), + Path(p) => p.to_path(cx, span, self_ty, generics), Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"), Unit => cx.span_bug(span, "unit in a path in generic `derive`"), } @@ -180,10 +180,7 @@ impl Bounds { let params = self .bounds .iter() - .map(|t| { - let (name, ref bounds) = *t; - mk_ty_param(cx, span, name, &bounds, self_ty, self_generics) - }) + .map(|&(name, ref bounds)| mk_ty_param(cx, span, name, &bounds, self_ty, self_generics)) .collect(); Generics { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6e9d5f08b..c136bb714 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -13,6 +13,7 @@ pub fn expand_deriving_hash( mitem: &MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), + is_const: bool, ) { let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std); @@ -24,7 +25,6 @@ pub fn expand_deriving_hash( path, skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::hash, @@ -39,6 +39,7 @@ pub fn expand_deriving_hash( })), }], associated_types: Vec::new(), + is_const, }; hash_trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index ee346047a..de657e4e6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -38,9 +38,10 @@ pub mod partial_ord; pub mod generic; -pub(crate) struct BuiltinDerive( - pub(crate) fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)), -); +pub(crate) type BuiltinDeriveFn = + fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); + +pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn); impl MultiItemModifier for BuiltinDerive { fn expand( @@ -49,6 +50,7 @@ impl MultiItemModifier for BuiltinDerive { span: Span, meta_item: &MetaItem, item: Annotatable, + is_derive_const: bool, ) -> ExpandResult, Annotatable> { // FIXME: Built-in derives often forget to give spans contexts, // so we are doing it here in a centralized way. @@ -57,21 +59,28 @@ impl MultiItemModifier for BuiltinDerive { match item { Annotatable::Stmt(stmt) => { if let ast::StmtKind::Item(item) = stmt.into_inner().kind { - (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| { - // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' - // to the function - items.push(Annotatable::Stmt(P(ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(a.expect_item()), - span, - }))); - }); + (self.0)( + ecx, + span, + meta_item, + &Annotatable::Item(item), + &mut |a| { + // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' + // to the function + items.push(Annotatable::Stmt(P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(a.expect_item()), + span, + }))); + }, + is_derive_const, + ); } else { unreachable!("should have already errored on non-item statement") } } _ => { - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); + (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const); } } ExpandResult::Ready(items) @@ -116,12 +125,12 @@ fn inject_impl_of_structural_trait( structural_path: generic::ty::Path, push: &mut dyn FnMut(Annotatable), ) { - let Annotatable::Item(ref item) = *item else { + let Annotatable::Item(item) = item else { unreachable!(); }; - let generics = match item.kind { - ItemKind::Struct(_, ref generics) | ItemKind::Enum(_, ref generics) => generics, + let generics = match &item.kind { + ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics, // Do not inject `impl Structural for Union`. (`PartialEq` does not // support unions, so we will see error downstream.) ItemKind::Union(..) => return, @@ -179,7 +188,7 @@ fn inject_impl_of_structural_trait( .cloned(), ); // Mark as `automatically_derived` to avoid some silly lints. - attrs.push(cx.attribute(cx.meta_word(span, sym::automatically_derived))); + attrs.push(cx.attr_word(sym::automatically_derived, span)); let newitem = cx.item( span, diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index 3f1a8b3bc..b2a21611d 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -6,15 +6,15 @@ use rustc_span::edition::Edition; use rustc_span::symbol::sym; use rustc_span::Span; -// This expands to either -// - `$crate::panic::panic_2015!(...)` or -// - `$crate::panic::panic_2021!(...)` -// depending on the edition. -// -// This is used for both std::panic!() and core::panic!(). -// -// `$crate` will refer to either the `std` or `core` crate depending on which -// one we're expanding from. +/// This expands to either +/// - `$crate::panic::panic_2015!(...)` or +/// - `$crate::panic::panic_2021!(...)` +/// depending on the edition. +/// +/// This is used for both std::panic!() and core::panic!(). +/// +/// `$crate` will refer to either the `std` or `core` crate depending on which +/// one we're expanding from. pub fn expand_panic<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -24,10 +24,10 @@ pub fn expand_panic<'cx>( expand(mac, cx, sp, tts) } -// This expands to either -// - `$crate::panic::unreachable_2015!(...)` or -// - `$crate::panic::unreachable_2021!(...)` -// depending on the edition. +/// This expands to either +/// - `$crate::panic::unreachable_2015!(...)` or +/// - `$crate::panic::unreachable_2021!(...)` +/// depending on the edition. pub fn expand_unreachable<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -58,11 +58,11 @@ fn expand<'cx>( .collect(), tokens: None, }, - args: P(MacArgs::Delimited( - DelimSpan::from_single(sp), - MacDelimiter::Parenthesis, - tts, - )), + args: P(DelimArgs { + dspan: DelimSpan::from_single(sp), + delim: MacDelimiter::Parenthesis, + tokens: tts, + }), prior_type_ascription: None, })), ), diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index b8828fa67..0b4e545f7 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -53,7 +53,7 @@ pub fn expand_env<'cx>( tts: TokenStream, ) -> Box { let mut exprs = match get_exprs_from_tts(cx, sp, tts) { - Some(ref exprs) if exprs.is_empty() => { + Some(exprs) if exprs.is_empty() => { cx.span_err(sp, "env! takes 1 or 2 arguments"); return DummyResult::any(sp); } diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index ecd16736e..6f7fc3a95 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -13,23 +13,23 @@ pub(crate) mod printf { impl<'a> Substitution<'a> { pub fn as_str(&self) -> &str { - match *self { - Substitution::Format(ref fmt) => fmt.span, + match self { + Substitution::Format(fmt) => fmt.span, Substitution::Escape(_) => "%%", } } pub fn position(&self) -> Option { - match *self { - Substitution::Format(ref fmt) => Some(fmt.position), - Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)), + match self { + Substitution::Format(fmt) => Some(fmt.position), + &Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)), } } pub fn set_position(&mut self, start: usize, end: usize) { match self { - Substitution::Format(ref mut fmt) => fmt.position = InnerSpan::new(start, end), - Substitution::Escape(ref mut pos) => *pos = (start, end), + Substitution::Format(fmt) => fmt.position = InnerSpan::new(start, end), + Substitution::Escape(pos) => *pos = (start, end), } } @@ -38,8 +38,8 @@ pub(crate) mod printf { /// This ignores cases where the substitution does not have an exact equivalent, or where /// the substitution would be unnecessary. pub fn translate(&self) -> Result> { - match *self { - Substitution::Format(ref fmt) => fmt.translate(), + match self { + Substitution::Format(fmt) => fmt.translate(), Substitution::Escape(_) => Err(None), } } @@ -635,23 +635,17 @@ pub mod shell { } pub fn position(&self) -> Option { - match self { - Substitution::Ordinal(_, pos) - | Substitution::Name(_, pos) - | Substitution::Escape(pos) => Some(InnerSpan::new(pos.0, pos.1)), - } + let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; + Some(InnerSpan::new(pos.0, pos.1)) } pub fn set_position(&mut self, start: usize, end: usize) { - match self { - Substitution::Ordinal(_, ref mut pos) - | Substitution::Name(_, ref mut pos) - | Substitution::Escape(ref mut pos) => *pos = (start, end), - } + let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; + *pos = (start, end); } pub fn translate(&self) -> Result> { - match *self { + match self { Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)), Substitution::Name(n, _) => Ok(format!("{{{}}}", n)), Substitution::Escape(_) => Err(None), diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs index fc7442470..df773910d 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -100,7 +100,7 @@ fn test_iter() { let s = "The %d'th word %% is: `%.*s` %!\n"; let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); assert_eq!( - subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), + subs.iter().map(Option::as_deref).collect::>(), vec![Some("{}"), None, Some("{:.*}"), None] ); } diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs index f5f82732f..93a7afcd6 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs @@ -39,7 +39,7 @@ fn test_iter() { let s = "The $0'th word $$ is: `$WORD` $!\n"; let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); assert_eq!( - subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), + subs.iter().map(Option::as_deref).collect::>(), vec![Some("{0}"), None, Some("{WORD}")] ); } diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 45b9b8ab6..41531580c 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -20,27 +20,23 @@ pub fn expand( check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator); let orig_item = item.clone(); - let not_static = || { - ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); - vec![orig_item.clone()] - }; // Allow using `#[global_allocator]` on an item statement // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, ty_span) = match &item { - Annotatable::Item(item) => match item.kind { - ItemKind::Static(ref ty, ..) => (item, false, ecx.with_def_site_ctxt(ty.span)), - _ => return not_static(), - }, - Annotatable::Stmt(stmt) => match &stmt.kind { - StmtKind::Item(item_) => match item_.kind { - ItemKind::Static(ref ty, ..) => (item_, true, ecx.with_def_site_ctxt(ty.span)), - _ => return not_static(), - }, - _ => return not_static(), - }, - _ => return not_static(), - }; + let (item, is_stmt, ty_span) = + if let Annotatable::Item(item) = &item + && let ItemKind::Static(ty, ..) = &item.kind + { + (item, false, ecx.with_def_site_ctxt(ty.span)) + } else if let Annotatable::Stmt(stmt) = &item + && let StmtKind::Item(item) = &stmt.kind + && let ItemKind::Static(ty, ..) = &item.kind + { + (item, true, ecx.with_def_site_ctxt(ty.span)) + } else { + ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); + return vec![orig_item.clone()] + }; // Generate a bunch of new items using the AllocFnFactory let span = ecx.with_def_site_ctxt(item.span); @@ -115,9 +111,7 @@ impl AllocFnFactory<'_, '_> { } fn attrs(&self) -> AttrVec { - let special = sym::rustc_std_internal_symbol; - let special = self.cx.meta_word(self.span, special); - thin_vec![self.cx.attribute(special)] + thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] } fn arg_ty( diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c7ea7de8f..75cfac723 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -25,6 +25,7 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::symbol::sym; +mod alloc_error_handler; mod assert; mod cfg; mod cfg_accessible; @@ -44,6 +45,7 @@ mod log_syntax; mod source_util; mod test; mod trace_macros; +mod type_ascribe; mod util; pub mod asm; @@ -91,13 +93,16 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { unreachable: edition_panic::expand_unreachable, stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, + type_ascribe: type_ascribe::expand_type_ascribe, } register_attr! { + alloc_error_handler: alloc_error_handler::expand, bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, - derive: derive::Expander, + derive: derive::Expander(false), + derive_const: derive::Expander(true), global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index ebe1c3663..ece660cf6 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,6 +1,3 @@ -use std::mem; - -use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, NodeId}; @@ -13,6 +10,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use smallvec::smallvec; +use std::mem; struct ProcMacroDerive { id: NodeId, @@ -365,14 +363,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { cx.expr_array_ref(span, decls), ) .map(|mut i| { - let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); - i.attrs.push(cx.attribute(attr)); - - let deprecated_attr = attr::mk_nested_word_item(Ident::new(sym::deprecated, span)); - let allow_deprecated_attr = - attr::mk_list_item(Ident::new(sym::allow, span), vec![deprecated_attr]); - i.attrs.push(cx.attribute(allow_deprecated_attr)); - + i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span)); + i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span)); i }); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index d78bbc3c9..0b17e92ef 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -164,7 +164,7 @@ pub fn expand_include<'cx>( Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id }) } -// include_str! : read the given file, insert it as a literal string expr +/// `include_str!`: read the given file, insert it as a literal string expr pub fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, @@ -216,7 +216,10 @@ pub fn expand_include_bytes( } }; match cx.source_map().load_binary_file(&file) { - Ok(bytes) => base::MacEager::expr(cx.expr_byte_str(sp, bytes)), + Ok(bytes) => { + let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes.into())); + base::MacEager::expr(expr) + } Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); DummyResult::any(sp) diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 49ef538f0..f73f20c84 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -52,7 +52,7 @@ pub fn inject( cx.item( span, ident, - thin_vec![cx.attribute(cx.meta_word(span, sym::macro_use))], + thin_vec![cx.attr_word(sym::macro_use, span)], ast::ItemKind::ExternCrate(None), ), ); @@ -79,7 +79,7 @@ pub fn inject( let use_item = cx.item( span, Ident::empty(), - thin_vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], + thin_vec![cx.attr_word(sym::prelude_import, span)], ast::ItemKind::Use(ast::UseTree { prefix: cx.path(span, import_path), kind: ast::UseTreeKind::Glob, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index fee5d04cd..f5f02fc77 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -2,7 +2,6 @@ /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast as ast; -use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; @@ -13,13 +12,13 @@ use rustc_span::Span; use std::iter; use thin_vec::thin_vec; -// #[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 -// Otherwise, we'll omit the item. This behavior means that any item annotated -// with #[test_case] is never addressable. -// -// We mark item with an inert attribute "rustc_test_marker" which the test generation -// logic will pick up on. +/// #[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 +/// Otherwise, we'll omit the item. This behavior means that any item annotated +/// with #[test_case] is never addressable. +/// +/// We mark item with an inert attribute "rustc_test_marker" which the test generation +/// logic will pick up on. pub fn expand_test_case( ecx: &mut ExtCtxt<'_>, attr_sp: Span, @@ -47,11 +46,7 @@ pub fn expand_test_case( tokens: None, }; item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); - item.attrs.push(ecx.attribute(attr::mk_name_value_item_str( - Ident::new(sym::rustc_test_marker, sp), - test_path_symbol, - sp, - ))); + item.attrs.push(ecx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, sp)); item }); @@ -112,7 +107,7 @@ pub fn expand_test_or_bench( }; // Note: non-associated fn items are already handled by `expand_test_or_bench` - if !matches!(item.kind, ast::ItemKind::Fn(_)) { + let ast::ItemKind::Fn(fn_) = &item.kind else { let diag = &cx.sess.parse_sess.span_diagnostic; let msg = "the `#[test]` attribute may only be used on a non-associated function"; let mut err = match item.kind { @@ -130,7 +125,7 @@ pub fn expand_test_or_bench( .emit(); return vec![Annotatable::Item(item)]; - } + }; // has_*_signature will report any errors in the type so compilation // will fail. We shouldn't try to expand in this case because the errors @@ -141,12 +136,14 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let (sp, attr_sp) = (cx.with_def_site_ctxt(item.span), cx.with_def_site_ctxt(attr_sp)); + let sp = cx.with_def_site_ctxt(item.span); + let ret_ty_sp = cx.with_def_site_ctxt(fn_.sig.decl.output.span()); + let attr_sp = cx.with_def_site_ctxt(attr_sp); let test_id = Ident::new(sym::test, attr_sp); // creates test::$name - let test_path = |name| cx.path(sp, vec![test_id, Ident::from_str_and_span(name, sp)]); + let test_path = |name| cx.path(ret_ty_sp, vec![test_id, Ident::from_str_and_span(name, sp)]); // creates test::ShouldPanic::$name let should_panic_path = |name| { @@ -192,7 +189,7 @@ pub fn expand_test_or_bench( vec![ // super::$test_fn(b) cx.expr_call( - sp, + ret_ty_sp, cx.expr_path(cx.path(sp, vec![item.ident])), vec![cx.expr_ident(sp, b)], ), @@ -216,7 +213,11 @@ pub fn expand_test_or_bench( cx.expr_path(test_path("assert_test_result")), vec![ // $test_fn() - cx.expr_call(sp, cx.expr_path(cx.path(sp, vec![item.ident])), vec![]), // ) + cx.expr_call( + ret_ty_sp, + cx.expr_path(cx.path(sp, vec![item.ident])), + vec![], + ), // ) ], ), // } ), // ) @@ -235,16 +236,9 @@ pub fn expand_test_or_bench( Ident::new(item.ident.name, sp), thin_vec![ // #[cfg(test)] - cx.attribute(attr::mk_list_item( - Ident::new(sym::cfg, attr_sp), - vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))], - )), + cx.attr_nested_word(sym::cfg, sym::test, attr_sp), // #[rustc_test_marker = "test_case_sort_key"] - cx.attribute(attr::mk_name_value_item_str( - Ident::new(sym::rustc_test_marker, attr_sp), - test_path_symbol, - attr_sp, - )), + cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), ] .into(), // const $ident: test::TestDescAndFn = @@ -472,61 +466,67 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic); let sd = &cx.sess.parse_sess.span_diagnostic; - if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind { - if let ast::Unsafe::Yes(span) = sig.header.unsafety { - sd.struct_span_err(i.span, "unsafe functions cannot be used for tests") - .span_label(span, "`unsafe` because of this") - .emit(); - return false; - } - if let ast::Async::Yes { span, .. } = sig.header.asyncness { - sd.struct_span_err(i.span, "async functions cannot be used for tests") - .span_label(span, "`async` because of this") - .emit(); - return false; - } - - // If the termination trait is active, the compiler will check that the output - // type implements the `Termination` trait as `libtest` enforces that. - let has_output = match sig.decl.output { - ast::FnRetTy::Default(..) => false, - ast::FnRetTy::Ty(ref t) if t.kind.is_unit() => false, - _ => true, - }; - - if !sig.decl.inputs.is_empty() { - sd.span_err(i.span, "functions used as tests can not have any arguments"); - return false; - } + match &i.kind { + ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => { + if let ast::Unsafe::Yes(span) = sig.header.unsafety { + sd.struct_span_err(i.span, "unsafe functions cannot be used for tests") + .span_label(span, "`unsafe` because of this") + .emit(); + return false; + } + if let ast::Async::Yes { span, .. } = sig.header.asyncness { + sd.struct_span_err(i.span, "async functions cannot be used for tests") + .span_label(span, "`async` because of this") + .emit(); + return false; + } - match (has_output, has_should_panic_attr) { - (true, true) => { - sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); - false + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let has_output = match &sig.decl.output { + ast::FnRetTy::Default(..) => false, + ast::FnRetTy::Ty(t) if t.kind.is_unit() => false, + _ => true, + }; + + if !sig.decl.inputs.is_empty() { + sd.span_err(i.span, "functions used as tests can not have any arguments"); + return false; } - (true, false) => { - if !generics.params.is_empty() { - sd.span_err(i.span, "functions used as tests must have signature fn() -> ()"); + + match (has_output, has_should_panic_attr) { + (true, true) => { + sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); false - } else { - true } + (true, false) => { + if !generics.params.is_empty() { + sd.span_err( + i.span, + "functions used as tests must have signature fn() -> ()", + ); + false + } else { + true + } + } + (false, _) => true, } - (false, _) => true, } - } else { - // should be unreachable because `is_test_fn_item` should catch all non-fn items - false + _ => { + // should be unreachable because `is_test_fn_item` should catch all non-fn items + debug_assert!(false); + false + } } } fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind { + let has_sig = match &i.kind { // N.B., inadequate check, but we're running // well before resolve, can't get too deep. - sig.decl.inputs.len() == 1 - } else { - false + ast::ItemKind::Fn(box ast::Fn { sig, .. }) => sig.decl.inputs.len() == 1, + _ => false, }; if !has_sig { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index b8b8351a3..ad8871080 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -34,8 +34,8 @@ struct TestCtxt<'a> { test_runner: Option, } -// Traverse the crate, collecting all the test functions, eliding any -// existing main functions, and synthesizing a main test harness +/// Traverse the crate, collecting all the test functions, eliding any +/// existing main functions, and synthesizing a main test harness pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); @@ -131,8 +131,9 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ref spans)) = item.kind { - let ast::ModSpans { inner_span: span, inject_use_span: _ } = *spans; + if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) = + item.kind + { let prev_tests = mem::take(&mut self.tests); noop_visit_item_kind(&mut item.kind, self); self.add_test_cases(item.id, span, prev_tests); @@ -185,13 +186,12 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { let item = match entry_point_type(self.sess, &item, self.depth) { EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { - let allow_ident = Ident::new(sym::allow, self.def_site); - let dc_nested = - attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site)); - let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); - let allow_dead_code = attr::mk_attr_outer( + let allow_dead_code = attr::mk_attr_nested_word( &self.sess.parse_sess.attr_id_generator, - allow_dead_code_item, + ast::AttrStyle::Outer, + sym::allow, + sym::dead_code, + self.def_site, ); let attrs = attrs .into_iter() @@ -309,8 +309,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { ); // #[rustc_main] - let main_meta = ecx.meta_word(sp, sym::rustc_main); - let main_attr = ecx.attribute(main_meta); + let main_attr = ecx.attr_word(sym::rustc_main, sp); // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs new file mode 100644 index 000000000..72b85af14 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/type_ascribe.rs @@ -0,0 +1,35 @@ +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 { + let (expr, ty) = match parse_ascribe(cx, tts) { + Ok(parsed) => parsed, + Err(mut 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, P)> { + 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 527fe50ef..83812631c 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,4 +1,4 @@ -use rustc_ast::{Attribute, MetaItem}; +use rustc_ast::{AttrStyle, Attribute, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_feature::AttributeTemplate; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; @@ -8,8 +8,13 @@ use rustc_span::Symbol; pub 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() }; - let attr = ecx.attribute(meta_item.clone()); - validate_attr::check_builtin_attribute(&ecx.sess.parse_sess, &attr, name, template); + validate_attr::check_builtin_meta_item( + &ecx.sess.parse_sess, + &meta_item, + AttrStyle::Outer, + name, + template, + ); } /// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when -- cgit v1.2.3