1
Fork 0

Compute a better lint_node_id during expansion

When we need to emit a lint at a macro invocation, we currently use the
`NodeId` of its parent definition (e.g. the enclosing function). This
means that any `#[allow]` / `#[deny]` attributes placed 'closer' to the
macro (e.g. on an enclosing block or statement) will have no effect.

This commit computes a better `lint_node_id` in `InvocationCollector`.
When we visit/flat_map an AST node, we assign it a `NodeId` (earlier
than we normally would), and store than `NodeId` in current
`ExpansionData`. When we collect a macro invocation, the current
`lint_node_id` gets cloned along with our `ExpansionData`, allowing it
to be used if we need to emit a lint later on.

This improves the handling of `#[allow]` / `#[deny]` for
`SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` and some `asm!`-related lints.
The 'legacy derive helpers' lint retains its current behavior
(I've inlined the now-removed `lint_node_id` function), since
there isn't an `ExpansionData` readily available.
This commit is contained in:
Aaron Hill 2021-07-14 18:24:12 -05:00
parent eb0b95b55a
commit ddd544856e
No known key found for this signature in database
GPG key ID: B4087E510E98B164
10 changed files with 139 additions and 65 deletions

View file

@ -455,7 +455,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
ecx.parse_sess().buffer_lint( ecx.parse_sess().buffer_lint(
lint::builtin::BAD_ASM_STYLE, lint::builtin::BAD_ASM_STYLE,
find_span(".intel_syntax"), find_span(".intel_syntax"),
ecx.resolver.lint_node_id(ecx.current_expansion.id), ecx.current_expansion.lint_node_id,
"avoid using `.intel_syntax`, Intel syntax is the default", "avoid using `.intel_syntax`, Intel syntax is the default",
); );
} }
@ -463,7 +463,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
ecx.parse_sess().buffer_lint( ecx.parse_sess().buffer_lint(
lint::builtin::BAD_ASM_STYLE, lint::builtin::BAD_ASM_STYLE,
find_span(".att_syntax"), find_span(".att_syntax"),
ecx.resolver.lint_node_id(ecx.current_expansion.id), ecx.current_expansion.lint_node_id,
"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead", "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
); );
} }

View file

@ -159,7 +159,7 @@ pub fn expand_include<'cx>(
} }
} }
Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) }) Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
} }
// include_str! : read the given file, insert it as a literal string expr // include_str! : read the given file, insert it as a literal string expr

View file

@ -869,9 +869,6 @@ pub trait ResolverExpand {
fn check_unused_macros(&mut self); fn check_unused_macros(&mut self);
/// Some parent node that is close enough to the given macro call.
fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId;
// Resolver interfaces for specific built-in macros. // Resolver interfaces for specific built-in macros.
/// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it? /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool; fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool;
@ -926,6 +923,8 @@ pub struct ExpansionData {
pub module: Rc<ModuleData>, pub module: Rc<ModuleData>,
pub dir_ownership: DirOwnership, pub dir_ownership: DirOwnership,
pub prior_type_ascription: Option<(Span, bool)>, pub prior_type_ascription: Option<(Span, bool)>,
/// Some parent node that is close to this macro call
pub lint_node_id: NodeId,
} }
type OnExternModLoaded<'a> = type OnExternModLoaded<'a> =
@ -971,6 +970,7 @@ impl<'a> ExtCtxt<'a> {
module: Default::default(), module: Default::default(),
dir_ownership: DirOwnership::Owned { relative: None }, dir_ownership: DirOwnership::Owned { relative: None },
prior_type_ascription: None, prior_type_ascription: None,
lint_node_id: ast::CRATE_NODE_ID,
}, },
force_mode: false, force_mode: false,
expansions: FxHashMap::default(), expansions: FxHashMap::default(),

View file

