diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b960671bf6e15..3d5056d82c56c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -603,6 +603,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); + gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index b74c59bca30c5..87c32ffce1214 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -556,8 +556,7 @@ impl<'a> State<'a> { self.pclose(); } ast::ExprKind::OffsetOf(container, fields) => { - // FIXME: This should have its own syntax, distinct from a macro invocation. - self.word("offset_of!"); + self.word("builtin # offset_of"); self.popen(); self.rbox(0, Inconsistent); self.print_type(container); diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 0d7cf7cdb267c..3b458b1d30ba7 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -150,10 +150,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n -> *[more] arguments } in format string, but {$desc} -builtin_macros_offset_of_expected_field = expected field - -builtin_macros_offset_of_expected_two_args = expected 2 arguments - builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c7da61d72b384..4e5edb4d6b1df 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -44,7 +44,6 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; -mod offset_of; mod source_util; mod test; mod trace_macros; @@ -92,7 +91,6 @@ 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 deleted file mode 100644 index 0ef3e000e414c..0000000000000 --- a/compiler/rustc_builtin_macros/src/offset_of.rs +++ /dev/null @@ -1,99 +0,0 @@ -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, 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 { - 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_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7e7df0e958438..a797dd94404c1 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -313,6 +313,8 @@ declare_features! ( (active, async_closure, "1.37.0", Some(62290), None), /// Allows async functions to be declared, implemented, and used in traits. (active, async_fn_in_trait, "1.66.0", Some(91611), None), + /// Allows builtin # foo() syntax + (active, builtin_syntax, "CURRENT_RUSTC_VERSION", Some(110680), None), /// Allows `c"foo"` literals. (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None), /// Treat `extern "C"` function as nounwind. diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index cd296dca133f5..711447a0af077 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -257,6 +257,10 @@ parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are inva .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access .tuple_exception_line_3 = see issue #60210 for more information +parse_expected_builtin_ident = expected identifier after `builtin #` + +parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}` + parse_non_string_abi_literal = non-string ABI literal .suggestion = specify the ABI with a string literal diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 010a13aefa420..0810f0efef98d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2644,3 +2644,18 @@ pub(crate) struct MalformedCfgAttr { pub span: Span, pub sugg: &'static str, } + +#[derive(Diagnostic)] +#[diag(parse_unknown_builtin_construct)] +pub(crate) struct UnknownBuiltinConstruct { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(parse_expected_builtin_ident)] +pub(crate) struct ExpectedBuiltinIdent { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 61396ee0d4aec..c1095512bd45d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1300,6 +1300,8 @@ impl<'a> Parser<'a> { }) } else if self.check(&token::OpenDelim(Delimiter::Bracket)) { self.parse_expr_array_or_repeat(Delimiter::Bracket) + } else if self.is_builtin() { + self.parse_expr_builtin() } else if self.check_path() { self.parse_expr_path_start() } else if self.check_keyword(kw::Move) @@ -1755,6 +1757,61 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } + /// Parse `builtin # ident(args,*)`. + fn parse_expr_builtin(&mut self) -> PResult<'a, P> { + self.parse_builtin(|this, lo, ident| { + if ident.name == sym::offset_of { + return Ok(Some(this.parse_expr_offset_of(lo)?)); + } + + Ok(None) + }) + } + + pub(crate) fn parse_builtin( + &mut self, + parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option>, + ) -> PResult<'a, T> { + let lo = self.token.span; + + self.bump(); // `builtin` + self.bump(); // `#` + + let Some((ident, false)) = self.token.ident() else { + let err = errors::ExpectedBuiltinIdent { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); + return Err(err); + }; + self.sess.gated_spans.gate(sym::builtin_syntax, ident.span); + self.bump(); + + self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?; + let ret = if let Some(res) = parse(self, lo, ident)? { + Ok(res) + } else { + let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name } + .into_diagnostic(&self.sess.span_diagnostic); + return Err(err); + }; + self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?; + + ret + } + + pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P> { + let container = self.parse_ty()?; + self.expect(&TokenKind::Comma)?; + + let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false }; + let (fields, _trailing, _recovered) = self.parse_seq_to_before_end( + &TokenKind::CloseDelim(Delimiter::Parenthesis), + seq_sep, + Parser::parse_field_name, + )?; + let span = lo.to(self.token.span); + Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into()))) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. @@ -2824,6 +2881,10 @@ impl<'a> Parser<'a> { }) } + pub(crate) fn is_builtin(&self) -> bool { + self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound) + } + /// Parses a `try {...}` expression (`try` token already eaten). fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P> { let (attrs, body) = self.parse_inner_attrs_and_block()?; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6ca88200dc51b..edfe316ec954e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -265,6 +265,9 @@ impl<'a> Parser<'a> { // UNION ITEM self.bump(); // `union` self.parse_item_union()? + } else if self.is_builtin() { + // BUILTIN# ITEM + return self.parse_item_builtin(); } else if self.eat_keyword(kw::Macro) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? @@ -434,6 +437,11 @@ impl<'a> Parser<'a> { } } + fn parse_item_builtin(&mut self) -> PResult<'a, Option> { + // To be expanded + return Ok(None); + } + /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1c17de337e833..a0bd086053e4e 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -90,7 +90,11 @@ impl<'a> Parser<'a> { attrs, errors::InvalidVariableDeclarationSub::UseLetNotVar, )? - } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { + } else if self.check_path() + && !self.token.is_qpath_start() + && !self.is_path_start_item() + && !self.is_builtin() + { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 58015d5d5026c..d54a615dd4ac0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -95,6 +95,7 @@ symbols! { // Weak keywords, have special meaning only in specific contexts. Auto: "auto", + Builtin: "builtin", Catch: "catch", Default: "default", MacroRules: "macro_rules", @@ -440,6 +441,7 @@ symbols! { breakpoint, bridge, bswap, + builtin_syntax, c_str, c_str_literals, c_unwind, diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 7d2f297152365..4913a6de91828 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1315,9 +1315,9 @@ impl SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` -#[unstable(feature = "offset_of", issue = "106655")] -#[rustc_builtin_macro] #[cfg(not(bootstrap))] +#[unstable(feature = "offset_of", issue = "106655")] +#[allow_internal_unstable(builtin_syntax)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - /* compiler built-in */ + builtin # offset_of($Container, $($fields).+) } diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff index e768a47a96d14..e3757941c8cd1 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff @@ -22,17 +22,17 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:10 -- _1 = OffsetOf(Alpha, [0]); // scope 0 at $DIR/offset_of.rs:+1:13: +1:33 -+ _1 = const 4_usize; // scope 0 at $DIR/offset_of.rs:+1:13: +1:33 +- _1 = OffsetOf(Alpha, [0]); // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _1 = const 4_usize; // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_2); // scope 1 at $DIR/offset_of.rs:+2:9: +2:10 -- _2 = OffsetOf(Alpha, [1]); // scope 1 at $DIR/offset_of.rs:+2:13: +2:33 -+ _2 = const 0_usize; // scope 1 at $DIR/offset_of.rs:+2:13: +2:33 +- _2 = OffsetOf(Alpha, [1]); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _2 = const 0_usize; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_3); // scope 2 at $DIR/offset_of.rs:+3:9: +3:11 -- _3 = OffsetOf(Alpha, [2, 0]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:36 -+ _3 = const 2_usize; // scope 2 at $DIR/offset_of.rs:+3:14: +3:36 +- _3 = OffsetOf(Alpha, [2, 0]); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _3 = const 2_usize; // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_4); // scope 3 at $DIR/offset_of.rs:+4:9: +4:11 -- _4 = OffsetOf(Alpha, [2, 1]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:36 -+ _4 = const 3_usize; // scope 3 at $DIR/offset_of.rs:+4:14: +4:36 +- _4 = OffsetOf(Alpha, [2, 1]); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _4 = const 3_usize; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/offset_of.rs:+0:15: +5:2 StorageDead(_4); // scope 3 at $DIR/offset_of.rs:+5:1: +5:2 StorageDead(_3); // scope 2 at $DIR/offset_of.rs:+5:1: +5:2 diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff index e40fdbd79d84e..4a655604cd183 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff @@ -22,13 +22,13 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:11 - _1 = OffsetOf(Gamma, [0]); // scope 0 at $DIR/offset_of.rs:+1:14: +1:37 + _1 = OffsetOf(Gamma, [0]); // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_2); // scope 1 at $DIR/offset_of.rs:+2:9: +2:11 - _2 = OffsetOf(Gamma, [1]); // scope 1 at $DIR/offset_of.rs:+2:14: +2:37 + _2 = OffsetOf(Gamma, [1]); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_3); // scope 2 at $DIR/offset_of.rs:+3:9: +3:11 - _3 = OffsetOf(Delta, [1]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:37 + _3 = OffsetOf(Delta, [1]); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_4); // scope 3 at $DIR/offset_of.rs:+4:9: +4:11 - _4 = OffsetOf(Delta, [2]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:37 + _4 = OffsetOf(Delta, [2]); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/offset_of.rs:+0:17: +5:2 StorageDead(_4); // scope 3 at $DIR/offset_of.rs:+5:1: +5:2 StorageDead(_3); // scope 2 at $DIR/offset_of.rs:+5:1: +5:2 diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.rs b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs new file mode 100644 index 0000000000000..832bb5a96bc3d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs @@ -0,0 +1,7 @@ +struct Foo { + v: u8, + w: u8, +} +fn main() { + builtin # offset_of(Foo, v); //~ ERROR `builtin #` syntax is unstable +} diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr b/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr new file mode 100644 index 0000000000000..3bc7848f66dd3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr @@ -0,0 +1,12 @@ +error[E0658]: `builtin #` syntax is unstable + --> $DIR/feature-gate-builtin_syntax.rs:6:15 + | +LL | builtin # offset_of(Foo, v); + | ^^^^^^^^^ + | + = note: see issue #110680 for more information + = help: add `#![feature(builtin_syntax)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 163b07454ecdf..5e66e33f8a273 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -3,7 +3,15 @@ use std::mem::offset_of; fn main() { - offset_of!(NotEnoughArguments); //~ ERROR expected one of - offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR expected 2 arguments - offset_of!(Container, field, too many arguments); //~ ERROR expected 2 arguments + offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation + offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation + offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too` + offset_of!(S, f); // compiles fine + offset_of!(S, f,); // also compiles fine + offset_of!(S, f.); //~ ERROR unexpected end of macro invocation + offset_of!(S, f.,); //~ ERROR expected identifier + offset_of!(S, f..); //~ ERROR no rules expected the token + offset_of!(S, f..,); //~ ERROR no rules expected the token } + +struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index ebecc982c5174..4275a89545f50 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -1,20 +1,59 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `` - --> $DIR/offset-of-arg-count.rs:6:16 +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(NotEnoughArguments); - | ^^^^^^^^^^^^^^^^^^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` + | ^ missing tokens in macro arguments + | +note: while trying to match `,` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: expected 2 arguments - --> $DIR/offset-of-arg-count.rs:7:5 +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:7:45 | LL | offset_of!(NotEnoughArgumentsWithAComma, ); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:tt` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: expected 2 arguments - --> $DIR/offset-of-arg-count.rs:8:5 +error: no rules expected the token `too` + --> $DIR/offset-of-arg-count.rs:8:34 | LL | offset_of!(Container, field, too many arguments); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:11:21 + | +LL | offset_of!(S, f.); + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:tt` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + +error: expected identifier, found `,` + --> $DIR/offset-of-arg-count.rs:12:21 + | +LL | offset_of!(S, f.,); + | ^ expected identifier + +error: no rules expected the token `..` + --> $DIR/offset-of-arg-count.rs:13:20 + | +LL | offset_of!(S, f..); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start + +error: no rules expected the token `..` + --> $DIR/offset-of-arg-count.rs:14:20 + | +LL | offset_of!(S, f..,); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start -error: aborting due to 3 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/offset-of/offset-of-builtin.rs b/tests/ui/offset-of/offset-of-builtin.rs new file mode 100644 index 0000000000000..1be9899887b4a --- /dev/null +++ b/tests/ui/offset-of/offset-of-builtin.rs @@ -0,0 +1,44 @@ +#![feature(builtin_syntax)] + +// For the exposed macro we already test these errors in the other files, +// but this test helps to make sure the builtin construct also errors. +// This has the same examples as offset-of-arg-count.rs + +fn main() { + builtin # offset_of(NotEnoughArguments); //~ ERROR expected one of +} +fn t1() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(NotEnoughArgumentsWithAComma, ); +} +fn t2() { + builtin # offset_of(Container, field, too many arguments); //~ ERROR expected identifier, found + //~| ERROR found `,` + //~| ERROR found `many` + //~| ERROR found `arguments` +} +fn t3() { + builtin # offset_of(S, f); // compiles fine +} +fn t4() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(S, f); +} +fn t5() { + builtin # offset_of(S, f.); //~ ERROR expected identifier +} +fn t6() { + builtin # offset_of(S, f.,); //~ ERROR expected identifier +} +fn t7() { + builtin # offset_of(S, f..); //~ ERROR expected one of +} +fn t8() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(S, f..,); +} + +struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-builtin.stderr b/tests/ui/offset-of/offset-of-builtin.stderr new file mode 100644 index 0000000000000..1a1f33cc613a7 --- /dev/null +++ b/tests/ui/offset-of/offset-of-builtin.stderr @@ -0,0 +1,65 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `)` + --> $DIR/offset-of-builtin.rs:8:43 + | +LL | builtin # offset_of(NotEnoughArguments); + | ^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` + +error: expected identifier, found `,` + --> $DIR/offset-of-builtin.rs:16:41 + | +LL | builtin # offset_of(Container, field, too many arguments); + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected one of `)` or `.`, found `,` + --> $DIR/offset-of-builtin.rs:16:41 + | +LL | builtin # offset_of(Container, field, too many arguments); + | ^ + | | + | expected one of `)` or `.` + | help: missing `.` + +error: expected one of `)` or `.`, found `many` + --> $DIR/offset-of-builtin.rs:16:47 + | +LL | builtin # offset_of(Container, field, too many arguments); + | -^^^^ expected one of `)` or `.` + | | + | help: missing `.` + +error: expected one of `)` or `.`, found `arguments` + --> $DIR/offset-of-builtin.rs:16:52 + | +LL | builtin # offset_of(Container, field, too many arguments); + | -^^^^^^^^^ expected one of `)` or `.` + | | + | help: missing `.` + +error: expected identifier, found `)` + --> $DIR/offset-of-builtin.rs:30:30 + | +LL | builtin # offset_of(S, f.); + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/offset-of-builtin.rs:33:30 + | +LL | builtin # offset_of(S, f.,); + | ^ expected identifier + +error: expected one of `)` or `.`, found `..` + --> $DIR/offset-of-builtin.rs:36:29 + | +LL | builtin # offset_of(S, f..); + | ^^ expected one of `)` or `.` + | +help: if you meant to bind the contents of the rest of the array pattern into `f`, use `@` + | +LL | builtin # offset_of(S, f @ ..); + | + + +error: aborting due to 8 previous errors + diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 8e88015b07a74..e6e0f49923620 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -5,6 +5,7 @@ LL | offset_of!(Alpha, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:31:5 @@ -13,6 +14,7 @@ LL | offset_of!(Beta, z); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `Extern` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:32:5 @@ -21,6 +23,7 @@ LL | offset_of!(Gamma, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `Extern` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/offset-of/offset-of-unstable.stderr b/tests/ui/offset-of/offset-of-unstable.stderr index 25811a061d7f0..c39882519a5da 100644 --- a/tests/ui/offset-of/offset-of-unstable.stderr +++ b/tests/ui/offset-of/offset-of-unstable.stderr @@ -33,6 +33,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:18:5 @@ -41,6 +42,7 @@ LL | offset_of!(StableWithUnstableField, unstable); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:20:5 @@ -49,6 +51,7 @@ LL | offset_of!(StableWithUnstableFieldType, stable.unstable); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:21:5 @@ -61,6 +64,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:26:5 @@ -73,6 +77,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors diff --git a/tests/ui/parser/builtin-syntax.rs b/tests/ui/parser/builtin-syntax.rs new file mode 100644 index 0000000000000..897dab8ec50ae --- /dev/null +++ b/tests/ui/parser/builtin-syntax.rs @@ -0,0 +1,9 @@ +#![feature(builtin_syntax)] + +fn main() { + builtin # foobar(); //~ ERROR unknown `builtin #` construct +} + +fn not_identifier() { + builtin # {}(); //~ ERROR expected identifier after +} diff --git a/tests/ui/parser/builtin-syntax.stderr b/tests/ui/parser/builtin-syntax.stderr new file mode 100644 index 0000000000000..ee3764a62216a --- /dev/null +++ b/tests/ui/parser/builtin-syntax.stderr @@ -0,0 +1,14 @@ +error: unknown `builtin #` construct `foobar` + --> $DIR/builtin-syntax.rs:4:5 + | +LL | builtin # foobar(); + | ^^^^^^^^^^^^^^^^ + +error: expected identifier after `builtin #` + --> $DIR/builtin-syntax.rs:8:15 + | +LL | builtin # {}(); + | ^ + +error: aborting due to 2 previous errors +