Skip to content

rustc_hir: add Expr! pattern macro and try it out in a couple places. #68320

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

Closed
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions src/librustc_hir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,18 @@ pub struct Expr<'hir> {
pub span: Span,
}

/// `Expr` pattern alias to facilitate pattern-matching.
///
/// Usage examples:
/// * `hir::Expr!(Unary(_, hir::Expr!(Lit(_))))`
/// * `hir::Expr! { Loop(..), hir_id: loop_id }`
pub macro Expr($variant:ident $($rest:tt)*) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use pat fragment?

Copy link
Member Author

@eddyb eddyb Jan 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because then people would have to write hir::ExprKind::Foo instead of Foo, inside the macro arguments.
And also this allows some trickery like matching on the hir_id (although maybe that should be done with @ instead of this EDIT: nevermind, @ needs a binding on one side, it's not a conjunction of patterns).

$crate::hir::Expr {
kind: $crate::hir::ExprKind::$variant $($rest)*,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$crate -> crate here and one line above, macros are fully hygienic and don't need $crate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to be conservative, presumably I can even write Expr without the full module path.

..
}
}

// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
rustc_data_structures::static_assert_size!(Expr<'static>, 64);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_hir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#![feature(crate_visibility_modifier)]
#![feature(const_fn)] // For the unsizing cast on `&[]`
#![feature(decl_macro)]
#![feature(in_band_lifetimes)]
#![feature(specialization)]
#![recursion_limit = "256"]
Expand Down
45 changes: 25 additions & 20 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1885,10 +1885,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
const TRANSMUTE_PATH: &[Symbol] =
&[sym::core, sym::intrinsics, kw::Invalid, sym::transmute];

if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
match expr {
// Find calls to `mem::{uninitialized,zeroed}` methods.
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
hir::Expr!(Call(hir::Expr! { Path(ref qpath), hir_id: path_hir_id }, ref args)) => {
let def_id = cx.tables.qpath_res(qpath, *path_hir_id).opt_def_id()?;

if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
return Some(InitKind::Zeroed);
Expand All @@ -1900,25 +1900,30 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
}
}
}
} else if let hir::ExprKind::MethodCall(_, _, ref args) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id =
cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;

if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
return Some(InitKind::Zeroed);
} else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
return Some(InitKind::Uninit);
}
}

// Find problematic calls to `MaybeUninit::assume_init`, where
// the `self` parameter is one of the dangerous constructors.
hir::Expr!(
MethodCall(
_,
_,
[hir::Expr!(Call(hir::Expr! { Path(ref qpath), hir_id: path_hir_id }, _)), ..],
)
) if cx.tcx.is_diagnostic_item(
sym::assume_init,
cx.tables.type_dependent_def_id(expr.hir_id)?,
) =>
{
let def_id = cx.tables.qpath_res(qpath, *path_hir_id).opt_def_id()?;

if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
return Some(InitKind::Zeroed);
} else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
return Some(InitKind::Uninit);
}
}

_ => {}
}

None
Expand Down
1 change: 1 addition & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#![feature(crate_visibility_modifier)]
#![feature(never_type)]
#![feature(nll)]
#![feature(slice_patterns)]
#![recursion_limit = "256"]

#[macro_use]
Expand Down
13 changes: 5 additions & 8 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2703,14 +2703,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {

let expr = &tcx.hir().body(ast_const.body).value;

let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
hir::ExprKind::Lit(ref lit) => {
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
}
_ => None,
},
let lit_input = match expr {
hir::Expr!(Lit(ref lit)) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::Expr!(Unary(hir::UnOp::UnNeg, hir::Expr!(Lit(ref lit)))) => {
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
}
_ => None,
};

Expand Down