Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add offset_of! macro (RFC 3308) #106934

Merged
merged 10 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,7 @@ impl Expr {
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf,
ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
Expand Down Expand Up @@ -1469,6 +1470,9 @@ pub enum ExprKind {
/// Output of the `asm!()` macro.
InlineAsm(P<InlineAsm>),

/// Output of the `offset_of!()` macro.
OffsetOf(P<Ty>, P<[Ident]>),

/// A macro invocation; pre-expansion.
MacCall(P<MacCall>),

Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,12 @@ pub fn noop_visit_expr<T: MutVisitor>(
}
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
ExprKind::OffsetOf(container, fields) => {
vis.visit_ty(container);
for field in fields.iter_mut() {
vis.visit_ident(field);
}
}
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
ExprKind::Struct(se) => {
let StructExpr { qself, path, fields, rest } = se.deref_mut();
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_ast/src/util/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ pub enum ExprPrecedence {
Index,
Try,
InlineAsm,
OffsetOf,
Mac,
FormatArgs,

Expand Down Expand Up @@ -335,7 +336,8 @@ impl ExprPrecedence {
| ExprPrecedence::Try
| ExprPrecedence::InlineAsm
| ExprPrecedence::Mac
| ExprPrecedence::FormatArgs => PREC_POSTFIX,
| ExprPrecedence::FormatArgs
| ExprPrecedence::OffsetOf => PREC_POSTFIX,

// Never need parens
ExprPrecedence::Array
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,12 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),
ExprKind::FormatArgs(f) => visitor.visit_format_args(f),
ExprKind::OffsetOf(container, fields) => {
visitor.visit_ty(container);
for &field in fields {
visitor.visit_ident(field);
}
}
ExprKind::Yield(optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
}
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
self.lower_ty(
container,
&mut ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
),
self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),
),
ExprKind::Struct(se) => {
let rest = match &se.rest {
StructRest::Base(e) => Some(self.lower_expr(e)),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ enum ImplTraitPosition {
FieldTy,
Cast,
ImplSelf,
OffsetOf,
}

impl std::fmt::Display for ImplTraitPosition {
Expand Down Expand Up @@ -313,6 +314,7 @@ impl std::fmt::Display for ImplTraitPosition {
ImplTraitPosition::FieldTy => "field types",
ImplTraitPosition::Cast => "cast types",
ImplTraitPosition::ImplSelf => "impl headers",
ImplTraitPosition::OffsetOf => "`offset_of!` params",
};

write!(f, "{name}")
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,26 @@ impl<'a> State<'a> {
self.end();
self.pclose();
}
ast::ExprKind::OffsetOf(container, fields) => {
// FIXME: This should have its own syntax, distinct from a macro invocation.
self.word("offset_of!");
self.popen();
self.rbox(0, Inconsistent);
self.print_type(container);
self.word(",");
self.space();

if let Some((&first, rest)) = fields.split_first() {
self.print_ident(first);

for &field in rest {
self.word(".");
self.print_ident(field);
}
}

self.end();
}
ast::ExprKind::MacCall(m) => self.print_mac(m),
ast::ExprKind::Paren(e) => {
self.popen();
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2306,7 +2306,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Rvalue::AddressOf(..)
| Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..)
| Rvalue::Discriminant(..) => {}
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
}
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n ->
[one] argument
*[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
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/assert/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::If(_, _, _)
| ExprKind::IncludedBytes(..)
| ExprKind::InlineAsm(_)
| ExprKind::OffsetOf(_, _)
| ExprKind::Let(_, _, _)
| ExprKind::Lit(_)
| ExprKind::Loop(_, _, _)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
99 changes: 99 additions & 0 deletions compiler/rustc_builtin_macros/src/offset_of.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -781,12 +781,15 @@ fn codegen_stmt<'tcx>(
let operand = operand.load_scalar(fx);
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
}
Rvalue::NullaryOp(null_op, ty) => {
Rvalue::NullaryOp(ref null_op, ty) => {
assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
let layout = fx.layout_of(fx.monomorphize(ty));
let val = match null_op {
NullOp::SizeOf => layout.size.bytes(),
NullOp::AlignOf => layout.align.abi.bytes(),
NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(fx, fields.iter().map(|f| f.index())).bytes()
}
};
let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
lval.write_cvalue(fx, val);
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,13 +666,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}

mir::Rvalue::NullaryOp(null_op, ty) => {
mir::Rvalue::NullaryOp(ref null_op, ty) => {
let ty = self.monomorphize(ty);
assert!(bx.cx().type_is_sized(ty));
let layout = bx.cx().layout_of(ty);
let val = match null_op {
mir::NullOp::SizeOf => layout.size.bytes(),
mir::NullOp::AlignOf => layout.align.abi.bytes(),
mir::NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(bx.cx(), fields.iter().map(|f| f.index())).bytes()
}
};
let val = bx.cx().const_usize(val);
let tcx = self.cx.tcx();
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,20 +280,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_immediate(*val, &dest)?;
}

NullaryOp(null_op, ty) => {
NullaryOp(ref null_op, ty) => {
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
let layout = self.layout_of(ty)?;
if layout.is_unsized() {
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() {
// FIXME: This should be a span_bug (#80742)
self.tcx.sess.delay_span_bug(
beepster4096 marked this conversation as resolved.
Show resolved Hide resolved
self.frame().current_span(),
&format!("Nullary MIR operator called for unsized type {}", ty),
&format!("{null_op:?} MIR operator called for unsized type {ty}"),
);
throw_inval!(SizeOfUnsizedType(ty));
}
let val = match null_op {
mir::NullOp::SizeOf => layout.size.bytes(),
mir::NullOp::AlignOf => layout.align.abi.bytes(),
mir::NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(self, fields.iter().map(|f| f.index())).bytes()
}
};
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {

Rvalue::Cast(_, _, _) => {}

Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) => {}
Rvalue::ShallowInitBox(_, _) => {}

Rvalue::UnaryOp(_, operand) => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ impl<'tcx> Validator<'_, 'tcx> {
Rvalue::NullaryOp(op, _) => match op {
NullOp::SizeOf => {}
NullOp::AlignOf => {}
NullOp::OffsetOf(_) => {}
},

Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
Expand Down
Loading