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/asm.rs28
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs68
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/offset_of.rs99
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs6
8 files changed, 188 insertions, 42 deletions
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 8c1579baacb..bcdd58a0901 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -15,6 +15,8 @@ use rustc_span::{InnerSpan, Span};
 use rustc_target::asm::InlineAsmArch;
 use smallvec::smallvec;
 
+use crate::errors;
+
 pub struct AsmArgs {
     pub templates: Vec<P<ast::Expr>>,
     pub operands: Vec<(ast::InlineAsmOperand, Span)>,
@@ -205,7 +207,7 @@ pub fn parse_asm_args<'a>(
         // of the argument available.
         if explicit_reg {
             if name.is_some() {
-                diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
+                diag.emit_err(errors::AsmExplicitRegisterName { span });
             }
             args.reg_args.insert(slot);
         } else if let Some(name) = name {
@@ -240,25 +242,19 @@ pub fn parse_asm_args<'a>(
         && args.options.contains(ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
-            .emit();
+        diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && args.options.contains(ast::InlineAsmOptions::NORETURN)
     {
         let spans = args.options_spans.clone();
-        diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
-            .emit();
+        diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        diag.struct_span_err(
-            spans,
-            "the `pure` option must be combined with either `nomem` or `readonly`",
-        )
-        .emit();
+        diag.emit_err(errors::AsmPureCombine { spans });
     }
 
     let mut have_real_output = false;
@@ -285,11 +281,7 @@ pub fn parse_asm_args<'a>(
         }
     }
     if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
-        diag.struct_span_err(
-            args.options_spans.clone(),
-            "asm with the `pure` option must have at least one output",
-        )
-        .emit();
+        diag.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
     }
     if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
         let err = diag
@@ -705,11 +697,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                             .ty_span
                             .map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
                             .unwrap_or(template_sp);
-                        ecx.struct_span_err(
-                            span,
-                            "asm template modifier must be a single character",
-                        )
-                        .emit();
+                        ecx.emit_err(errors::AsmModifierInvalid { span });
                         modifier = None;
                     }
 
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index c9e3cd486f8..090e00616fb 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -301,6 +301,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::If(_, _, _)
             | ExprKind::IncludedBytes(..)
             | ExprKind::InlineAsm(_)
+            | ExprKind::OffsetOf(_, _)
             | ExprKind::Let(_, _, _)
             | ExprKind::Lit(_)
             | ExprKind::Loop(_, _, _)
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 630f9b87bc3..b146988a3c2 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -551,3 +551,71 @@ pub(crate) struct FormatPositionalMismatch {
     #[subdiagnostic]
     pub(crate) highlight: SingleLabelManySpans,
 }
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_case_non_item)]
+pub(crate) struct TestCaseNonItem {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_bad_fn)]
+pub(crate) struct TestBadFn {
+    #[primary_span]
+    pub(crate) span: Span,
+    #[label]
+    pub(crate) cause: Span,
+    pub(crate) kind: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_explicit_register_name)]
+pub(crate) struct AsmExplicitRegisterName {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_mutually_exclusive)]
+pub(crate) struct AsmMutuallyExclusive {
+    #[primary_span]
+    pub(crate) spans: Vec<Span>,
+    pub(crate) opt1: &'static str,
+    pub(crate) opt2: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_pure_combine)]
+pub(crate) struct AsmPureCombine {
+    #[primary_span]
+    pub(crate) spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_pure_no_output)]
+pub(crate) struct AsmPureNoOutput {
+    #[primary_span]
+    pub(crate) spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_modifier_invalid)]
+pub(crate) struct AsmModifierInvalid {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_runner_invalid)]
+pub(crate) struct TestRunnerInvalid {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_runner_nargs)]
+pub(crate) struct TestRunnerNargs {
+    #[primary_span]
+    pub(crate) span: Span,
+}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index f0fc61d7c4f..f17df5b0a83 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -141,13 +141,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
                         args: args
                             .named_args()
                             .iter()
-                            .filter_map(|a| {
-                                if let Some(ident) = a.kind.ident() {
-                                    Some((a, ident))
-                                } else {
-                                    None
-                                }
-                            })
+                            .filter_map(|a| a.kind.ident().map(|ident| (a, ident)))
                             .map(|(arg, n)| n.span.to(arg.expr.span))
                             .collect(),
                     });
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 37fbd03a6a2..8f86ef44aa3 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -24,7 +24,7 @@ use crate::deriving::*;
 use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
 use rustc_span::symbol::sym;
 
 mod alloc_error_handler;