@ -1098,6 +1098,41 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
} }
} }
/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
/// This method assigns a `NodeId`, and sets that `NodeId`
/// as our current 'lint node id'. If a macro call is found
/// inside this AST node, we will use this AST node's `NodeId`
/// to emit lints associated with that macro (allowing
/// `#[allow]` / `#[deny]` to be applied close to
/// the macro invocation).
///
/// Do *not* call this for a macro AST node
/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
/// at these AST nodes, since they are removed and
/// replaced with the result of macro expansion.
///
/// All other `NodeId`s are assigned by `visit_id`.
/// * `self` is the 'self' parameter for the current method,
/// * `id` is a mutable reference to the `NodeId` field
/// of the current AST node.
/// * `closure` is a closure that executes the
/// `noop_visit_*` / `noop_flat_map_*` method
/// for the current AST node.
macro_rules! assign_id {
($self:ident, $id:expr, $closure:expr) => {{
let old_id = $self.cx.current_expansion.lint_node_id;
if $self.monotonic {
debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
let new_id = $self.cx.resolver.next_node_id();
*$id = new_id;
$self.cx.current_expansion.lint_node_id = new_id;
}
let ret = ($closure)();
$self.cx.current_expansion.lint_node_id = old_id;
ret
}};
}
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) { fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
self.cfg.configure_expr(expr); self.cfg.configure_expr(expr);
@ -1118,7 +1153,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
self.check_attributes(&expr.attrs); self.check_attributes(&expr.attrs);
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
} else { } else {
ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); assign_id!(self, &mut expr.id, || {
ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
});
expr expr
} }
}); });
@ -1133,7 +1170,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_arms(); .make_arms();
} }
noop_flat_map_arm(arm, self) assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
} }
fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
@ -1145,7 +1182,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_expr_fields(); .make_expr_fields();
} }
noop_flat_map_expr_field(field, self) assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
} }
fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
@ -1157,7 +1194,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_pat_fields(); .make_pat_fields();
} }
noop_flat_map_pat_field(fp, self) assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
} }
fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
@ -1169,7 +1206,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_params(); .make_params();
} }
noop_flat_map_param(p, self) assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
} }
fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
@ -1181,7 +1218,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_field_defs(); .make_field_defs();
} }
noop_flat_map_field_def(sf, self) assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
} }
fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
@ -1193,7 +1230,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_variants(); .make_variants();
} }
noop_flat_map_variant(variant, self) assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
} }
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
@ -1214,9 +1251,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_opt_expr() .make_opt_expr()
.map(|expr| expr.into_inner()) .map(|expr| expr.into_inner())
} else { } else {
Some({ assign_id!(self, &mut expr.id, || {
noop_visit_expr(&mut expr, self); Some({
expr noop_visit_expr(&mut expr, self);
expr
})
}) })
} }
}) })
@ -1225,7 +1264,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn visit_pat(&mut self, pat: &mut P<ast::Pat>) { fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
match pat.kind { match pat.kind {
PatKind::MacCall(_) => {} PatKind::MacCall(_) => {}
_ => return noop_visit_pat(pat, self), _ => {
return assign_id!(self, &mut pat.id, || noop_visit_pat(pat, self));
}
} }
visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) {
@ -1278,7 +1319,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
&mut self.cx.current_expansion.dir_ownership, &mut self.cx.current_expansion.dir_ownership,
DirOwnership::UnownedViaBlock, DirOwnership::UnownedViaBlock,
); );
noop_visit_block(block, self); assign_id!(self, &mut block.id, || noop_visit_block(block, self));
self.cx.current_expansion.dir_ownership = orig_dir_ownership; self.cx.current_expansion.dir_ownership = orig_dir_ownership;
} }
@ -1377,7 +1418,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
let orig_dir_ownership = let orig_dir_ownership =
mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership); mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
let result = noop_flat_map_item(item, self); let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
// Restore the module info. // Restore the module info.
self.cx.current_expansion.dir_ownership = orig_dir_ownership; self.cx.current_expansion.dir_ownership = orig_dir_ownership;
@ -1387,7 +1428,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
} }
_ => { _ => {
item.attrs = attrs; item.attrs = attrs;
noop_flat_map_item(item, self) // The crate root is special - don't assign an ID to it.
if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
} else {
noop_flat_map_item(item, self)
}
} }
} }
} }
@ -1411,7 +1457,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
_ => unreachable!(), _ => unreachable!(),
}) })
} }
_ => noop_flat_map_assoc_item(item, self), _ => {
assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
}
} }
} }
@ -1434,14 +1482,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
_ => unreachable!(), _ => unreachable!(),
}) })
} }
_ => noop_flat_map_assoc_item(item, self), _ => {
assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
}
} }
} }
fn visit_ty(&mut self, ty: &mut P<ast::Ty>) { fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
match ty.kind { match ty.kind {
ast::TyKind::MacCall(_) => {} ast::TyKind::MacCall(_) => {}
_ => return noop_visit_ty(ty, self), _ => return assign_id!(self, &mut ty.id, || noop_visit_ty(ty, self)),
}; };
visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) {
@ -1478,7 +1528,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
_ => unreachable!(), _ => unreachable!(),
}) })
} }
_ => noop_flat_map_foreign_item(foreign_item, self), _ => {
assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
foreign_item,
self
))
}
} }
} }
@ -1498,13 +1553,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
.make_generic_params(); .make_generic_params();
} }
noop_flat_map_generic_param(param, self) assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
} }
fn visit_id(&mut self, id: &mut ast::NodeId) { fn visit_id(&mut self, id: &mut ast::NodeId) {
if self.monotonic { // We may have already assigned a `NodeId`
debug_assert_eq!(*id, ast::DUMMY_NODE_ID); // by calling `assign_id`
*id = self.cx.resolver.next_node_id() if self.monotonic && *id == ast::DUMMY_NODE_ID {
*id = self.cx.resolver.next_node_id();
} }
} }
} }

