Add SEMICOLON_IN_EXPRESSIONS_FROM_MACROS
lint
cc #79813 This PR adds an allow-by-default future-compatibility lint `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS`. It fires when a trailing semicolon in a macro body is ignored due to the macro being used in expression position: ```rust macro_rules! foo { () => { true; // WARN } } fn main() { let val = match true { true => false, _ => foo!() }; } ``` The lint takes its level from the macro call site, and can be allowed for a particular macro by adding `#[allow(semicolon_in_expressions_from_macros)]`. The lint is set to warn for all internal rustc crates (when being built by a stage1 compiler). After the next beta bump, we can enable the lint for the bootstrap compiler as well.
This commit is contained in:
parent
0e190206e2
commit
f9025512e7
10 changed files with 150 additions and 1 deletions
|
@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
|
|||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
|
|
|
@ -11,12 +11,14 @@ use crate::mbe::transcribe::transcribe;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::builtin::SEMICOLON_IN_EXPRESSIONS_FROM_MACROS;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_session::Session;
|
||||
|
@ -37,6 +39,7 @@ crate struct ParserAnyMacro<'a> {
|
|||
site_span: Span,
|
||||
/// The ident of the macro we're parsing
|
||||
macro_ident: Ident,
|
||||
lint_node_id: NodeId,
|
||||
arm_span: Span,
|
||||
}
|
||||
|
||||
|
@ -110,7 +113,8 @@ fn emit_frag_parse_err(
|
|||
|
||||
impl<'a> ParserAnyMacro<'a> {
|
||||
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, lint_node_id, arm_span } =
|
||||
*self;
|
||||
let snapshot = &mut parser.clone();
|
||||
let fragment = match parse_ast_fragment(parser, kind) {
|
||||
Ok(f) => f,
|
||||
|
@ -124,6 +128,12 @@ impl<'a> ParserAnyMacro<'a> {
|
|||
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
|
||||
// but `m!()` is allowed in expression positions (cf. issue #34706).
|
||||
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
|
||||
parser.sess.buffer_lint(
|
||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
parser.token.span,
|
||||
lint_node_id,
|
||||
"trailing semicolon in macro used in expression position",
|
||||
);
|
||||
parser.bump();
|
||||
}
|
||||
|
||||
|
@ -276,6 +286,7 @@ fn generic_extension<'cx>(
|
|||
|
||||
let mut p = Parser::new(sess, tts, false, None);
|
||||
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.
|
||||
// Weird, but useful for X-macros.
|
||||
|
@ -287,6 +298,7 @@ fn generic_extension<'cx>(
|
|||
// macro leaves unparsed tokens.
|
||||
site_span: sp,
|
||||
macro_ident: name,
|
||||
lint_node_id,
|
||||
arm_span,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue