diff options
Diffstat (limited to 'compiler/rustc_builtin_macros')
25 files changed, 465 insertions, 716 deletions
| diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index d2b4e1ca824..78bf2195975 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -67,10 +67,11 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: 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, thin_vec![ - cx.expr_ident(span, size), - cx.expr_ident(span, align) - ]); + let layout = cx.expr_call( + span, + layout_new, + thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)], + ); let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]); @@ -85,6 +86,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span defaultness: ast::Defaultness::Final, sig, generics: Generics::default(), + contract: None, body, })); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 5062cf55bb9..eb5b345e49e 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -651,7 +651,7 @@ fn expand_preparsed_asm( .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))); for piece in unverified_pieces { match piece { - parse::Piece::String(s) => { + parse::Piece::Lit(s) => { template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into())) } parse::Piece::NextArgument(arg) => { diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 8960cf6ab59..24c54edd705 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -406,19 +406,21 @@ mod llvm_enzyme { let unsf_expr = ecx.expr_block(P(unsf_block)); let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); let primal_call = gen_primal_call(ecx, span, primal, idents); - let black_box_primal_call = - ecx.expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![ - primal_call.clone() - ]); + let black_box_primal_call = ecx.expr_call( + new_decl_span, + blackbox_call_expr.clone(), + thin_vec![primal_call.clone()], + ); let tup_args = new_names .iter() .map(|arg| ecx.expr_path(ecx.path_ident(span, Ident::from_str(arg)))) .collect(); - let black_box_remaining_args = - ecx.expr_call(sig_span, blackbox_call_expr.clone(), thin_vec![ - ecx.expr_tuple(sig_span, tup_args) - ]); + let black_box_remaining_args = ecx.expr_call( + sig_span, + blackbox_call_expr.clone(), + thin_vec![ecx.expr_tuple(sig_span, tup_args)], + ); let mut body = ecx.block(span, ThinVec::new()); body.stmts.push(ecx.stmt_semi(unsf_expr)); @@ -532,8 +534,11 @@ mod llvm_enzyme { return body; } [arg] => { - ret = ecx - .expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![arg.clone()]); + ret = ecx.expr_call( + new_decl_span, + blackbox_call_expr.clone(), + thin_vec![arg.clone()], + ); } args => { let ret_tuple: P<ast::Expr> = ecx.expr_tuple(span, args.into()); diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs new file mode 100644 index 00000000000..6a24af361fe --- /dev/null +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -0,0 +1,171 @@ +use rustc_ast::token; +use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; +use rustc_errors::ErrorGuaranteed; +use rustc_expand::base::{AttrProcMacro, ExtCtxt}; +use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, kw}; + +pub(crate) struct ExpandRequires; + +pub(crate) struct ExpandEnsures; + +impl AttrProcMacro for ExpandRequires { + fn expand<'cx>( + &self, + ecx: &'cx mut ExtCtxt<'_>, + span: Span, + annotation: TokenStream, + annotated: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + expand_requires_tts(ecx, span, annotation, annotated) + } +} + +impl AttrProcMacro for ExpandEnsures { + fn expand<'cx>( + &self, + ecx: &'cx mut ExtCtxt<'_>, + span: Span, + annotation: TokenStream, + annotated: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + expand_ensures_tts(ecx, span, annotation, annotated) + } +} + +/// Expand the function signature to include the contract clause. +/// +/// The contracts clause will be injected before the function body and the optional where clause. +/// For that, we search for the body / where token, and invoke the `inject` callback to generate the +/// contract clause in the right place. +/// +// FIXME: this kind of manual token tree munging does not have significant precedent among +// rustc builtin macros, probably because most builtin macros use direct AST manipulation to +// accomplish similar goals. But since our attributes need to take arbitrary expressions, and +// our attribute infrastructure does not yet support mixing a token-tree annotation with an AST +// annotated, we end up doing token tree manipulation. +fn expand_contract_clause( + ecx: &mut ExtCtxt<'_>, + attr_span: Span, + annotated: TokenStream, + inject: impl FnOnce(&mut TokenStream) -> Result<(), ErrorGuaranteed>, +) -> Result<TokenStream, ErrorGuaranteed> { + let mut new_tts = TokenStream::default(); + let mut cursor = annotated.iter(); + + let is_kw = |tt: &TokenTree, sym: Symbol| { + if let TokenTree::Token(token, _) = tt { token.is_ident_named(sym) } else { false } + }; + + // Find the `fn` keyword to check if this is a function. + if cursor + .find(|tt| { + new_tts.push_tree((*tt).clone()); + is_kw(tt, kw::Fn) + }) + .is_none() + { + return Err(ecx + .sess + .dcx() + .span_err(attr_span, "contract annotations can only be used on functions")); + } + + // Found the `fn` keyword, now find either the `where` token or the function body. + let next_tt = loop { + let Some(tt) = cursor.next() else { + return Err(ecx.sess.dcx().span_err( + attr_span, + "contract annotations is only supported in functions with bodies", + )); + }; + // If `tt` is the last element. Check if it is the function body. + if cursor.peek().is_none() { + if let TokenTree::Delimited(_, _, token::Delimiter::Brace, _) = tt { + break tt; + } else { + return Err(ecx.sess.dcx().span_err( + attr_span, + "contract annotations is only supported in functions with bodies", + )); + } + } + + if is_kw(tt, kw::Where) { + break tt; + } + new_tts.push_tree(tt.clone()); + }; + + // At this point, we've transcribed everything from the `fn` through the formal parameter list + // and return type declaration, (if any), but `tt` itself has *not* been transcribed. + // + // Now inject the AST contract form. + // + inject(&mut new_tts)?; + + // Above we injected the internal AST requires/ensures construct. Now copy over all the other + // token trees. + new_tts.push_tree(next_tt.clone()); + while let Some(tt) = cursor.next() { + new_tts.push_tree(tt.clone()); + if cursor.peek().is_none() + && !matches!(tt, TokenTree::Delimited(_, _, token::Delimiter::Brace, _)) + { + return Err(ecx.sess.dcx().span_err( + attr_span, + "contract annotations is only supported in functions with bodies", + )); + } + } + + Ok(new_tts) +} + +fn expand_requires_tts( + ecx: &mut ExtCtxt<'_>, + attr_span: Span, + annotation: TokenStream, + annotated: TokenStream, +) -> Result<TokenStream, ErrorGuaranteed> { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { + new_tts.push_tree(TokenTree::Token( + token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)), + Spacing::Joint, + )); + new_tts.push_tree(TokenTree::Token( + token::Token::new(token::TokenKind::OrOr, attr_span), + Spacing::Alone, + )); + new_tts.push_tree(TokenTree::Delimited( + DelimSpan::from_single(attr_span), + DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden), + token::Delimiter::Parenthesis, + annotation, + )); + Ok(()) + }) +} + +fn expand_ensures_tts( + ecx: &mut ExtCtxt<'_>, + attr_span: Span, + annotation: TokenStream, + annotated: TokenStream, +) -> Result<TokenStream, ErrorGuaranteed> { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { + new_tts.push_tree(TokenTree::Token( + token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)), + Spacing::Joint, + )); + new_tts.push_tree(TokenTree::Delimited( + DelimSpan::from_single(attr_span), + DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden), + token::Delimiter::Parenthesis, + annotation, + )); + Ok(()) + }) +} diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 78f50ba8d29..c3656e8244f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -114,10 +114,13 @@ fn cs_clone_simple( // type parameters. } else { // let _: AssertParamIsClone<FieldTy>; - super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[ - sym::clone, - sym::AssertParamIsClone, - ]); + super::assert_ty_bounds( + cx, + &mut stmts, + field.ty.clone(), + field.span, + &[sym::clone, sym::AssertParamIsClone], + ); } } }; @@ -126,10 +129,13 @@ fn cs_clone_simple( // Just a single assertion for unions, that the union impls `Copy`. // let _: AssertParamIsCopy<Self>; let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper))); - super::assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, &[ - sym::clone, - sym::AssertParamIsCopy, - ]); + super::assert_ty_bounds( + cx, + &mut stmts, + self_ty, + trait_span, + &[sym::clone, sym::AssertParamIsCopy], + ); } else { match *substr.fields { StaticStruct(vdata, ..) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 5790350203a..eca79e4dc48 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -65,10 +65,13 @@ fn cs_total_eq_assert( // Already produced an assertion for this type. } else { // let _: AssertParamIsEq<FieldTy>; - super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[ - sym::cmp, - sym::AssertParamIsEq, - ]); + super::assert_ty_bounds( + cx, + &mut stmts, + field.ty.clone(), + field.span, + &[sym::cmp, sym::AssertParamIsEq], + ); } } }; diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 49706db0e0b..5aed9f76f14 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -3,11 +3,11 @@ use ast::ptr::P; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::visit::BoundKind; use rustc_ast::{ - self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, + self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem, TraitBoundModifiers, VariantData, WherePredicate, }; -use rustc_attr_parsing as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_errors::E0802; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; @@ -32,15 +32,6 @@ pub(crate) fn expand_deriving_coerce_pointee( let (name_ident, generics) = if let Annotatable::Item(aitem) = item && let ItemKind::Struct(struct_data, g) = &aitem.kind { - let is_transparent = aitem.attrs.iter().any(|attr| { - attr::find_repr_attrs(cx.sess, attr) - .into_iter() - .any(|r| matches!(r, attr::ReprTransparent)) - }); - if !is_transparent { - cx.dcx().emit_err(RequireTransparent { span }); - return; - } if !matches!( struct_data, VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) @@ -88,8 +79,7 @@ pub(crate) fn expand_deriving_coerce_pointee( } else { let mut pointees = type_params .iter() - .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span))) - .fuse(); + .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span))); match (pointees.next(), pointees.next()) { (Some((idx, _span)), None) => idx, (None, _) => { @@ -110,6 +100,52 @@ pub(crate) fn expand_deriving_coerce_pointee( // Declare helper function that adds implementation blocks. // FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),]; + // # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`. + { + let trait_path = + cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]); + let trait_ref = cx.trait_ref(trait_path); + push(Annotatable::Item( + cx.item( + span, + Ident::empty(), + attrs.clone(), + ast::ItemKind::Impl(Box::new(ast::Impl { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Final, + constness: ast::Const::No, + generics: Generics { + params: generics + .params + .iter() + .map(|p| match &p.kind { + GenericParamKind::Lifetime => { + cx.lifetime_param(p.span(), p.ident, p.bounds.clone()) + } + GenericParamKind::Type { default: _ } => { + cx.typaram(p.span(), p.ident, p.bounds.clone(), None) + } + GenericParamKind::Const { ty, kw_span: _, default: _ } => cx + .const_param( + p.span(), + p.ident, + p.bounds.clone(), + ty.clone(), + None, + ), + }) + .collect(), + where_clause: generics.where_clause.clone(), + span: generics.span, + }, + of_trait: Some(trait_ref), + self_ty: self_type.clone(), + items: ThinVec::new(), + })), + ), + )); + } let mut add_impl_block = |generics, trait_symbol, trait_args| { let mut parts = path!(span, core::ops); parts.push(Ident::new(trait_symbol, span)); @@ -157,7 +193,7 @@ pub(crate) fn expand_deriving_coerce_pointee( { cx.dcx().emit_err(RequiresMaybeSized { span: pointee_ty_ident.span, - name: pointee_ty_ident.name.to_ident_string(), + name: pointee_ty_ident, }); return; } @@ -430,35 +466,35 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_transparent)] +#[diag(builtin_macros_coerce_pointee_requires_transparent, code = E0802)] struct RequireTransparent { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_field)] +#[diag(builtin_macros_coerce_pointee_requires_one_field, code = E0802)] struct RequireOneField { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_generic)] +#[diag(builtin_macros_coerce_pointee_requires_one_generic, code = E0802)] struct RequireOneGeneric { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_pointee)] +#[diag(builtin_macros_coerce_pointee_requires_one_pointee, code = E0802)] struct RequireOnePointee { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_too_many_pointees)] +#[diag(builtin_macros_coerce_pointee_too_many_pointees, code = E0802)] struct TooManyPointees { #[primary_span] one: Span, @@ -467,9 +503,9 @@ struct TooManyPointees { } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)] +#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)] struct RequiresMaybeSized { #[primary_span] span: Span, - name: String, + name: Ident, } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index eb01ca3941d..8ab21986e68 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -56,7 +56,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> 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), EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => { cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs deleted file mode 100644 index 6348560496e..00000000000 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more. - -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Ident, Span, Symbol, sym}; -use thin_vec::{ThinVec, thin_vec}; - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; - -pub(crate) fn expand_deriving_rustc_decodable( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let krate = sym::rustc_serialize; - let typaram = sym::__D; - - let trait_def = TraitDef { - span, - path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::decode, - generics: Bounds { - bounds: vec![(typaram, vec![Path::new_( - vec![krate, sym::Decoder], - vec![], - PathKind::Global, - )])], - }, - explicit_self: false, - nonself_args: vec![( - Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), - sym::d, - )], - ret_ty: Path(Path::new_( - pathvec_std!(result::Result), - vec![ - Box::new(Self_), - Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), - ], - PathKind::Std, - )), - attributes: ast::AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn decodable_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: Symbol, -) -> BlockOrExpr { - let decoder = substr.nonselflike_args[0].clone(); - let recurse = vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Decodable, trait_span), - Ident::new(sym::decode, trait_span), - ]; - let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); - // throw an underscore in front to suppress unused variable warnings - let blkarg = Ident::new(sym::_d, trait_span); - let blkdecoder = cx.expr_ident(trait_span, blkarg); - - 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]); - - let path = cx.path_ident(trait_span, substr.type_ident); - let result = - decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| { - cx.expr_try( - span, - cx.expr_call_global(span, fn_read_struct_field_path.clone(), thin_vec![ - blkdecoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone(), - ]), - ) - }); - let result = cx.expr_ok(trait_span, result); - let fn_read_struct_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]); - - cx.expr_call_global(trait_span, fn_read_struct_path, thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, nfields), - cx.lambda1(trait_span, result, blkarg), - ]) - } - StaticEnum(_, fields) => { - let variant = Ident::new(sym::i, trait_span); - - let mut arms = ThinVec::with_capacity(fields.len() + 1); - let mut variants = ThinVec::with_capacity(fields.len()); - - let fn_read_enum_variant_arg_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]); - - for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { - variants.push(cx.expr_str(v_span, ident.name)); - - let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = - decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| { - let idx = cx.expr_usize(span, field); - cx.expr_try( - span, - cx.expr_call_global( - span, - fn_read_enum_variant_arg_path.clone(), - thin_vec![blkdecoder.clone(), idx, exprdecode.clone()], - ), - ) - }); - - arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded)); - } - - arms.push(cx.arm_unreachable(trait_span)); - - let result = cx.expr_ok( - trait_span, - cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms), - ); - let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); - let variant_array_ref = cx.expr_array_ref(trait_span, variants); - let fn_read_enum_variant_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]); - let result = cx.expr_call_global(trait_span, fn_read_enum_variant_path, thin_vec![ - blkdecoder, - variant_array_ref, - lambda - ]); - let fn_read_enum_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]); - - cx.expr_call_global(trait_span, fn_read_enum_path, thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.lambda1(trait_span, result, blkarg), - ]) - } - _ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"), - }; - BlockOrExpr::new_expr(expr) -} - -/// Creates a decoder for a single enum variant/struct: -/// - `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: &ExtCtxt<'_>, - trait_span: Span, - outer_pat_path: ast::Path, - fields: &StaticFields, - mut getarg: F, -) -> P<Expr> -where - F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>, -{ - match fields { - Unnamed(fields, is_tuple) => { - let path_expr = cx.expr_path(outer_pat_path); - if matches!(is_tuple, IsTuple::No) { - path_expr - } else { - let fields = fields - .iter() - .enumerate() - .map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i)) - .collect(); - - cx.expr_call(trait_span, path_expr, fields) - } - } - Named(fields) => { - // use the field's span to get nicer error messages. - let fields = fields - .iter() - .enumerate() - .map(|(i, &(ident, span, _))| { - let arg = getarg(cx, span, ident.name, i); - cx.field_imm(span, ident, arg) - }) - .collect(); - cx.expr_struct(trait_span, outer_pat_path, fields) - } - } -} diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 3c7bebd0f19..1fe567e23f4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -42,7 +42,7 @@ pub(crate) fn expand_deriving_default( StaticStruct(_, fields) => { default_struct_substructure(cx, trait_span, substr, fields) } - StaticEnum(enum_def, _) => { + StaticEnum(enum_def) => { default_enum_substructure(cx, trait_span, enum_def, item.span()) } _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"), @@ -108,30 +108,38 @@ fn default_enum_substructure( Ok(default_variant) => { // We now know there is exactly one unit variant with exactly one `#[default]` attribute. match &default_variant.data { - VariantData::Unit(_) => cx.expr_path(cx.path(default_variant.span, vec![ - Ident::new(kw::SelfUpper, default_variant.span), - default_variant.ident, - ])), + VariantData::Unit(_) => cx.expr_path(cx.path( + default_variant.span, + vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], + )), VariantData::Struct { fields, .. } => { // This only happens if `#![feature(default_field_values)]`. We have validated // all fields have default values in the definition. let default_fields = fields .iter() .map(|field| { - cx.field_imm(field.span, field.ident.unwrap(), match &field.default { - // We use `Default::default()`. - None => default_call(cx, field.span), - // We use the field default const expression. - Some(val) => { - cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone())) - } - }) + cx.field_imm( + field.span, + field.ident.unwrap(), + match &field.default { + // We use `Default::default()`. + None => default_call(cx, field.span), + // We use the field default const expression. + Some(val) => cx.expr( + val.value.span, + ast::ExprKind::ConstBlock(val.clone()), + ), + }, + ) }) .collect(); - let path = cx.path(default_variant.span, vec![ - Ident::new(kw::SelfUpper, default_variant.span), - default_variant.ident, - ]); + let path = cx.path( + default_variant.span, + vec![ + Ident::new(kw::SelfUpper, default_variant.span), + default_variant.ident, + ], + ); cx.expr_struct(default_variant.span, path, default_fields) } // Logic error in `extract_default_variant`. diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs deleted file mode 100644 index 20aacb2caca..00000000000 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! The compiler code necessary to implement the `#[derive(RustcEncodable)]` -//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that -//! type-defining items may be tagged with -//! `#[derive(RustcEncodable, RustcDecodable)]`. -//! -//! For example, a type like: -//! -//! ```ignore (old code) -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Node { id: usize } -//! ``` -//! -//! would generate two implementations like: -//! -//! ```ignore (old code) -//! # struct Node { id: usize } -//! impl<S: Encoder<E>, E> Encodable<S, E> for Node { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Node", 1, |this| { -//! this.emit_struct_field("id", 0, |this| { -//! Encodable::encode(&self.id, this) -//! /* this.emit_usize(self.id) can also be used */ -//! }) -//! }) -//! } -//! } -//! -//! impl<D: Decoder<E>, E> Decodable<D, E> for Node { -//! fn decode(d: &mut D) -> Result<Node, E> { -//! d.read_struct("Node", 1, |this| { -//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { -//! Ok(id) => Ok(Node { id: id }), -//! Err(e) => Err(e), -//! } -//! }) -//! } -//! } -//! ``` -//! -//! Other interesting scenarios are when the item has type parameters or -//! references other non-built-in types. A type definition like: -//! -//! ```ignore (old code) -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Spanned<T> { node: T, span: Span } -//! ``` -//! -//! would yield functions like: -//! -//! ```ignore (old code) -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! # struct Spanned<T> { node: T, span: Span } -//! impl< -//! S: Encoder<E>, -//! E, -//! T: Encodable<S, E> -//! > Encodable<S, E> for Spanned<T> { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Spanned", 2, |this| { -//! this.emit_struct_field("node", 0, |this| self.node.encode(this)) -//! .unwrap(); -//! this.emit_struct_field("span", 1, |this| self.span.encode(this)) -//! }) -//! } -//! } -//! -//! impl< -//! D: Decoder<E>, -//! E, -//! T: Decodable<D, E> -//! > Decodable<D, E> for Spanned<T> { -//! fn decode(d: &mut D) -> Result<Spanned<T>, E> { -//! d.read_struct("Spanned", 2, |this| { -//! Ok(Spanned { -//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) -//! .unwrap(), -//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) -//! .unwrap(), -//! }) -//! }) -//! } -//! } -//! ``` - -use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Ident, Span, Symbol, sym}; -use thin_vec::{ThinVec, thin_vec}; - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; - -pub(crate) fn expand_deriving_rustc_encodable( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let krate = sym::rustc_serialize; - let typaram = sym::__S; - - let trait_def = TraitDef { - span, - path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::encode, - generics: Bounds { - bounds: vec![(typaram, vec![Path::new_( - vec![krate, sym::Encoder], - vec![], - PathKind::Global, - )])], - }, - explicit_self: true, - nonself_args: vec![( - Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), - sym::s, - )], - ret_ty: Path(Path::new_( - pathvec_std!(result::Result), - vec![ - Box::new(Unit), - Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), - ], - PathKind::Std, - )), - attributes: AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - encodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn encodable_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: Symbol, -) -> BlockOrExpr { - let encoder = substr.nonselflike_args[0].clone(); - // throw an underscore in front to suppress unused variable warnings - let blkarg = Ident::new(sym::_e, trait_span); - let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global(trait_span, vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Encodable, trait_span), - Ident::new(sym::encode, trait_span), - ])); - - 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 = ThinVec::new(); - for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() { - let name = match name { - Some(id) => id.name, - None => Symbol::intern(&format!("_field{i}")), - }; - let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = - cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(span, enc, blkarg); - let call = cx.expr_call_global(span, fn_emit_struct_field_path.clone(), thin_vec![ - blkencoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda, - ]); - - // last call doesn't need a try! - let last = fields.len() - 1; - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprKind::Ret(Some(call))) - }; - - let stmt = cx.stmt_expr(call); - stmts.push(stmt); - } - - // unit structs have no fields and need to return Ok() - let blk = if stmts.is_empty() { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); - cx.lambda1(trait_span, ok, blkarg) - } else { - cx.lambda_stmts_1(trait_span, stmts, blkarg) - }; - - let fn_emit_struct_path = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]); - - let expr = cx.expr_call_global(trait_span, fn_emit_struct_path, thin_vec![ - encoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, fields.len()), - blk, - ]); - BlockOrExpr::new_expr(expr) - } - - 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 - // actually exist. - let me = cx.stmt_let(trait_span, false, blkarg, encoder); - let encoder = cx.expr_ident(trait_span, blkarg); - - let fn_emit_enum_variant_arg_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]); - - let mut stmts = ThinVec::new(); - if !fields.is_empty() { - let last = fields.len() - 1; - for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { - let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = cx - .expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(span, enc, blkarg); - - let call = cx.expr_call_global( - span, - fn_emit_enum_variant_arg_path.clone(), - thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda], - ); - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprKind::Ret(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - } else { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); - let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - let name = cx.expr_str(trait_span, variant.ident.name); - - let fn_emit_enum_variant_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]); - - let call = cx.expr_call_global(trait_span, fn_emit_enum_variant_path, thin_vec![ - blkencoder, - name, - cx.expr_usize(trait_span, *idx), - cx.expr_usize(trait_span, fields.len()), - blk, - ]); - - let blk = cx.lambda1(trait_span, call, blkarg); - let fn_emit_enum_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]); - let expr = cx.expr_call_global(trait_span, fn_emit_enum_path, thin_vec![ - encoder, - cx.expr_str(trait_span, substr.type_ident.name), - blk - ]); - BlockOrExpr::new_mixed(thin_vec![me], Some(expr)) - } - - _ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"), - } -} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f0a5e44e066..234ec858216 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -311,7 +311,7 @@ pub(crate) enum SubstructureFields<'a> { /// 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, &'a ast::Variant, Vec<FieldInfo>), + EnumMatching(&'a ast::Variant, Vec<FieldInfo>), /// 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 @@ -322,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> { StaticStruct(&'a ast::VariantData, StaticFields), /// A static method where `Self` is an enum. - StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), + StaticEnum(&'a ast::EnumDef), } /// Combine the values of all the fields together. The last argument is @@ -1034,6 +1034,7 @@ impl<'a> MethodDef<'a> { defaultness, sig, generics: fn_generics, + contract: None, body: Some(body_block), })), tokens: None, @@ -1219,10 +1220,12 @@ impl<'a> MethodDef<'a> { let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { - let variant_value = - deriving::call_intrinsic(cx, span, sym::discriminant_value, thin_vec![ - selflike_arg.clone() - ]); + let variant_value = deriving::call_intrinsic( + cx, + span, + sym::discriminant_value, + thin_vec![selflike_arg.clone()], + ); cx.stmt_let(span, false, ident, variant_value) }) .collect(); @@ -1270,7 +1273,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, nonselflike_args, - &EnumMatching(0, variant, Vec::new()), + &EnumMatching(variant, Vec::new()), ); } } @@ -1282,9 +1285,8 @@ impl<'a> MethodDef<'a> { // where each tuple has length = selflike_args.len() let mut match_arms: ThinVec<ast::Arm> = variants .iter() - .enumerate() - .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty())) - .map(|(index, variant)| { + .filter(|&v| !(unify_fieldless_variants && v.data.fields().is_empty())) + .map(|variant| { // A single arm has form (&VariantK, &VariantK, ...) => BodyK // (see "Final wrinkle" note below for why.) @@ -1316,7 +1318,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, variant, fields); + let substructure = EnumMatching(variant, fields); let arm_expr = self .call_substructure_method( cx, @@ -1344,7 +1346,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, nonselflike_args, - &EnumMatching(0, v, Vec::new()), + &EnumMatching(v, Vec::new()), ) .into_expr(cx, span), ) @@ -1407,21 +1409,12 @@ impl<'a> MethodDef<'a> { type_ident: Ident, nonselflike_args: &[P<Expr>], ) -> BlockOrExpr { - let summary = enum_def - .variants - .iter() - .map(|v| { - let sp = v.span.with_ctxt(trait_.span.ctxt()); - let summary = trait_.summarise_struct(cx, &v.data); - (v.ident, sp, summary) - }) - .collect(); self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &StaticEnum(enum_def, summary), + &StaticEnum(enum_def), ) } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index af6dc62db7a..f34a6ae1d98 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -21,7 +21,6 @@ pub(crate) struct Path { #[derive(Clone)] pub(crate) enum PathKind { Local, - Global, Std, } @@ -57,7 +56,6 @@ impl Path { let params = tys.map(GenericArg::Type).collect(); match self.kind { - PathKind::Global => cx.path_all(span, true, idents, params), PathKind::Local => cx.path_all(span, false, idents, params), PathKind::Std => { let def_site = cx.with_def_site_ctxt(DUMMY_SP); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index ec058b41313..c112589b131 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -23,9 +23,7 @@ pub(crate) mod bounds; pub(crate) mod clone; pub(crate) mod coerce_pointee; pub(crate) mod debug; -pub(crate) mod decodable; pub(crate) mod default; -pub(crate) mod encodable; pub(crate) mod hash; #[path = "cmp/eq.rs"] diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 8831261759c..0913dc91a53 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -77,11 +77,11 @@ pub(crate) fn expand_option_env<'cx>( let guar = cx.dcx().emit_err(errors::EnvNotUnicode { span: sp, var: *symbol }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } - Ok(value) => { - cx.expr_call_global(sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), thin_vec![ - cx.expr_str(sp, value) - ]) - } + Ok(value) => cx.expr_call_global( + sp, + cx.std_path(&[sym::option, sym::Option, sym::Some]), + thin_vec![cx.expr_str(sp, value)], + ), }; ExpandResult::Ready(MacEager::expr(e)) } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 5202fe26c40..90447da6680 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -8,7 +8,9 @@ use rustc_ast::{ token, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; +use rustc_errors::{ + Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize, +}; use rustc_expand::base::*; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; @@ -101,15 +103,14 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, match p.expect(exp!(Comma)) { Err(err) => { - match token::TokenKind::Comma.similar_tokens() { - Some(tks) if tks.contains(&p.token.kind) => { - // If a similar token is found, then it may be a typo. We - // consider it as a comma, and continue parsing. - err.emit(); - p.bump(); - } + if token::TokenKind::Comma.similar_tokens().contains(&p.token.kind) { + // If a similar token is found, then it may be a typo. We + // consider it as a comma, and continue parsing. + err.emit(); + p.bump(); + } else { // Otherwise stop the parsing and return the error. - _ => return Err(err), + return Err(err); } } Ok(Recovered::Yes(_)) => (), @@ -406,7 +407,7 @@ fn make_format_args( for piece in &pieces { match *piece { - parse::Piece::String(s) => { + parse::Piece::Lit(s) => { unfinished_literal.push_str(s); } parse::Piece::NextArgument(box parse::Argument { position, position_span, format }) => { @@ -976,15 +977,11 @@ fn report_invalid_references( } else { MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect()) }; - let arg_list = if let &[index] = &indexes[..] { - format!("argument {index}") - } else { - let tail = indexes.pop().unwrap(); - format!( - "arguments {head} and {tail}", - head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ") - ) - }; + let arg_list = format!( + "argument{} {}", + pluralize!(indexes.len()), + listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default() + ); e = ecx.dcx().struct_span_err( span, format!("invalid reference to positional {arg_list} ({num_args_desc})"), diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 71320e6d5ad..866ec72f116 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -183,10 +183,14 @@ pub(crate) mod printf { s.push('{'); if let Some(arg) = self.parameter { - match write!(s, "{}", match arg.checked_sub(1) { - Some(a) => a, - None => return Err(None), - }) { + match write!( + s, + "{}", + match arg.checked_sub(1) { + Some(a) => a, + None => return Err(None), + } + ) { Err(_) => return 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 8fe06df48e5..1fd54e170b9 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -99,12 +99,10 @@ fn test_parse() { 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(Option::as_deref).collect::<Vec<_>>(), vec![ - Some("{}"), - None, - Some("{:.*}"), - None - ]); + assert_eq!( + subs.iter().map(Option::as_deref).collect::<Vec<_>>(), + vec![Some("{}"), None, Some("{:.*}"), None] + ); } /// Checks that the translations are what we expect. 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 dd2ee2b6ca9..145e3e529b0 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs @@ -38,11 +38,10 @@ fn test_iter() { use super::iter_subs; 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(Option::as_deref).collect::<Vec<_>>(), vec![ - Some("{0}"), - None, - Some("{WORD}") - ]); + assert_eq!( + subs.iter().map(Option::as_deref).collect::<Vec<_>>(), + vec![Some("{0}"), None, Some("{WORD}")] + ); } #[test] diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 8388e9dcafb..8fdbbf8e704 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -81,6 +81,7 @@ impl AllocFnFactory<'_, '_> { defaultness: ast::Defaultness::Final, sig, generics: Generics::default(), + contract: None, body, })); let item = self.cx.item( diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 0918403b855..ca16583a45d 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -55,6 +55,7 @@ mod trace_macros; pub mod asm; pub mod cmdline_attrs; +pub mod contracts; pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; @@ -132,11 +133,13 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { Ord: ord::expand_deriving_ord, PartialEq: partial_eq::expand_deriving_partial_eq, PartialOrd: partial_ord::expand_deriving_partial_ord, - RustcDecodable: decodable::expand_deriving_rustc_decodable, - RustcEncodable: encodable::expand_deriving_rustc_encodable, CoercePointee: coerce_pointee::expand_deriving_coerce_pointee, } let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }))); + let requires = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandRequires)); + register(sym::contracts_requires, requires); + let ensures = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandEnsures)); + register(sym::contracts_ensures, ensures); } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index dee185ff0c9..ee6475c8b8e 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -301,13 +301,10 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { }; let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name])); let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { - cx.expr_path(cx.path(span.with_ctxt(harness_span.ctxt()), vec![ - proc_macro, - bridge, - client, - proc_macro_ty, - method, - ])) + cx.expr_path(cx.path( + span.with_ctxt(harness_span.ctxt()), + vec![proc_macro, bridge, client, proc_macro_ty, method], + )) }; match m { ProcMacro::Derive(cd) => { @@ -340,10 +337,14 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { // The call needs to use `harness_span` so that the const stability checker // accepts it. - cx.expr_call(harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![ - cx.expr_str(span, ca.function_name.name), - local_path(cx, ca.function_name), - ]) + cx.expr_call( + harness_span, + proc_macro_ty_method_path(cx, ident), + thin_vec![ + cx.expr_str(span, ca.function_name.name), + local_path(cx, ca.function_name), + ], + ) } } }) @@ -357,12 +358,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { span, cx.ty( span, - ast::TyKind::Slice(cx.ty_path(cx.path(span, vec![ - proc_macro, - bridge, - client, - proc_macro_ty, - ]))), + ast::TyKind::Slice( + cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), + ), ), None, ast::Mutability::Not, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index d163da3ddea..8142f1518dd 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,12 +1,12 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::sync::Arc; 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_data_structures::sync::Lrc; use rustc_expand::base::{ DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path, }; @@ -249,7 +249,7 @@ fn load_binary_file( original_path: &Path, macro_span: Span, path_span: Span, -) -> Result<(Lrc<[u8]>, Span), Box<dyn MacResult>> { +) -> Result<(Arc<[u8]>, Span), Box<dyn MacResult>> { let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) { Ok(path) => path, Err(err) => { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 3f73ddbdd29..a05fff2dcd1 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -169,20 +169,26 @@ pub(crate) fn expand_test_or_bench( // creates test::ShouldPanic::$name let should_panic_path = |name| { - cx.path(sp, vec![ - test_id, - Ident::from_str_and_span("ShouldPanic", sp), - Ident::from_str_and_span(name, sp), - ]) + cx.path( + sp, + vec![ + test_id, + Ident::from_str_and_span("ShouldPanic", sp), + Ident::from_str_and_span(name, sp), + ], + ) }; // creates test::TestType::$name let test_type_path = |name| { - cx.path(sp, vec![ - test_id, - Ident::from_str_and_span("TestType", sp), - Ident::from_str_and_span(name, sp), - ]) + cx.path( + sp, + vec![ + test_id, + Ident::from_str_and_span("TestType", sp), + Ident::from_str_and_span(name, sp), + ], + ) }; // creates $name: $expr @@ -202,39 +208,55 @@ pub(crate) fn expand_test_or_bench( // A simple ident for a lambda let b = Ident::from_str_and_span("b", attr_sp); - cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), thin_vec![ - // #[coverage(off)] - // |b| self::test::assert_test_result( - coverage_off(cx.lambda1( - sp, - cx.expr_call(sp, cx.expr_path(test_path("assert_test_result")), thin_vec![ - // super::$test_fn(b) + cx.expr_call( + sp, + cx.expr_path(test_path("StaticBenchFn")), + thin_vec![ + // #[coverage(off)] + // |b| self::test::assert_test_result( + coverage_off(cx.lambda1( + sp, cx.expr_call( - ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), - thin_vec![cx.expr_ident(sp, b)], + sp, + cx.expr_path(test_path("assert_test_result")), + thin_vec![ + // super::$test_fn(b) + cx.expr_call( + ret_ty_sp, + cx.expr_path(cx.path(sp, vec![item.ident])), + thin_vec![cx.expr_ident(sp, b)], + ), + ], ), - ],), - b, - )), // ) - ]) + b, + )), // ) + ], + ) } else { - cx.expr_call(sp, cx.expr_path(test_path("StaticTestFn")), thin_vec![ - // #[coverage(off)] - // || { - coverage_off(cx.lambda0( - sp, - // test::assert_test_result( - cx.expr_call(sp, cx.expr_path(test_path("assert_test_result")), thin_vec![ - // $test_fn() + cx.expr_call( + sp, + cx.expr_path(test_path("StaticTestFn")), + thin_vec![ + // #[coverage(off)] + // || { + coverage_off(cx.lambda0( + sp, + // test::assert_test_result( cx.expr_call( - ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), - ThinVec::new(), - ), // ) - ],), // } - )), // ) - ]) + sp, + cx.expr_path(test_path("assert_test_result")), + thin_vec![ + // $test_fn() + cx.expr_call( + ret_ty_sp, + cx.expr_path(cx.path(sp, vec![item.ident])), + ThinVec::new(), + ), // ) + ], + ), // } + )), // ) + ], + ) }; let test_path_symbol = Symbol::intern(&item_path( @@ -245,26 +267,30 @@ pub(crate) fn expand_test_or_bench( let location_info = get_location_info(cx, &item); - let mut test_const = cx.item( - sp, - Ident::new(item.ident.name, sp), - thin_vec![ - // #[cfg(test)] - cx.attr_nested_word(sym::cfg, sym::test, attr_sp), - // #[rustc_test_marker = "test_case_sort_key"] - cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), - // #[doc(hidden)] - cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), - ], - // const $ident: test::TestDescAndFn = - ast::ItemKind::Const( - ast::ConstItem { - defaultness: ast::Defaultness::Final, - generics: ast::Generics::default(), - ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), - // test::TestDescAndFn { - expr: Some( - cx.expr_struct(sp, test_path("TestDescAndFn"), thin_vec![ + let mut test_const = + cx.item( + sp, + Ident::new(item.ident.name, sp), + thin_vec![ + // #[cfg(test)] + cx.attr_nested_word(sym::cfg, sym::test, attr_sp), + // #[rustc_test_marker = "test_case_sort_key"] + cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), + // #[doc(hidden)] + cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), + ], + // const $ident: test::TestDescAndFn = + ast::ItemKind::Const( + ast::ConstItem { + defaultness: ast::Defaultness::Final, + generics: ast::Generics::default(), + ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + // test::TestDescAndFn { + expr: Some( + cx.expr_struct( + sp, + test_path("TestDescAndFn"), + thin_vec![ // desc: test::TestDesc { field( "desc", @@ -340,12 +366,13 @@ pub(crate) fn expand_test_or_bench( ), // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) field("testfn", test_fn), // } - ]), // } - ), - } - .into(), - ), - ); + ], + ), // } + ), + } + .into(), + ), + ); test_const = test_const.map(|mut tc| { tc.vis.kind = ast::VisibilityKind::Public; tc diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 31b068bd33d..472e16e62d5 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -344,6 +344,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { defaultness, sig, generics: ast::Generics::default(), + contract: None, body: Some(main_body), })); | 