View file

@ -289,7 +289,6 @@ fn generic_extension<'cx>(
let mut p = Parser::new(sess, tts, false, None); let mut p = Parser::new(sess, tts, false, None);
p.last_type_ascription = cx.current_expansion.prior_type_ascription; p.last_type_ascription = cx.current_expansion.prior_type_ascription;
let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
// Let the context choose how to interpret the result. // Let the context choose how to interpret the result.
// Weird, but useful for X-macros. // Weird, but useful for X-macros.
@ -301,7 +300,7 @@ fn generic_extension<'cx>(
// macro leaves unparsed tokens. // macro leaves unparsed tokens.
site_span: sp, site_span: sp,
macro_ident: name, macro_ident: name,
lint_node_id, lint_node_id: cx.current_expansion.lint_node_id,
arm_span, arm_span,
}); });
} }

View file

@ -274,7 +274,7 @@ impl<HCX> ToStableHashKey<HCX> for LintId {
} }
// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency // Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
#[derive(PartialEq)] #[derive(PartialEq, Debug)]
pub enum ExternDepSpec { pub enum ExternDepSpec {
Json(Json), Json(Json),
Raw(String), Raw(String),
@ -282,7 +282,7 @@ pub enum ExternDepSpec {
// This could be a closure, but then implementing derive trait // This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated). // becomes hacky (and it gets allocated).
#[derive(PartialEq)] #[derive(PartialEq, Debug)]
pub enum BuiltinLintDiagnostics { pub enum BuiltinLintDiagnostics {
Normal, Normal,
BareTraitObject(Span, /* is_global */ bool), BareTraitObject(Span, /* is_global */ bool),

View file

@ -281,7 +281,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
// Derives are not included when `invocations` are collected, so we have to add them here. // Derives are not included when `invocations` are collected, so we have to add them here.
let parent_scope = &ParentScope { derives, ..parent_scope }; let parent_scope = &ParentScope { derives, ..parent_scope };
let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion(); let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion();
let node_id = self.lint_node_id(eager_expansion_root); let node_id = invoc.expansion_data.lint_node_id;
let (ext, res) = self.smart_resolve_macro_path( let (ext, res) = self.smart_resolve_macro_path(
path, path,
kind, kind,
@ -348,14 +348,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
} }
} }
fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId {
// FIXME - make this more precise. This currently returns the NodeId of the
// nearest closing item - we should try to return the closest parent of the ExpnId
self.invocation_parents
.get(&expn_id)
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0])
}
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool { fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool {
self.containers_deriving_copy.contains(&expn_id) self.containers_deriving_copy.contains(&expn_id)
} }
@ -1105,9 +1097,13 @@ impl<'a> Resolver<'a> {
let seg = Segment::from_ident(ident); let seg = Segment::from_ident(ident);
check_consistency(self, &[seg], ident.span, kind, initial_res, res); check_consistency(self, &[seg], ident.span, kind, initial_res, res);
if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) { if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) {
let node_id = self
.invocation_parents
.get(&parent_scope.expansion)
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]);
self.lint_buffer.buffer_lint_with_diagnostic( self.lint_buffer.buffer_lint_with_diagnostic(
LEGACY_DERIVE_HELPERS, LEGACY_DERIVE_HELPERS,
self.lint_node_id(parent_scope.expansion), node_id,
ident.span, ident.span,
"derive helper attribute is used before it is introduced", "derive helper attribute is used before it is introduced",
BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span), BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span),

View file