@@ -45,6 +45,7 @@ mod format;
 mod format_foreign;
 mod global_allocator;
 mod log_syntax;
+mod offset_of;
 mod source_util;
 mod test;
 mod trace_macros;
@@ -92,6 +93,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         line: source_util::expand_line,
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
+        offset_of: offset_of::expand_offset_of,
         option_env: env::expand_option_env,
         core_panic: edition_panic::expand_panic,
         std_panic: edition_panic::expand_panic,
diff --git a/compiler/rustc_builtin_macros/src/offset_of.rs b/compiler/rustc_builtin_macros/src/offset_of.rs
new file mode 100644
index 00000000000..0ef3e000e41
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/offset_of.rs
@@ -0,0 +1,99 @@
+use rustc_ast as ast;
+use rustc_ast::ptr::P;
+use rustc_ast::token;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_errors::PResult;
+use rustc_expand::base::{self, *};
+use rustc_macros::Diagnostic;
+use rustc_parse::parser::Parser;
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_offset_of_expected_field)]
+struct ExpectedField {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_offset_of_expected_two_args)]
+struct ExpectedTwoArgs {
+    #[primary_span]
+    span: Span,
+}
+
+fn parse_field<'a>(cx: &ExtCtxt<'a>, p: &mut Parser<'a>) -> PResult<'a, Ident> {
+    let token = p.token.uninterpolate();
+    let field = match token.kind {
+        token::Ident(name, _) => Ident::new(name, token.span),
+        token::Literal(token::Lit { kind: token::Integer, symbol, suffix: None }) => {
+            Ident::new(symbol, token.span)
+        }
+        _ => return Err(cx.create_err(ExpectedField { span: p.token.span })),
+    };
+
+    p.bump();
+
+    Ok(field)
+}
+
+fn parse_args<'a>(
+    cx: &mut ExtCtxt<'a>,
+    sp: Span,
+    tts: TokenStream,
+) -> PResult<'a, (P<ast::Ty>, P<[Ident]>)> {
+    let mut p = cx.new_parser_from_tts(tts);
+
+    let container = p.parse_ty()?;
+
+    p.expect(&token::Comma)?;
+
+    if p.eat(&token::Eof) {
+        return Err(cx.create_err(ExpectedTwoArgs { span: sp }));
+    }
+
+    let mut fields = Vec::new();
+
+    loop {
+        let field = parse_field(cx, &mut p)?;
+        fields.push(field);
+
+        if p.eat(&token::Dot) {
+            continue;
+        }
+
+        p.eat(&token::Comma);
+
+        if !p.eat(&token::Eof) {
+            return Err(cx.create_err(ExpectedTwoArgs { span: sp }));
+        }
+
+        break;
+    }
+
+    Ok((container, fields.into()))
+}
+
+pub fn expand_offset_of<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn base::MacResult + 'cx> {
+    match parse_args(cx, sp, tts) {
+        Ok((container, fields)) => {
+            let expr = P(ast::Expr {
+                id: ast::DUMMY_NODE_ID,
+                kind: ast::ExprKind::OffsetOf(container, fields),
+                span: sp,
+                attrs: ast::AttrVec::new(),
+                tokens: None,
+            });
+
+            MacEager::expr(expr)
+        }
+        Err(mut err) => {
+            err.emit();
+            DummyResult::any(sp)
+        }
+    }
+}
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 79d8be2484b..49ee276af4e 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -1,3 +1,4 @@
+use crate::errors;
 /// The expansion from a test function to the appropriate test struct for libtest
 /// 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};
@@ -40,12 +41,7 @@ pub fn expand_test_case(
             unreachable!()
         },
         _ => {
-            ecx.struct_span_err(
-                anno_item.span(),
-                "`#[test_case]` attribute is only allowed on items",
-            )
-            .emit();
-
+            ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
             return vec![];
         }
     };
@@ -533,15 +529,11 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
     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();
+                sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" });
                 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();
+                sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" });
                 return false;
             }
 
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 80f497333a6..be4ba66c082 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -19,6 +19,8 @@ use tracing::debug;
 
 use std::{iter, mem};
 
+use crate::errors;
+
 #[derive(Clone)]
 struct Test {
     span: Span,
@@ -385,11 +387,11 @@ fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast
         [single] => match single.meta_item() {
             Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
             _ => {
-                sd.struct_span_err(span, "`test_runner` argument must be a path").emit();
+                sd.emit_err(errors::TestRunnerInvalid { span });
             }
         },
         _ => {
-            sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit();
+            sd.emit_err(errors::TestRunnerNargs { span });
         }
     }
     None