about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs104
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs20
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs15
21 files changed, 210 insertions, 33 deletions
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 00000000000..eaf1b1167cf
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -0,0 +1,104 @@
+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<Annotatable> {
+    check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
+
+    let orig_item = item.clone();
+    let not_function = || {
+        ecx.sess
+            .parse_sess
+            .span_diagnostic
+            .span_err(item.span(), "alloc_error_handler must be a function");
+        vec![orig_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) = match &item {
+        Annotatable::Item(item) => match item.kind {
+            ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)),
+            _ => return not_function(),
+        },
+        Annotatable::Stmt(stmt) => match &stmt.kind {
+            StmtKind::Item(item_) => match item_.kind {
+                ItemKind::Fn(ref fn_kind) => {
+                    (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+                }
+                _ => return not_function(),
+            },
+            _ => return not_function(),
+        },
+        _ => return not_function(),
+    };
+
+    // 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 special = sym::rustc_std_internal_symbol;
+    let special = cx.meta_word(span, special);
+    let attrs = thin_vec![cx.attribute(special)];
+
+    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/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 973a8cb85c2..bb683936026 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -58,6 +58,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
     /// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to:
     ///
     /// ```rust
+    /// #![feature(generic_assert_internals)]
     /// let elem = 1;
     /// {
     ///   #[allow(unused_imports)]
@@ -70,7 +71,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
     ///       __local_bind0
     ///     } == 1
     ///   ) {
-    ///     panic!("Assertion failed: elem == 1\nWith captures:\n  elem = {}", __capture0)
+    ///     panic!("Assertion failed: elem == 1\nWith captures:\n  elem = {:?}", __capture0)
     ///   }
     /// }
     /// ```
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 46b54eae384..5638c2f6180 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -36,7 +36,7 @@ pub fn expand_cfg(
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros::requires_cfg_pattern)]
+#[diag(builtin_macros_requires_cfg_pattern)]
 struct RequiresCfgPattern {
     #[primary_span]
     #[label]
@@ -44,7 +44,7 @@ struct RequiresCfgPattern {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros::expected_one_cfg_pattern)]
+#[diag(builtin_macros_expected_one_cfg_pattern)]
 struct OneCfgPattern {
     #[primary_span]
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 009f3c783d4..750f1fe121f 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -210,8 +210,15 @@ impl CfgEval<'_, '_> {
 }
 
 impl MutVisitor for CfgEval<'_, '_> {
+    #[instrument(level = "trace", skip(self))]
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
-        self.cfg.configure_expr(expr);
+        self.cfg.configure_expr(expr, false);
+        mut_visit::noop_visit_expr(expr, self);
+    }
+
+    #[instrument(level = "trace", skip(self))]
+    fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+        self.cfg.configure_expr(expr, true);
         mut_visit::noop_visit_expr(expr, self);
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 77e0b6c55a8..7bd344467d0 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -16,6 +16,7 @@ pub fn expand_deriving_copy(
     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,
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index c7f2d95e72f..fa8685f5f4e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -72,6 +72,7 @@ pub fn expand_deriving_clone(
     let trait_def = TraitDef {
         span,
         path: path_std!(clone::Clone),
+        skip_path_as_bound: false,
         additional_bounds: bounds,
         generics: Bounds::empty(),
         supports_unions: true,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 5b556c5c9b9..eab67b0d354 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -25,6 +25,7 @@ pub fn expand_deriving_eq(
     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,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 72625869558..7f117981a9a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -19,6 +19,7 @@ pub fn expand_deriving_ord(
     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,
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 42ee65b570a..236cbccaf9f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -83,6 +83,7 @@ pub fn expand_deriving_partial_eq(
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::PartialEq),
+        skip_path_as_bound: false,
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
         supports_unions: false,
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 516892aeda9..4173403a1b8 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -37,6 +37,7 @@ pub fn expand_deriving_partial_ord(
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::PartialOrd),
+        skip_path_as_bound: false,
         additional_bounds: vec![],
         generics: Bounds::empty(),
         supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 4af7fd81653..2cf614ed947 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -20,6 +20,7 @@ pub fn expand_deriving_debug(
     let trait_def = TraitDef {
         span,
         path: path_std!(fmt::Debug),
+        skip_path_as_bound: false,
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
         supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 7174dbbe7ea..d669f616802 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -23,6 +23,7 @@ pub fn expand_deriving_rustc_decodable(
     let trait_def = TraitDef {
         span,
         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,
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index a94c8a996e6..17df9fb279a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -24,6 +24,7 @@ pub fn expand_deriving_default(
     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,
@@ -262,3 +263,22 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
         }
     }
 }
+
+fn has_a_default_variant(item: &Annotatable) -> bool {
+    struct HasDefaultAttrOnVariant {
+        found: bool,
+    }
+
+    impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
+        fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) {
+            if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
+                self.found = true;
+            }
+            // no need to subrecurse.
+        }
+    }
+
+    let mut visitor = HasDefaultAttrOnVariant { found: false };
+    item.visit_with(&mut visitor);
+    visitor.found
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index b220e54238f..f83f58b97d3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -107,6 +107,7 @@ pub fn expand_deriving_rustc_encodable(
     let trait_def = TraitDef {
         span,
         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,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 3cc160adb53..16ee3aa89bb 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -174,6 +174,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use std::cell::RefCell;
 use std::iter;
+use std::ops::Not;
 use std::vec;
 use thin_vec::thin_vec;
 use ty::{Bounds, Path, Ref, Self_, Ty};
@@ -187,6 +188,9 @@ pub struct TraitDef<'a> {
     /// Path of the trait, including any type parameters
     pub path: Path,
 
+    /// Whether to skip adding the current trait as a bound to the type parameters of the type.
+    pub skip_path_as_bound: bool,
+
     /// Additional bounds required of any type parameters of the type,
     /// other than the current trait
     pub additional_bounds: Vec<Ty>,
@@ -562,7 +566,7 @@ impl<'a> TraitDef<'a> {
                     tokens: None,
                 },
                 attrs: ast::AttrVec::new(),
-                kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
+                kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
                     defaultness: ast::Defaultness::Final,
                     generics: Generics::default(),
                     where_clauses: (
@@ -596,7 +600,7 @@ impl<'a> TraitDef<'a> {
                         cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
                     }).chain(
                         // require the current trait
-                        iter::once(cx.trait_bound(trait_path.clone()))
+                        self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
                     ).chain(
                         // also add in any bounds from the declaration
                         param.bounds.iter().cloned()
@@ -1110,6 +1114,11 @@ impl<'a> MethodDef<'a> {
     /// ```
     /// is equivalent to:
     /// ```
+    /// #![feature(core_intrinsics)]
+    /// enum A {
+    ///     A1,
+    ///     A2(i32)
+    /// }
     /// impl ::core::cmp::PartialEq for A {
     ///     #[inline]
     ///     fn eq(&self, other: &A) -> bool {
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index f1f02e7ce77..6e9d5f08b94 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -22,6 +22,7 @@ pub fn expand_deriving_hash(
     let hash_trait_def = TraitDef {
         span,
         path,
+        skip_path_as_bound: false,
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
         supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a65d0bad6de..ee346047a0b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -131,6 +131,8 @@ fn inject_impl_of_structural_trait(
     // Create generics param list for where clauses and impl headers
     let mut generics = generics.clone();
 
+    let ctxt = span.ctxt();
+
     // Create the type of `self`.
     //
     // in addition, remove defaults from generic params (impls cannot have them).
@@ -138,16 +140,18 @@ fn inject_impl_of_structural_trait(
         .params
         .iter_mut()
         .map(|param| match &mut param.kind {
-            ast::GenericParamKind::Lifetime => {
-                ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
-            }
+            ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
+                cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
+            ),
             ast::GenericParamKind::Type { default } => {
                 *default = None;
-                ast::GenericArg::Type(cx.ty_ident(span, param.ident))
+                ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
             }
             ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
                 *default = None;
-                ast::GenericArg::Const(cx.const_ident(span, param.ident))
+                ast::GenericArg::Const(
+                    cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
+                )
             }
         })
         .collect();
@@ -174,6 +178,8 @@ 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)));
 
     let newitem = cx.item(
         span,
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index b15e2d084ef..8b07c110663 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -159,7 +159,7 @@ pub fn make_format_args(
     append_newline: bool,
 ) -> Result<FormatArgs, ()> {
     let msg = "format argument must be a string literal";
-    let fmt_span = efmt.span;
+    let unexpanded_fmt_span = efmt.span;
     let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
         Ok(mut fmt) if append_newline => {
             fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@@ -174,7 +174,7 @@ pub fn make_format_args(
                 };
                 if !suggested {
                     err.span_suggestion(
-                        fmt_span.shrink_to_lo(),
+                        unexpanded_fmt_span.shrink_to_lo(),
                         "you might be missing a string literal to format with",
                         format!("\"{}\", ", sugg_fmt),
                         Applicability::MaybeIncorrect,
@@ -192,7 +192,7 @@ pub fn make_format_args(
     };
 
     let fmt_str = fmt_str.as_str(); // for the suggestions below
-    let fmt_snippet = ecx.source_map().span_to_snippet(fmt_span).ok();
+    let fmt_snippet = ecx.source_map().span_to_snippet(unexpanded_fmt_span).ok();
     let mut parser = parse::Parser::new(
         fmt_str,
         str_style,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index f058503064b..bde0102186a 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -7,7 +7,7 @@
 #![feature(box_patterns)]
 #![feature(decl_macro)]
 #![feature(if_let_guard)]
-#![feature(is_some_with)]
+#![feature(is_some_and)]
 #![feature(is_sorted)]
 #![feature(let_chains)]
 #![feature(proc_macro_internals)]
@@ -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;
@@ -94,6 +95,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     }
 
     register_attr! {
+        alloc_error_handler: alloc_error_handler::expand,
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 7efb6cc61ee..fee5d04cdae 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -36,13 +36,22 @@ pub fn expand_test_case(
     let sp = ecx.with_def_site_ctxt(attr_sp);
     let mut item = anno_item.expect_item();
     item = item.map(|mut item| {
+        let test_path_symbol = Symbol::intern(&item_path(
+            // skip the name of the root module
+            &ecx.current_expansion.module.mod_path[1..],
+            &item.ident,
+        ));
         item.vis = ast::Visibility {
             span: item.vis.span,
             kind: ast::VisibilityKind::Public,
             tokens: None,
         };
         item.ident.span = item.ident.span.with_ctxt(sp.ctxt());
-        item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker)));
+        item.attrs.push(ecx.attribute(attr::mk_name_value_item_str(
+            Ident::new(sym::rustc_test_marker, sp),
+            test_path_symbol,
+            sp,
+        )));
         item
     });
 
@@ -115,7 +124,7 @@ pub fn expand_test_or_bench(
             // reworked in the future to not need it, it'd be nice.
             _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
         };
-        err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
+        err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions")
             .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
             .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
             .emit();
@@ -215,6 +224,12 @@ pub fn expand_test_or_bench(
         )
     };
 
+    let test_path_symbol = Symbol::intern(&item_path(
+        // skip the name of the root module
+        &cx.current_expansion.module.mod_path[1..],
+        &item.ident,
+    ));
+
     let mut test_const = cx.item(
         sp,
         Ident::new(item.ident.name, sp),
@@ -224,9 +239,14 @@ pub fn expand_test_or_bench(
                 Ident::new(sym::cfg, attr_sp),
                 vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))],
             )),
-            // #[rustc_test_marker]
-            cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)),
-        ],
+            // #[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,
+            )),
+        ]
+        .into(),
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
@@ -250,14 +270,7 @@ pub fn expand_test_or_bench(
                                         cx.expr_call(
                                             sp,
                                             cx.expr_path(test_path("StaticTestName")),
-                                            vec![cx.expr_str(
-                                                sp,
-                                                Symbol::intern(&item_path(
-                                                    // skip the name of the root module
-                                                    &cx.current_expansion.module.mod_path[1..],
-                                                    &item.ident,
-                                                )),
-                                            )],
+                                            vec![cx.expr_str(sp, test_path_symbol)],
                                         ),
                                     ),
                                     // ignore: true | false
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 561ca00c719..b8b8351a36f 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -18,9 +18,11 @@ use thin_vec::thin_vec;
 
 use std::{iter, mem};
 
+#[derive(Clone)]
 struct Test {
     span: Span,
     ident: Ident,
+    name: Symbol,
 }
 
 struct TestCtxt<'a> {
@@ -120,10 +122,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = i.into_inner();
-        if is_test_case(&self.cx.ext_cx.sess, &item) {
+        if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
             debug!("this is a test item");
 
-            let test = Test { span: item.span, ident: item.ident };
+            let test = Test { span: item.span, ident: item.ident, name };
             self.tests.push(test);
         }
 
@@ -357,9 +359,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     debug!("building test vector from {} tests", cx.test_cases.len());
     let ecx = &cx.ext_cx;
 
+    let mut tests = cx.test_cases.clone();
+    tests.sort_by(|a, b| a.name.as_str().cmp(&b.name.as_str()));
+
     ecx.expr_array_ref(
         sp,
-        cx.test_cases
+        tests
             .iter()
             .map(|test| {
                 ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident])))
@@ -368,8 +373,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     )
 }
 
-fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
-    sess.contains_name(&i.attrs, sym::rustc_test_marker)
+fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
+    sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
 }
 
 fn get_test_runner(