@ -1,16 +1,10 @@
warning: avoid using `.intel_syntax`, Intel syntax is the default
--> $DIR/inline-syntax.rs:57:14
|
LL | global_asm!(".intel_syntax noprefix", "nop");
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(bad_asm_style)]` on by default
warning: avoid using `.intel_syntax`, Intel syntax is the default warning: avoid using `.intel_syntax`, Intel syntax is the default
--> $DIR/inline-syntax.rs:31:15 --> $DIR/inline-syntax.rs:31:15
| |
LL | asm!(".intel_syntax noprefix", "nop"); LL | asm!(".intel_syntax noprefix", "nop");
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(bad_asm_style)]` on by default
warning: avoid using `.intel_syntax`, Intel syntax is the default warning: avoid using `.intel_syntax`, Intel syntax is the default
--> $DIR/inline-syntax.rs:34:15 --> $DIR/inline-syntax.rs:34:15
@ -42,5 +36,11 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default
LL | .intel_syntax noprefix LL | .intel_syntax noprefix
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
warning: avoid using `.intel_syntax`, Intel syntax is the default
--> $DIR/inline-syntax.rs:57:14
|
LL | global_asm!(".intel_syntax noprefix", "nop");
| ^^^^^^^^^^^^^^^^^^^^^^
warning: 7 warnings emitted warning: 7 warnings emitted

View file

@ -1,14 +1,17 @@
// check-pass // check-pass
// edition:2018 // edition:2018
#![feature(stmt_expr_attributes)]
#![warn(semicolon_in_expressions_from_macros)] #![warn(semicolon_in_expressions_from_macros)]
#[allow(dead_code)] #[allow(dead_code)]
macro_rules! foo { macro_rules! foo {
($val:ident) => { ($val:ident) => {
true; //~ WARN trailing true; //~ WARN trailing semicolon in macro
//~| WARN this was previously //~| WARN this was previously accepted
//~| WARN trailing //~| WARN trailing semicolon in macro
//~| WARN this was previously //~| WARN this was previously accepted
//~| WARN trailing semicolon in macro
//~| WARN this was previously accepted
} }
} }
@ -18,17 +21,14 @@ async fn bar() {
} }
fn main() { fn main() {
// This `allow` doesn't work
#[allow(semicolon_in_expressions_from_macros)] #[allow(semicolon_in_expressions_from_macros)]
let _ = { let _ = {
foo!(first) foo!(first)
}; };
// This 'allow' doesn't work either
#[allow(semicolon_in_expressions_from_macros)] #[allow(semicolon_in_expressions_from_macros)]
let _ = foo!(second); let _ = foo!(second);
// But this 'allow' does
#[allow(semicolon_in_expressions_from_macros)] #[allow(semicolon_in_expressions_from_macros)]
fn inner() { fn inner() {
let _ = foo!(third); let _ = foo!(third);
@ -38,4 +38,14 @@ fn main() {
async { async {
let _ = foo!(fourth); let _ = foo!(fourth);
}; };
let _ = {
foo!(warn_in_block)
};
let _ = foo!(warn_in_expr);
// This `#[allow]` does not work, since the attribute gets dropped
// when we expand the macro
let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
} }

View file

@ -1,14 +1,14 @@
warning: trailing semicolon in macro used in expression position warning: trailing semicolon in macro used in expression position
--> $DIR/semicolon-in-expressions-from-macros.rs:8:13 --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
| |
LL | true; LL | true;
| ^ | ^
... ...
LL | foo!(first) LL | foo!(warn_in_block)
| ----------- in this macro invocation | ------------------- in this macro invocation
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/semicolon-in-expressions-from-macros.rs:3:9 --> $DIR/semicolon-in-expressions-from-macros.rs:4:9
| |
LL | #![warn(semicolon_in_expressions_from_macros)] LL | #![warn(semicolon_in_expressions_from_macros)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -17,17 +17,30 @@ LL | #![warn(semicolon_in_expressions_from_macros)]
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: trailing semicolon in macro used in expression position warning: trailing semicolon in macro used in expression position
--> $DIR/semicolon-in-expressions-from-macros.rs:8:13 --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
| |
LL | true; LL | true;
| ^ | ^
... ...
LL | let _ = foo!(second); LL | let _ = foo!(warn_in_expr);
| ------------ in this macro invocation | ------------------ in this macro invocation
| |
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 2 warnings emitted warning: trailing semicolon in macro used in expression position
--> $DIR/semicolon-in-expressions-from-macros.rs:9:13
|
LL | true;
| ^
...
LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
| ------------------------- in this macro invocation
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 3 warnings emitted