Specify macro is invalid in certain contexts
This commit is contained in:
parent
8771282d4e
commit
287db04636
@ -457,6 +457,12 @@ parse_loop_else = `{$loop_kind}...else` loops are not supported
|
|||||||
.note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
|
.note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
|
||||||
.loop_keyword = `else` is attached to this loop
|
.loop_keyword = `else` is attached to this loop
|
||||||
|
|
||||||
|
parse_macro_expands_to_adt_field = macros cannot expand to {$adt_ty} fields
|
||||||
|
|
||||||
|
parse_macro_expands_to_enum_variant = macros cannot expand to enum variants
|
||||||
|
|
||||||
|
parse_macro_expands_to_match_arm = macros cannot expand to match arms
|
||||||
|
|
||||||
parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
|
parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
|
||||||
.suggestion = remove the visibility
|
.suggestion = remove the visibility
|
||||||
.help = try adjusting the macro to put `{$vis}` inside the invocation
|
.help = try adjusting the macro to put `{$vis}` inside the invocation
|
||||||
|
@ -1800,6 +1800,12 @@ pub struct UnknownPrefix<'a> {
|
|||||||
pub sugg: Option<UnknownPrefixSugg>,
|
pub sugg: Option<UnknownPrefixSugg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[note(parse_macro_expands_to_adt_field)]
|
||||||
|
pub struct MacroExpandsToAdtField<'a> {
|
||||||
|
pub adt_ty: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub enum UnknownPrefixSugg {
|
pub enum UnknownPrefixSugg {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
|
@ -2591,6 +2591,7 @@ pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
|
|||||||
pub(crate) fn maybe_recover_unexpected_comma(
|
pub(crate) fn maybe_recover_unexpected_comma(
|
||||||
&mut self,
|
&mut self,
|
||||||
lo: Span,
|
lo: Span,
|
||||||
|
is_mac_invoc: bool,
|
||||||
rt: CommaRecoveryMode,
|
rt: CommaRecoveryMode,
|
||||||
) -> PResult<'a, ()> {
|
) -> PResult<'a, ()> {
|
||||||
if self.token != token::Comma {
|
if self.token != token::Comma {
|
||||||
@ -2611,24 +2612,28 @@ pub(crate) fn maybe_recover_unexpected_comma(
|
|||||||
let seq_span = lo.to(self.prev_token.span);
|
let seq_span = lo.to(self.prev_token.span);
|
||||||
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
|
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
|
||||||
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
|
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
|
||||||
err.multipart_suggestion(
|
if is_mac_invoc {
|
||||||
format!(
|
err.note(fluent::parse_macro_expands_to_match_arm);
|
||||||
"try adding parentheses to match on a tuple{}",
|
} else {
|
||||||
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
|
err.multipart_suggestion(
|
||||||
),
|
format!(
|
||||||
vec![
|
"try adding parentheses to match on a tuple{}",
|
||||||
(seq_span.shrink_to_lo(), "(".to_string()),
|
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
|
||||||
(seq_span.shrink_to_hi(), ")".to_string()),
|
),
|
||||||
],
|
vec![
|
||||||
Applicability::MachineApplicable,
|
(seq_span.shrink_to_lo(), "(".to_string()),
|
||||||
);
|
(seq_span.shrink_to_hi(), ")".to_string()),
|
||||||
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
|
],
|
||||||
err.span_suggestion(
|
|
||||||
seq_span,
|
|
||||||
"...or a vertical bar to match on multiple alternatives",
|
|
||||||
seq_snippet.replace(',', " |"),
|
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
|
||||||
|
err.span_suggestion(
|
||||||
|
seq_span,
|
||||||
|
"...or a vertical bar to match on multiple alternatives",
|
||||||
|
seq_snippet.replace(',', " |"),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err)
|
Err(err)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::errors;
|
|
||||||
|
|
||||||
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
|
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
|
||||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||||
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
|
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
|
||||||
|
use crate::errors::{self, MacroExpandsToAdtField};
|
||||||
|
use crate::fluent_generated as fluent;
|
||||||
use ast::StaticItem;
|
use ast::StaticItem;
|
||||||
use rustc_ast::ast::*;
|
use rustc_ast::ast::*;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
@ -1342,6 +1342,13 @@ fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
|
|||||||
}
|
}
|
||||||
let ident = this.parse_field_ident("enum", vlo)?;
|
let ident = this.parse_field_ident("enum", vlo)?;
|
||||||
|
|
||||||
|
if this.token == token::Not {
|
||||||
|
return this.unexpected().map_err(|mut err| {
|
||||||
|
err.note(fluent::parse_macro_expands_to_enum_variant);
|
||||||
|
err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
|
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
|
||||||
// Parse a struct variant.
|
// Parse a struct variant.
|
||||||
let (fields, recovered) =
|
let (fields, recovered) =
|
||||||
@ -1369,7 +1376,7 @@ fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
|
|||||||
|
|
||||||
Ok((Some(vr), TrailingToken::MaybeComma))
|
Ok((Some(vr), TrailingToken::MaybeComma))
|
||||||
},
|
},
|
||||||
).map_err(|mut err|{
|
).map_err(|mut err| {
|
||||||
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
|
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
@ -1691,9 +1698,10 @@ fn parse_single_struct_field(
|
|||||||
Ok(a_var)
|
Ok(a_var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
|
fn expect_field_ty_separator(&mut self, adt_ty: &str) -> PResult<'a, ()> {
|
||||||
if let Err(mut err) = self.expect(&token::Colon) {
|
if let Err(mut err) = self.expect(&token::Colon) {
|
||||||
let sm = self.sess.source_map();
|
let sm = self.sess.source_map();
|
||||||
|
let mac_invoc = self.token.kind == token::Not;
|
||||||
let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
|
let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
|
||||||
let semi_typo = self.token.kind == token::Semi
|
let semi_typo = self.token.kind == token::Semi
|
||||||
&& self.look_ahead(1, |t| {
|
&& self.look_ahead(1, |t| {
|
||||||
@ -1705,7 +1713,9 @@ fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
|
|||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if eq_typo || semi_typo {
|
if mac_invoc {
|
||||||
|
err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
|
||||||
|
} else if eq_typo || semi_typo {
|
||||||
self.bump();
|
self.bump();
|
||||||
// Gracefully handle small typos.
|
// Gracefully handle small typos.
|
||||||
err.span_suggestion_short(
|
err.span_suggestion_short(
|
||||||
@ -1713,8 +1723,8 @@ fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
|
|||||||
"field names and their types are separated with `:`",
|
"field names and their types are separated with `:`",
|
||||||
":",
|
":",
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
)
|
||||||
err.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
@ -1731,7 +1741,7 @@ fn parse_name_and_ty(
|
|||||||
attrs: AttrVec,
|
attrs: AttrVec,
|
||||||
) -> PResult<'a, FieldDef> {
|
) -> PResult<'a, FieldDef> {
|
||||||
let name = self.parse_field_ident(adt_ty, lo)?;
|
let name = self.parse_field_ident(adt_ty, lo)?;
|
||||||
self.expect_field_ty_separator()?;
|
self.expect_field_ty_separator(adt_ty)?;
|
||||||
let ty = self.parse_ty()?;
|
let ty = self.parse_ty()?;
|
||||||
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
|
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
|
||||||
self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
|
self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
|
||||||
|
@ -135,7 +135,11 @@ fn parse_pat_allow_top_alt_inner(
|
|||||||
// Parse the first pattern (`p_0`).
|
// Parse the first pattern (`p_0`).
|
||||||
let mut first_pat = self.parse_pat_no_top_alt(expected)?;
|
let mut first_pat = self.parse_pat_no_top_alt(expected)?;
|
||||||
if rc == RecoverComma::Yes {
|
if rc == RecoverComma::Yes {
|
||||||
self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
|
self.maybe_recover_unexpected_comma(
|
||||||
|
first_pat.span,
|
||||||
|
matches!(first_pat.kind, PatKind::MacCall(_)),
|
||||||
|
rt,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the next token is not a `|`,
|
// If the next token is not a `|`,
|
||||||
@ -177,7 +181,11 @@ fn parse_pat_allow_top_alt_inner(
|
|||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
if rc == RecoverComma::Yes {
|
if rc == RecoverComma::Yes {
|
||||||
self.maybe_recover_unexpected_comma(pat.span, rt)?;
|
self.maybe_recover_unexpected_comma(
|
||||||
|
pat.span,
|
||||||
|
matches!(pat.kind, PatKind::MacCall(_)),
|
||||||
|
rt,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
pats.push(pat);
|
pats.push(pat);
|
||||||
}
|
}
|
||||||
|
16
tests/ui/parser/macro/macro-expand-to-field-2.rs
Normal file
16
tests/ui/parser/macro/macro-expand-to-field-2.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
macro_rules! field {
|
||||||
|
($name:ident:$type:ty) => {
|
||||||
|
$name:$type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EnumVariantField {
|
||||||
|
Named { //~ NOTE while parsing this struct
|
||||||
|
field!(oopsies:()), //~ NOTE macros cannot expand to struct fields
|
||||||
|
//~^ ERROR expected `:`, found `!`
|
||||||
|
//~^^ ERROR expected `,`, or `}`, found `(`
|
||||||
|
//~^^^ NOTE expected `:`
|
||||||
|
},
|
||||||
|
}
|
18
tests/ui/parser/macro/macro-expand-to-field-2.stderr
Normal file
18
tests/ui/parser/macro/macro-expand-to-field-2.stderr
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
error: expected `:`, found `!`
|
||||||
|
--> $DIR/macro-expand-to-field-2.rs:11:14
|
||||||
|
|
|
||||||
|
LL | field!(oopsies:()),
|
||||||
|
| ^ expected `:`
|
||||||
|
|
|
||||||
|
= note: macros cannot expand to struct fields
|
||||||
|
|
||||||
|
error: expected `,`, or `}`, found `(`
|
||||||
|
--> $DIR/macro-expand-to-field-2.rs:11:15
|
||||||
|
|
|
||||||
|
LL | Named {
|
||||||
|
| ----- while parsing this struct
|
||||||
|
LL | field!(oopsies:()),
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
15
tests/ui/parser/macro/macro-expand-to-field-3.rs
Normal file
15
tests/ui/parser/macro/macro-expand-to-field-3.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
macro_rules! field {
|
||||||
|
($name:ident:$type:ty) => {
|
||||||
|
$name:$type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
union EnumVariantField { //~ NOTE while parsing this union
|
||||||
|
A: u32,
|
||||||
|
field!(oopsies:()), //~ NOTE macros cannot expand to union fields
|
||||||
|
//~^ ERROR expected `:`, found `!`
|
||||||
|
//~^^ ERROR expected `,`, or `}`, found `(`
|
||||||
|
//~^^^ NOTE expected `:`
|
||||||
|
}
|
19
tests/ui/parser/macro/macro-expand-to-field-3.stderr
Normal file
19
tests/ui/parser/macro/macro-expand-to-field-3.stderr
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
error: expected `:`, found `!`
|
||||||
|
--> $DIR/macro-expand-to-field-3.rs:11:10
|
||||||
|
|
|
||||||
|
LL | field!(oopsies:()),
|
||||||
|
| ^ expected `:`
|
||||||
|
|
|
||||||
|
= note: macros cannot expand to union fields
|
||||||
|
|
||||||
|
error: expected `,`, or `}`, found `(`
|
||||||
|
--> $DIR/macro-expand-to-field-3.rs:11:11
|
||||||
|
|
|
||||||
|
LL | union EnumVariantField {
|
||||||
|
| ---------------- while parsing this union
|
||||||
|
LL | A: u32,
|
||||||
|
LL | field!(oopsies:()),
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
26
tests/ui/parser/macro/macro-expand-to-field.rs
Normal file
26
tests/ui/parser/macro/macro-expand-to-field.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
macro_rules! field {
|
||||||
|
($name:ident:$type:ty) => {
|
||||||
|
$name:$type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! variant {
|
||||||
|
($name:ident) => {
|
||||||
|
$name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct { //~ NOTE while parsing this struct
|
||||||
|
field!(bar:u128), //~ NOTE macros cannot expand to struct fields
|
||||||
|
//~^ ERROR expected `:`, found `!`
|
||||||
|
//~^^ NOTE expected `:`
|
||||||
|
//~^^^ ERROR expected `,`, or `}`, found `(`
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EnumVariant { //~ NOTE while parsing this enum
|
||||||
|
variant!(whoops), //~ NOTE macros cannot expand to enum variants
|
||||||
|
//~^ ERROR unexpected token: `!`
|
||||||
|
//~^^ NOTE unexpected token after this
|
||||||
|
}
|
29
tests/ui/parser/macro/macro-expand-to-field.stderr
Normal file
29
tests/ui/parser/macro/macro-expand-to-field.stderr
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
error: expected `:`, found `!`
|
||||||
|
--> $DIR/macro-expand-to-field.rs:16:10
|
||||||
|
|
|
||||||
|
LL | field!(bar:u128),
|
||||||
|
| ^ expected `:`
|
||||||
|
|
|
||||||
|
= note: macros cannot expand to struct fields
|
||||||
|
|
||||||
|
error: expected `,`, or `}`, found `(`
|
||||||
|
--> $DIR/macro-expand-to-field.rs:16:11
|
||||||
|
|
|
||||||
|
LL | struct Struct {
|
||||||
|
| ------ while parsing this struct
|
||||||
|
LL | field!(bar:u128),
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: unexpected token: `!`
|
||||||
|
--> $DIR/macro-expand-to-field.rs:23:12
|
||||||
|
|
|
||||||
|
LL | enum EnumVariant {
|
||||||
|
| ----------- while parsing this enum
|
||||||
|
LL | variant!(whoops),
|
||||||
|
| ^ unexpected token after this
|
||||||
|
|
|
||||||
|
= note: macros cannot expand to enum variants
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
15
tests/ui/parser/macro/macro-expand-to-match-arm.rs
Normal file
15
tests/ui/parser/macro/macro-expand-to-match-arm.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
macro_rules! arm {
|
||||||
|
($pattern:pat => $block:block) => {
|
||||||
|
$pattern => $block
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Some(1);
|
||||||
|
match x {
|
||||||
|
Some(1) => {},
|
||||||
|
arm!(None => {}), //~ NOTE macros cannot expand to match arms
|
||||||
|
//~^ ERROR unexpected `,` in pattern
|
||||||
|
_ => {},
|
||||||
|
};
|
||||||
|
}
|
10
tests/ui/parser/macro/macro-expand-to-match-arm.stderr
Normal file
10
tests/ui/parser/macro/macro-expand-to-match-arm.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
error: unexpected `,` in pattern
|
||||||
|
--> $DIR/macro-expand-to-match-arm.rs:11:25
|
||||||
|
|
|
||||||
|
LL | arm!(None => {}),
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: macros cannot expand to match arms
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Reference in New Issue
Block a user