mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 22:16:53 +00:00
Rollup merge of #110694 - est31:builtin, r=petrochenkov
Implement builtin # syntax and use it for offset_of!(...) Add `builtin #` syntax to the parser, as well as a generic infrastructure to support both item and expression position builtin syntaxes. The PR also uses this infrastructure for the implementation of the `offset_of!` macro, added by #106934. cc `@petrochenkov` `@DrMeepster` cc #110680 `builtin #` tracking issue cc #106655 `offset_of!` tracking issue
This commit is contained in:
commit
dbd090c655
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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<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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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 <https://github.com/rust-lang/rust/issues/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
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
@ -1766,6 +1768,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<Expr>> {
|
||||
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<T>(
|
||||
&mut self,
|
||||
parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
|
||||
) -> 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<Expr>> {
|
||||
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.
|
||||
@ -2835,6 +2892,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<Expr>> {
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
|
@ -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<ItemInfo>> {
|
||||
// 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`
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -1315,9 +1315,9 @@ impl<T> 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).+)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -22,13 +22,13 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:11
|
||||
_1 = OffsetOf(Gamma<T>, [0]); // scope 0 at $DIR/offset_of.rs:+1:14: +1:37
|
||||
_1 = OffsetOf(Gamma<T>, [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<T>, [1]); // scope 1 at $DIR/offset_of.rs:+2:14: +2:37
|
||||
_2 = OffsetOf(Gamma<T>, [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<T>, [1]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:37
|
||||
_3 = OffsetOf(Delta<T>, [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<T>, [2]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:37
|
||||
_4 = OffsetOf(Delta<T>, [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
|
||||
|
7
tests/ui/feature-gates/feature-gate-builtin_syntax.rs
Normal file
7
tests/ui/feature-gates/feature-gate-builtin_syntax.rs
Normal file
@ -0,0 +1,7 @@
|
||||
struct Foo {
|
||||
v: u8,
|
||||
w: u8,
|
||||
}
|
||||
fn main() {
|
||||
builtin # offset_of(Foo, v); //~ ERROR `builtin #` syntax is unstable
|
||||
}
|
12
tests/ui/feature-gates/feature-gate-builtin_syntax.stderr
Normal file
12
tests/ui/feature-gates/feature-gate-builtin_syntax.stderr
Normal file
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
@ -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, }
|
||||
|
@ -1,20 +1,59 @@
|
||||
error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `<eof>`
|
||||
--> $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: aborting due to 3 previous errors
|
||||
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 7 previous errors
|
||||
|
||||
|
44
tests/ui/offset-of/offset-of-builtin.rs
Normal file
44
tests/ui/offset-of/offset-of-builtin.rs
Normal file
@ -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, }
|
65
tests/ui/offset-of/offset-of-builtin.stderr
Normal file
65
tests/ui/offset-of/offset-of-builtin.stderr
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
9
tests/ui/parser/builtin-syntax.rs
Normal file
9
tests/ui/parser/builtin-syntax.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![feature(builtin_syntax)]
|
||||
|
||||
fn main() {
|
||||
builtin # foobar(); //~ ERROR unknown `builtin #` construct
|
||||
}
|
||||
|
||||
fn not_identifier() {
|
||||
builtin # {}(); //~ ERROR expected identifier after
|
||||
}
|
14
tests/ui/parser/builtin-syntax.stderr
Normal file
14
tests/ui/parser/builtin-syntax.stderr
Normal file
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user