mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-09 16:37:36 +00:00
Auto merge of #66982 - Centril:rollup-yq2281i, r=Centril
Rollup of 6 pull requests Successful merges: - #66148 (Show the sign for signed ops on `exact_div`) - #66651 (Add `enclosing scope` parameter to `rustc_on_unimplemented`) - #66904 (Adding docs for keyword match, move) - #66935 (syntax: Unify macro and attribute arguments in AST) - #66941 (Remove `ord` lang item) - #66967 (Remove hack for top-level or-patterns in match checking) Failed merges: r? @ghost
This commit is contained in:
commit
f577b0ef6e
@ -534,7 +534,6 @@ impl<T: Ord> Ord for Reverse<T> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[lang = "ord"]
|
||||
#[doc(alias = "<")]
|
||||
#[doc(alias = ">")]
|
||||
#[doc(alias = "<=")]
|
||||
|
@ -5,19 +5,20 @@
|
||||
/// extracting those success or failure values from an existing instance and
|
||||
/// creating a new instance from a success or failure value.
|
||||
#[unstable(feature = "try_trait", issue = "42327")]
|
||||
#[rustc_on_unimplemented(
|
||||
#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
|
||||
on(all(
|
||||
any(from_method="from_error", from_method="from_ok"),
|
||||
from_desugaring="QuestionMark"),
|
||||
message="the `?` operator can only be used in {ItemContext} \
|
||||
that returns `Result` or `Option` \
|
||||
(or another type that implements `{Try}`)",
|
||||
label="cannot use the `?` operator in {ItemContext} that returns `{Self}`"),
|
||||
label="cannot use the `?` operator in {ItemContext} that returns `{Self}`",
|
||||
enclosing_scope="this function should return `Result` or `Option` to accept `?`"),
|
||||
on(all(from_method="into_result", from_desugaring="QuestionMark"),
|
||||
message="the `?` operator can only be applied to values \
|
||||
that implement `{Try}`",
|
||||
label="the `?` operator cannot be applied to type `{Self}`")
|
||||
)]
|
||||
))]
|
||||
#[doc(alias = "?")]
|
||||
pub trait Try {
|
||||
/// The type of this value when viewed as successful.
|
||||
|
@ -1003,7 +1003,7 @@ impl<'a> LoweringContext<'a> {
|
||||
AttrKind::Normal(ref item) => {
|
||||
AttrKind::Normal(AttrItem {
|
||||
path: item.path.clone(),
|
||||
tokens: self.lower_token_stream(item.tokens.clone()),
|
||||
args: self.lower_mac_args(&item.args),
|
||||
})
|
||||
}
|
||||
AttrKind::DocComment(comment) => AttrKind::DocComment(comment)
|
||||
@ -1017,6 +1017,16 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_mac_args(&mut self, args: &MacArgs) -> MacArgs {
|
||||
match *args {
|
||||
MacArgs::Empty => MacArgs::Empty,
|
||||
MacArgs::Delimited(dspan, delim, ref tokens) =>
|
||||
MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone())),
|
||||
MacArgs::Eq(eq_span, ref tokens) =>
|
||||
MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
|
||||
tokens
|
||||
.into_trees()
|
||||
|
@ -233,7 +233,7 @@ impl LoweringContext<'_> {
|
||||
|
||||
if let ItemKind::MacroDef(ref def) = i.kind {
|
||||
if !def.legacy || attr::contains_name(&i.attrs, sym::macro_export) {
|
||||
let body = self.lower_token_stream(def.stream());
|
||||
let body = self.lower_token_stream(def.body.inner_tokens());
|
||||
let hir_id = self.lower_node_id(i.id);
|
||||
self.exported_macros.push(hir::MacroDef {
|
||||
name: ident.name,
|
||||
|
@ -358,7 +358,6 @@ language_item_table! {
|
||||
// Don't be fooled by the naming here: this lang item denotes `PartialEq`, not `Eq`.
|
||||
EqTraitLangItem, "eq", eq_trait, Target::Trait;
|
||||
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Target::Trait;
|
||||
OrdTraitLangItem, "ord", ord_trait, Target::Trait;
|
||||
|
||||
// A number of panic-related lang items. The `panic` item corresponds to
|
||||
// divide-by-zero and various panic cases with `match`. The
|
||||
|
@ -521,7 +521,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
) {
|
||||
command.evaluate(self.tcx, trait_ref, &flags[..])
|
||||
} else {
|
||||
OnUnimplementedNote::empty()
|
||||
OnUnimplementedNote::default()
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,6 +697,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
fallback_has_occurred: bool,
|
||||
points_at_arg: bool,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let span = obligation.cause.span;
|
||||
|
||||
let mut err = match *error {
|
||||
@ -732,6 +733,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
message,
|
||||
label,
|
||||
note,
|
||||
enclosing_scope,
|
||||
} = self.on_unimplemented_note(trait_ref, obligation);
|
||||
let have_alt_message = message.is_some() || label.is_some();
|
||||
let is_try = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
@ -798,6 +800,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
||||
err.note(s.as_str());
|
||||
}
|
||||
if let Some(ref s) = enclosing_scope {
|
||||
let enclosing_scope_span = tcx.def_span(
|
||||
tcx.hir()
|
||||
.opt_local_def_id(obligation.cause.body_id)
|
||||
.unwrap_or_else(|| {
|
||||
tcx.hir().body_owner_def_id(hir::BodyId {
|
||||
hir_id: obligation.cause.body_id,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
err.span_label(enclosing_scope_span, s.as_str());
|
||||
}
|
||||
|
||||
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
|
||||
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
|
||||
|
@ -22,18 +22,15 @@ pub struct OnUnimplementedDirective {
|
||||
pub message: Option<OnUnimplementedFormatString>,
|
||||
pub label: Option<OnUnimplementedFormatString>,
|
||||
pub note: Option<OnUnimplementedFormatString>,
|
||||
pub enclosing_scope: Option<OnUnimplementedFormatString>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OnUnimplementedNote {
|
||||
pub message: Option<String>,
|
||||
pub label: Option<String>,
|
||||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
impl OnUnimplementedNote {
|
||||
pub fn empty() -> Self {
|
||||
OnUnimplementedNote { message: None, label: None, note: None }
|
||||
}
|
||||
pub enclosing_scope: Option<String>,
|
||||
}
|
||||
|
||||
fn parse_error(
|
||||
@ -85,24 +82,33 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
let mut note = None;
|
||||
let mut enclosing_scope = None;
|
||||
let mut subcommands = vec![];
|
||||
|
||||
let parse_value = |value_str| {
|
||||
OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span)
|
||||
.map(Some)
|
||||
};
|
||||
|
||||
for item in item_iter {
|
||||
if item.check_name(sym::message) && message.is_none() {
|
||||
if let Some(message_) = item.value_str() {
|
||||
message = Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx, trait_def_id, message_, span)?);
|
||||
message = parse_value(message_)?;
|
||||
continue;
|
||||
}
|
||||
} else if item.check_name(sym::label) && label.is_none() {
|
||||
if let Some(label_) = item.value_str() {
|
||||
label = Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx, trait_def_id, label_, span)?);
|
||||
label = parse_value(label_)?;
|
||||
continue;
|
||||
}
|
||||
} else if item.check_name(sym::note) && note.is_none() {
|
||||
if let Some(note_) = item.value_str() {
|
||||
note = Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx, trait_def_id, note_, span)?);
|
||||
note = parse_value(note_)?;
|
||||
continue;
|
||||
}
|
||||
} else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() {
|
||||
if let Some(enclosing_scope_) = item.value_str() {
|
||||
enclosing_scope = parse_value(enclosing_scope_)?;
|
||||
continue;
|
||||
}
|
||||
} else if item.check_name(sym::on) && is_root &&
|
||||
@ -130,7 +136,14 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
if errored {
|
||||
Err(ErrorReported)
|
||||
} else {
|
||||
Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
|
||||
Ok(OnUnimplementedDirective {
|
||||
condition,
|
||||
subcommands,
|
||||
message,
|
||||
label,
|
||||
note,
|
||||
enclosing_scope
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,6 +170,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
label: Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx, trait_def_id, value, attr.span)?),
|
||||
note: None,
|
||||
enclosing_scope: None,
|
||||
}))
|
||||
} else {
|
||||
return Err(ErrorReported);
|
||||
@ -174,6 +188,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
let mut note = None;
|
||||
let mut enclosing_scope = None;
|
||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
||||
|
||||
for command in self.subcommands.iter().chain(Some(self)).rev() {
|
||||
@ -202,6 +217,10 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
if let Some(ref note_) = command.note {
|
||||
note = Some(note_.clone());
|
||||
}
|
||||
|
||||
if let Some(ref enclosing_scope_) = command.enclosing_scope {
|
||||
enclosing_scope = Some(enclosing_scope_.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let options: FxHashMap<Symbol, String> = options.into_iter()
|
||||
@ -211,6 +230,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
label: label.map(|l| l.format(tcx, trait_ref, &options)),
|
||||
message: message.map(|m| m.format(tcx, trait_ref, &options)),
|
||||
note: note.map(|n| n.format(tcx, trait_ref, &options)),
|
||||
enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1450,10 +1450,10 @@ impl KeywordIdents {
|
||||
|
||||
impl EarlyLintPass for KeywordIdents {
|
||||
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
|
||||
self.check_tokens(cx, mac_def.stream());
|
||||
self.check_tokens(cx, mac_def.body.inner_tokens());
|
||||
}
|
||||
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
|
||||
self.check_tokens(cx, mac.tts.clone().into());
|
||||
self.check_tokens(cx, mac.args.inner_tokens());
|
||||
}
|
||||
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
|
||||
self.check_ident_token(cx, UnderMacro(false), ident);
|
||||
|
@ -32,6 +32,8 @@ use syntax::source_map;
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::expand::allocator::AllocatorKind;
|
||||
use syntax::ptr::P;
|
||||
use syntax::tokenstream::DelimSpan;
|
||||
use syntax_pos::{Span, FileName};
|
||||
|
||||
macro_rules! provide {
|
||||
@ -427,6 +429,7 @@ impl CStore {
|
||||
|
||||
let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);
|
||||
let local_span = Span::with_root_ctxt(source_file.start_pos, source_file.end_pos);
|
||||
let dspan = DelimSpan::from_single(local_span);
|
||||
let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None);
|
||||
emit_unclosed_delims(&mut errors, &sess.parse_sess);
|
||||
|
||||
@ -448,7 +451,7 @@ impl CStore {
|
||||
span: local_span,
|
||||
attrs: attrs.iter().cloned().collect(),
|
||||
kind: ast::ItemKind::MacroDef(ast::MacroDef {
|
||||
tokens: body.into(),
|
||||
body: P(ast::MacArgs::Delimited(dspan, ast::MacDelimiter::Brace, body)),
|
||||
legacy: def.legacy,
|
||||
}),
|
||||
vis: source_map::respan(local_span.shrink_to_lo(), ast::VisibilityKind::Inherited),
|
||||
|
@ -425,16 +425,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
|
||||
}
|
||||
|
||||
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
||||
fn specialize_constructor<'a, 'q>(
|
||||
fn specialize_constructor(
|
||||
&self,
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
constructor: &Constructor<'tcx>,
|
||||
ctor_wild_subpatterns: &[&'q Pat<'tcx>],
|
||||
) -> Option<PatStack<'q, 'tcx>>
|
||||
where
|
||||
'a: 'q,
|
||||
'p: 'q,
|
||||
{
|
||||
ctor_wild_subpatterns: &'p [Pat<'tcx>],
|
||||
) -> Option<PatStack<'p, 'tcx>> {
|
||||
let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
|
||||
new_heads.map(|mut new_head| {
|
||||
new_head.0.extend_from_slice(&self.0[1..]);
|
||||
@ -459,6 +455,7 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
|
||||
}
|
||||
|
||||
/// A 2D matrix.
|
||||
#[derive(Clone)]
|
||||
pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
|
||||
|
||||
impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||
@ -486,16 +483,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||
}
|
||||
|
||||
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
||||
fn specialize_constructor<'a, 'q>(
|
||||
fn specialize_constructor(
|
||||
&self,
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
constructor: &Constructor<'tcx>,
|
||||
ctor_wild_subpatterns: &[&'q Pat<'tcx>],
|
||||
) -> Matrix<'q, 'tcx>
|
||||
where
|
||||
'a: 'q,
|
||||
'p: 'q,
|
||||
{
|
||||
ctor_wild_subpatterns: &'p [Pat<'tcx>],
|
||||
) -> Matrix<'p, 'tcx> {
|
||||
self.0
|
||||
.iter()
|
||||
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
|
||||
@ -1033,17 +1026,19 @@ impl<'tcx> Constructor<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Usefulness<'tcx> {
|
||||
Useful,
|
||||
pub enum Usefulness<'tcx, 'p> {
|
||||
/// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
|
||||
Useful(Vec<&'p Pat<'tcx>>),
|
||||
/// Carries a list of witnesses of non-exhaustiveness.
|
||||
UsefulWithWitness(Vec<Witness<'tcx>>),
|
||||
NotUseful,
|
||||
}
|
||||
|
||||
impl<'tcx> Usefulness<'tcx> {
|
||||
impl<'tcx, 'p> Usefulness<'tcx, 'p> {
|
||||
fn new_useful(preference: WitnessPreference) -> Self {
|
||||
match preference {
|
||||
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
|
||||
LeaveOutWitness => Useful,
|
||||
LeaveOutWitness => Useful(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1604,13 +1599,13 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
|
||||
/// relation to preceding patterns, it is not reachable) and exhaustiveness
|
||||
/// checking (if a wildcard pattern is useful in relation to a matrix, the
|
||||
/// matrix isn't exhaustive).
|
||||
pub fn is_useful<'p, 'a, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
pub fn is_useful<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
matrix: &Matrix<'p, 'tcx>,
|
||||
v: &PatStack<'_, 'tcx>,
|
||||
v: &PatStack<'p, 'tcx>,
|
||||
witness_preference: WitnessPreference,
|
||||
hir_id: HirId,
|
||||
) -> Usefulness<'tcx> {
|
||||
) -> Usefulness<'tcx, 'p> {
|
||||
let &Matrix(ref rows) = matrix;
|
||||
debug!("is_useful({:#?}, {:#?})", matrix, v);
|
||||
|
||||
@ -1631,11 +1626,26 @@ pub fn is_useful<'p, 'a, 'tcx>(
|
||||
|
||||
// If the first pattern is an or-pattern, expand it.
|
||||
if let Some(vs) = v.expand_or_pat() {
|
||||
return vs
|
||||
.into_iter()
|
||||
.map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
|
||||
.find(|result| result.is_useful())
|
||||
.unwrap_or(NotUseful);
|
||||
// We need to push the already-seen patterns into the matrix in order to detect redundant
|
||||
// branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
|
||||
let mut matrix = matrix.clone();
|
||||
let mut unreachable_pats = Vec::new();
|
||||
let mut any_is_useful = false;
|
||||
for v in vs {
|
||||
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
|
||||
match res {
|
||||
Useful(pats) => {
|
||||
any_is_useful = true;
|
||||
unreachable_pats.extend(pats);
|
||||
}
|
||||
NotUseful => unreachable_pats.push(v.head()),
|
||||
UsefulWithWitness(_) => {
|
||||
bug!("Encountered or-pat in `v` during exhaustiveness checking")
|
||||
}
|
||||
}
|
||||
matrix.push(v);
|
||||
}
|
||||
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
|
||||
}
|
||||
|
||||
let (ty, span) = matrix
|
||||
@ -1768,21 +1778,21 @@ pub fn is_useful<'p, 'a, 'tcx>(
|
||||
|
||||
/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
|
||||
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
|
||||
fn is_useful_specialized<'p, 'a, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
fn is_useful_specialized<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
matrix: &Matrix<'p, 'tcx>,
|
||||
v: &PatStack<'_, 'tcx>,
|
||||
v: &PatStack<'p, 'tcx>,
|
||||
ctor: Constructor<'tcx>,
|
||||
lty: Ty<'tcx>,
|
||||
witness_preference: WitnessPreference,
|
||||
hir_id: HirId,
|
||||
) -> Usefulness<'tcx> {
|
||||
) -> Usefulness<'tcx, 'p> {
|
||||
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
|
||||
|
||||
let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty);
|
||||
let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
|
||||
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
|
||||
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
|
||||
let ctor_wild_subpatterns =
|
||||
cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
|
||||
let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
|
||||
v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
|
||||
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
|
||||
.map(|u| u.apply_constructor(cx, &ctor, lty))
|
||||
.unwrap_or(NotUseful)
|
||||
@ -2250,13 +2260,13 @@ fn constructor_covered_by_range<'tcx>(
|
||||
if intersects { Some(()) } else { None }
|
||||
}
|
||||
|
||||
fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
fn patterns_for_variant<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
subpatterns: &'p [FieldPat<'tcx>],
|
||||
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
|
||||
ctor_wild_subpatterns: &'p [Pat<'tcx>],
|
||||
is_non_exhaustive: bool,
|
||||
) -> PatStack<'p, 'tcx> {
|
||||
let mut result = SmallVec::from_slice(ctor_wild_subpatterns);
|
||||
let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect();
|
||||
|
||||
for subpat in subpatterns {
|
||||
if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
|
||||
@ -2280,11 +2290,11 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
|
||||
/// different patterns.
|
||||
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
||||
/// fields filled with wild patterns.
|
||||
fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
pat: &'q Pat<'tcx>,
|
||||
fn specialize_one_pattern<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
pat: &'p Pat<'tcx>,
|
||||
constructor: &Constructor<'tcx>,
|
||||
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
|
||||
ctor_wild_subpatterns: &'p [Pat<'tcx>],
|
||||
) -> Option<PatStack<'p, 'tcx>> {
|
||||
if let NonExhaustive = constructor {
|
||||
// Only a wildcard pattern can match the special extra constructor
|
||||
@ -2294,9 +2304,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
|
||||
let result = match *pat.kind {
|
||||
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
|
||||
|
||||
PatKind::Binding { .. } | PatKind::Wild => {
|
||||
Some(PatStack::from_slice(ctor_wild_subpatterns))
|
||||
}
|
||||
PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()),
|
||||
|
||||
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
|
||||
let ref variant = adt_def.variants[variant_index];
|
||||
@ -2406,7 +2414,6 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
|
||||
.chain(
|
||||
ctor_wild_subpatterns
|
||||
.iter()
|
||||
.map(|p| *p)
|
||||
.skip(prefix.len())
|
||||
.take(slice_count)
|
||||
.chain(suffix.iter()),
|
||||
|
@ -139,39 +139,22 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
|
||||
let mut have_errors = false;
|
||||
|
||||
let inlined_arms: Vec<(Vec<_>, _)> = arms
|
||||
let inlined_arms: Vec<_> = arms
|
||||
.iter()
|
||||
.map(|arm| {
|
||||
(
|
||||
// HACK(or_patterns; Centril | dlrobertson): Remove this and
|
||||
// correctly handle exhaustiveness checking for nested or-patterns.
|
||||
match &arm.pat.kind {
|
||||
hir::PatKind::Or(pats) => pats,
|
||||
_ => std::slice::from_ref(&arm.pat),
|
||||
}
|
||||
.iter()
|
||||
.map(|pat| {
|
||||
let mut patcx = PatCtxt::new(
|
||||
self.tcx,
|
||||
self.param_env.and(self.identity_substs),
|
||||
self.tables,
|
||||
);
|
||||
patcx.include_lint_checks();
|
||||
let pattern = cx
|
||||
.pattern_arena
|
||||
.alloc(expand_pattern(cx, patcx.lower_pattern(&pat)))
|
||||
as &_;
|
||||
if !patcx.errors.is_empty() {
|
||||
patcx.report_inlining_errors(pat.span);
|
||||
have_errors = true;
|
||||
}
|
||||
(pattern, &**pat)
|
||||
})
|
||||
.collect(),
|
||||
arm.guard.as_ref().map(|g| match g {
|
||||
hir::Guard::If(ref e) => &**e,
|
||||
}),
|
||||
)
|
||||
let mut patcx = PatCtxt::new(
|
||||
self.tcx,
|
||||
self.param_env.and(self.identity_substs),
|
||||
self.tables,
|
||||
);
|
||||
patcx.include_lint_checks();
|
||||
let pattern: &_ =
|
||||
cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&arm.pat)));
|
||||
if !patcx.errors.is_empty() {
|
||||
patcx.report_inlining_errors(arm.pat.span);
|
||||
have_errors = true;
|
||||
}
|
||||
(pattern, &*arm.pat, arm.guard.is_some())
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -181,7 +164,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
}
|
||||
|
||||
// Fourth, check for unreachable arms.
|
||||
check_arms(cx, &inlined_arms, source);
|
||||
let matrix = check_arms(cx, &inlined_arms, source);
|
||||
|
||||
// Then, if the match has no arms, check whether the scrutinee
|
||||
// is uninhabited.
|
||||
@ -248,12 +231,6 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
let matrix: Matrix<'_, '_> = inlined_arms
|
||||
.iter()
|
||||
.filter(|&&(_, guard)| guard.is_none())
|
||||
.flat_map(|arm| &arm.0)
|
||||
.map(|pat| PatStack::from_pattern(pat.0))
|
||||
.collect();
|
||||
let scrut_ty = self.tables.node_type(scrut.hir_id);
|
||||
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
|
||||
})
|
||||
@ -267,8 +244,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
patcx.include_lint_checks();
|
||||
let pattern = patcx.lower_pattern(pat);
|
||||
let pattern_ty = pattern.ty;
|
||||
let pattern = expand_pattern(cx, pattern);
|
||||
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(&pattern)].into_iter().collect();
|
||||
let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
|
||||
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
|
||||
|
||||
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
|
||||
Ok(_) => return,
|
||||
@ -403,113 +380,120 @@ fn pat_is_catchall(pat: &Pat) -> bool {
|
||||
}
|
||||
|
||||
// Check for unreachable patterns
|
||||
fn check_arms<'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||
arms: &[(Vec<(&super::Pat<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
|
||||
fn check_arms<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
arms: &[(&'p super::Pat<'tcx>, &hir::Pat, bool)],
|
||||
source: hir::MatchSource,
|
||||
) {
|
||||
) -> Matrix<'p, 'tcx> {
|
||||
let mut seen = Matrix::empty();
|
||||
let mut catchall = None;
|
||||
for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
|
||||
for &(pat, hir_pat) in pats {
|
||||
let v = PatStack::from_pattern(pat);
|
||||
for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
|
||||
let v = PatStack::from_pattern(pat);
|
||||
|
||||
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
|
||||
NotUseful => {
|
||||
match source {
|
||||
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => {
|
||||
bug!()
|
||||
}
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::IRREFUTABLE_LET_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"irrefutable if-let pattern",
|
||||
);
|
||||
}
|
||||
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
|
||||
NotUseful => {
|
||||
match source {
|
||||
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
|
||||
|
||||
hir::MatchSource::WhileLetDesugar => {
|
||||
// check which arm we're on.
|
||||
match arm_index {
|
||||
// The arm with the user-specified pattern.
|
||||
0 => {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
}
|
||||
// The arm with the wildcard pattern.
|
||||
1 => {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::IRREFUTABLE_LET_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"irrefutable while-let pattern",
|
||||
);
|
||||
}
|
||||
_ => bug!(),
|
||||
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
|
||||
// check which arm we're on.
|
||||
match arm_index {
|
||||
// The arm with the user-specified pattern.
|
||||
0 => {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
||||
let mut err = cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
// if we had a catchall pattern, hint at that
|
||||
if let Some(catchall) = catchall {
|
||||
err.span_label(pat.span, "unreachable pattern");
|
||||
err.span_label(catchall, "matches any value");
|
||||
// The arm with the wildcard pattern.
|
||||
1 => {
|
||||
let msg = match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
"irrefutable if-let pattern"
|
||||
}
|
||||
hir::MatchSource::WhileLetDesugar => {
|
||||
"irrefutable while-let pattern"
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::IRREFUTABLE_LET_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
msg,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
_ => bug!(),
|
||||
}
|
||||
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
// the arms are an uninhabited type. Which is OK.
|
||||
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
|
||||
}
|
||||
|
||||
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
||||
let mut err = cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
// if we had a catchall pattern, hint at that
|
||||
if let Some(catchall) = catchall {
|
||||
err.span_label(pat.span, "unreachable pattern");
|
||||
err.span_label(catchall, "matches any value");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
// the arms are an uninhabited type. Which is OK.
|
||||
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
|
||||
}
|
||||
Useful => (),
|
||||
UsefulWithWitness(_) => bug!(),
|
||||
}
|
||||
if guard.is_none() {
|
||||
seen.push(v);
|
||||
if catchall.is_none() && pat_is_catchall(hir_pat) {
|
||||
catchall = Some(pat.span);
|
||||
Useful(unreachable_subpatterns) => {
|
||||
for pat in unreachable_subpatterns {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
}
|
||||
}
|
||||
UsefulWithWitness(_) => bug!(),
|
||||
}
|
||||
if !has_guard {
|
||||
seen.push(v);
|
||||
if catchall.is_none() && pat_is_catchall(hir_pat) {
|
||||
catchall = Some(pat.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
seen
|
||||
}
|
||||
|
||||
fn check_not_useful(
|
||||
cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||
fn check_not_useful<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
matrix: &Matrix<'_, 'tcx>,
|
||||
matrix: &Matrix<'p, 'tcx>,
|
||||
hir_id: HirId,
|
||||
) -> Result<(), Vec<super::Pat<'tcx>>> {
|
||||
let wild_pattern = super::Pat::wildcard_from_ty(ty);
|
||||
match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
|
||||
let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
|
||||
match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) {
|
||||
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
|
||||
UsefulWithWitness(pats) => Err(if pats.is_empty() {
|
||||
vec![wild_pattern]
|
||||
bug!("Exhaustiveness check returned no witnesses")
|
||||
} else {
|
||||
pats.into_iter().map(|w| w.single_pattern()).collect()
|
||||
}),
|
||||
Useful => bug!(),
|
||||
Useful(_) => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_exhaustive<'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||
fn check_exhaustive<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
scrut_ty: Ty<'tcx>,
|
||||
sp: Span,
|
||||
matrix: &Matrix<'_, 'tcx>,
|
||||
matrix: &Matrix<'p, 'tcx>,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
|
||||
|
@ -424,13 +424,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 {
|
||||
// Then, check if `b` is -1, which is the "min_value / -1" case.
|
||||
let minus1 = Scalar::from_int(-1, dest.layout.size);
|
||||
let b = b.to_scalar().unwrap();
|
||||
if b == minus1 {
|
||||
let b_scalar = b.to_scalar().unwrap();
|
||||
if b_scalar == minus1 {
|
||||
throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented")
|
||||
} else {
|
||||
throw_ub_format!(
|
||||
"exact_div: {} cannot be divided by {} without remainder",
|
||||
a.to_scalar().unwrap(),
|
||||
a,
|
||||
b,
|
||||
)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use super::{
|
||||
};
|
||||
pub use rustc::mir::interpret::ScalarMaybeUndef;
|
||||
use rustc_macros::HashStable;
|
||||
use syntax::ast;
|
||||
|
||||
/// An `Immediate` represents a single immediate self-contained Rust value.
|
||||
///
|
||||
@ -100,6 +101,42 @@ pub struct ImmTy<'tcx, Tag=()> {
|
||||
pub layout: TyLayout<'tcx>,
|
||||
}
|
||||
|
||||
// `Tag: Copy` because some methods on `Scalar` consume them by value
|
||||
impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match &self.imm {
|
||||
Immediate::Scalar(ScalarMaybeUndef::Scalar(s)) => match s.to_bits(self.layout.size) {
|
||||
Ok(s) => {
|
||||
match self.layout.ty.kind {
|
||||
ty::Int(_) => return write!(
|
||||
fmt, "{}",
|
||||
super::sign_extend(s, self.layout.size) as i128,
|
||||
),
|
||||
ty::Uint(_) => return write!(fmt, "{}", s),
|
||||
ty::Bool if s == 0 => return fmt.write_str("false"),
|
||||
ty::Bool if s == 1 => return fmt.write_str("true"),
|
||||
ty::Char => if let Some(c) =
|
||||
u32::try_from(s).ok().and_then(std::char::from_u32) {
|
||||
return write!(fmt, "{}", c);
|
||||
},
|
||||
ty::Float(ast::FloatTy::F32) => if let Ok(u) = u32::try_from(s) {
|
||||
return write!(fmt, "{}", f32::from_bits(u));
|
||||
},
|
||||
ty::Float(ast::FloatTy::F64) => if let Ok(u) = u64::try_from(s) {
|
||||
return write!(fmt, "{}", f64::from_bits(u));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
write!(fmt, "{:x}", s)
|
||||
},
|
||||
Err(_) => fmt.write_str("{pointer}"),
|
||||
},
|
||||
Immediate::Scalar(ScalarMaybeUndef::Undef) => fmt.write_str("{undef}"),
|
||||
Immediate::ScalarPair(..) => fmt.write_str("{wide pointer or tuple}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
|
||||
type Target = Immediate<Tag>;
|
||||
#[inline(always)]
|
||||
|
@ -101,7 +101,7 @@ impl<'a> StripUnconfigured<'a> {
|
||||
if !attr.has_name(sym::cfg_attr) {
|
||||
return vec![attr];
|
||||
}
|
||||
if attr.get_normal_item().tokens.is_empty() {
|
||||
if let ast::MacArgs::Empty = attr.get_normal_item().args {
|
||||
self.sess.span_diagnostic
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
|
@ -277,7 +277,9 @@ pub fn parse_in_attr<'a, T>(
|
||||
) -> PResult<'a, T> {
|
||||
let mut parser = Parser::new(
|
||||
sess,
|
||||
attr.get_normal_item().tokens.clone(),
|
||||
// FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't
|
||||
// require reconstructing and immediately re-parsing delimiters.
|
||||
attr.get_normal_item().args.outer_tokens(),
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
@ -409,7 +411,7 @@ fn prepend_attrs(
|
||||
brackets.push(stream);
|
||||
}
|
||||
|
||||
brackets.push(item.tokens.clone());
|
||||
brackets.push(item.args.outer_tokens());
|
||||
|
||||
// The span we list here for `#` and for `[ ... ]` are both wrong in
|
||||
// that it encompasses more than each token, but it hopefully is "good
|
||||
|
@ -2,8 +2,7 @@ use super::{SeqSep, Parser, TokenType, PathStyle};
|
||||
use syntax::attr;
|
||||
use syntax::ast;
|
||||
use syntax::util::comments;
|
||||
use syntax::token::{self, Nonterminal, DelimToken};
|
||||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::token::{self, Nonterminal};
|
||||
use syntax_pos::{Span, Symbol};
|
||||
use errors::PResult;
|
||||
|
||||
@ -181,31 +180,8 @@ impl<'a> Parser<'a> {
|
||||
item
|
||||
} else {
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
|
||||
self.check(&token::OpenDelim(DelimToken::Bracket)) ||
|
||||
self.check(&token::OpenDelim(DelimToken::Brace)) {
|
||||
self.parse_token_tree().into()
|
||||
} else if self.eat(&token::Eq) {
|
||||
let eq = TokenTree::token(token::Eq, self.prev_span);
|
||||
let mut is_interpolated_expr = false;
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtExpr(..) = **nt {
|
||||
is_interpolated_expr = true;
|
||||
}
|
||||
}
|
||||
let token_tree = if is_interpolated_expr {
|
||||
// We need to accept arbitrary interpolated expressions to continue
|
||||
// supporting things like `doc = $expr` that work on stable.
|
||||
// Non-literal interpolated expressions are rejected after expansion.
|
||||
self.parse_token_tree()
|
||||
} else {
|
||||
self.parse_unsuffixed_lit()?.token_tree()
|
||||
};
|
||||
TokenStream::new(vec![eq.into(), token_tree.into()])
|
||||
} else {
|
||||
TokenStream::default()
|
||||
};
|
||||
ast::AttrItem { path, tokens }
|
||||
let args = self.parse_attr_args()?;
|
||||
ast::AttrItem { path, args }
|
||||
})
|
||||
}
|
||||
|
||||
@ -244,7 +220,7 @@ impl<'a> Parser<'a> {
|
||||
Ok(attrs)
|
||||
}
|
||||
|
||||
fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
|
||||
pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
|
||||
let lit = self.parse_lit()?;
|
||||
debug!("checking if {:?} is unusuffixed", lit);
|
||||
|
||||
|
@ -922,13 +922,11 @@ impl<'a> Parser<'a> {
|
||||
// `!`, as an operator, is prefix, so we know this isn't that.
|
||||
if self.eat(&token::Not) {
|
||||
// MACRO INVOCATION expression
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
let args = self.parse_mac_args()?;
|
||||
hi = self.prev_span;
|
||||
ex = ExprKind::Mac(Mac {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
span: lo.to(hi),
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
});
|
||||
} else if self.check(&token::OpenDelim(token::Brace)) {
|
||||
|
@ -8,12 +8,12 @@ use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, Us
|
||||
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
|
||||
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
|
||||
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField};
|
||||
use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
|
||||
use syntax::ast::{Mac, MacArgs, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ThinVec;
|
||||
use syntax::token;
|
||||
use syntax::tokenstream::{TokenTree, TokenStream};
|
||||
use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream};
|
||||
use syntax::source_map::{self, respan, Span};
|
||||
use syntax::struct_span_err;
|
||||
use syntax_pos::BytePos;
|
||||
@ -432,22 +432,18 @@ impl<'a> Parser<'a> {
|
||||
let prev_span = self.prev_span;
|
||||
self.complain_if_pub_macro(&visibility.node, prev_span);
|
||||
|
||||
let mac_lo = self.token.span;
|
||||
|
||||
// Item macro
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
self.expect(&token::Not)?;
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
|
||||
let args = self.parse_mac_args()?;
|
||||
if args.need_semicolon() && !self.eat(&token::Semi) {
|
||||
self.report_invalid_macro_expansion_item();
|
||||
}
|
||||
|
||||
let hi = self.prev_span;
|
||||
let mac = Mac {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
span: mac_lo.to(hi),
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
};
|
||||
let item =
|
||||
@ -500,7 +496,6 @@ impl<'a> Parser<'a> {
|
||||
if self.token.is_path_start() &&
|
||||
!(self.is_async_fn() && self.token.span.rust_2015()) {
|
||||
let prev_span = self.prev_span;
|
||||
let lo = self.token.span;
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
|
||||
if path.segments.len() == 1 {
|
||||
@ -518,16 +513,14 @@ impl<'a> Parser<'a> {
|
||||
*at_end = true;
|
||||
|
||||
// eat a matched-delimiter token tree:
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
if delim != MacDelimiter::Brace {
|
||||
let args = self.parse_mac_args()?;
|
||||
if args.need_semicolon() {
|
||||
self.expect_semi()?;
|
||||
}
|
||||
|
||||
Ok(Some(Mac {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
span: lo.to(self.prev_span),
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
}))
|
||||
} else {
|
||||
@ -1624,33 +1617,31 @@ impl<'a> Parser<'a> {
|
||||
vis: &Visibility,
|
||||
lo: Span
|
||||
) -> PResult<'a, Option<P<Item>>> {
|
||||
let token_lo = self.token.span;
|
||||
let (ident, def) = if self.eat_keyword(kw::Macro) {
|
||||
let ident = self.parse_ident()?;
|
||||
let tokens = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
match self.parse_token_tree() {
|
||||
TokenTree::Delimited(_, _, tts) => tts,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let body = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
self.parse_mac_args()?
|
||||
} else if self.check(&token::OpenDelim(token::Paren)) {
|
||||
let args = self.parse_token_tree();
|
||||
let params = self.parse_token_tree();
|
||||
let pspan = params.span();
|
||||
let body = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
self.parse_token_tree()
|
||||
} else {
|
||||
self.unexpected()?;
|
||||
unreachable!()
|
||||
return self.unexpected();
|
||||
};
|
||||
TokenStream::new(vec![
|
||||
args.into(),
|
||||
TokenTree::token(token::FatArrow, token_lo.to(self.prev_span)).into(),
|
||||
let bspan = body.span();
|
||||
let tokens = TokenStream::new(vec![
|
||||
params.into(),
|
||||
TokenTree::token(token::FatArrow, pspan.between(bspan)).into(),
|
||||
body.into(),
|
||||
])
|
||||
]);
|
||||
let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi());
|
||||
P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens))
|
||||
} else {
|
||||
self.unexpected()?;
|
||||
unreachable!()
|
||||
return self.unexpected();
|
||||
};
|
||||
|
||||
(ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
|
||||
(ident, ast::MacroDef { body, legacy: false })
|
||||
} else if self.check_keyword(sym::macro_rules) &&
|
||||
self.look_ahead(1, |t| *t == token::Not) &&
|
||||
self.look_ahead(2, |t| t.is_ident()) {
|
||||
@ -1660,12 +1651,12 @@ impl<'a> Parser<'a> {
|
||||
self.bump();
|
||||
|
||||
let ident = self.parse_ident()?;
|
||||
let (delim, tokens) = self.expect_delimited_token_tree()?;
|
||||
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
|
||||
let body = self.parse_mac_args()?;
|
||||
if body.need_semicolon() && !self.eat(&token::Semi) {
|
||||
self.report_invalid_macro_expansion_item();
|
||||
}
|
||||
|
||||
(ident, ast::MacroDef { tokens, legacy: true })
|
||||
(ident, ast::MacroDef { body, legacy: true })
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ use crate::lexer::UnmatchedBrace;
|
||||
|
||||
use syntax::ast::{
|
||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit,
|
||||
IsAsync, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
|
||||
IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
|
||||
};
|
||||
|
||||
use syntax::print::pprust;
|
||||
@ -1010,27 +1010,49 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> {
|
||||
let delim = match self.token.kind {
|
||||
token::OpenDelim(delim) => delim,
|
||||
_ => {
|
||||
let msg = "expected open delimiter";
|
||||
let mut err = self.fatal(msg);
|
||||
err.span_label(self.token.span, msg);
|
||||
return Err(err)
|
||||
fn parse_mac_args(&mut self) -> PResult<'a, P<MacArgs>> {
|
||||
self.parse_mac_args_common(true).map(P)
|
||||
}
|
||||
|
||||
fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> {
|
||||
self.parse_mac_args_common(false)
|
||||
}
|
||||
|
||||
fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> {
|
||||
Ok(if self.check(&token::OpenDelim(DelimToken::Paren)) ||
|
||||
self.check(&token::OpenDelim(DelimToken::Bracket)) ||
|
||||
self.check(&token::OpenDelim(DelimToken::Brace)) {
|
||||
match self.parse_token_tree() {
|
||||
TokenTree::Delimited(dspan, delim, tokens) =>
|
||||
// We've confirmed above that there is a delimiter so unwrapping is OK.
|
||||
MacArgs::Delimited(dspan, MacDelimiter::from_token(delim).unwrap(), tokens),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
let tts = match self.parse_token_tree() {
|
||||
TokenTree::Delimited(_, _, tts) => tts,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let delim = match delim {
|
||||
token::Paren => MacDelimiter::Parenthesis,
|
||||
token::Bracket => MacDelimiter::Bracket,
|
||||
token::Brace => MacDelimiter::Brace,
|
||||
token::NoDelim => self.bug("unexpected no delimiter"),
|
||||
};
|
||||
Ok((delim, tts.into()))
|
||||
} else if !delimited_only {
|
||||
if self.eat(&token::Eq) {
|
||||
let eq_span = self.prev_span;
|
||||
let mut is_interpolated_expr = false;
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtExpr(..) = **nt {
|
||||
is_interpolated_expr = true;
|
||||
}
|
||||
}
|
||||
let token_tree = if is_interpolated_expr {
|
||||
// We need to accept arbitrary interpolated expressions to continue
|
||||
// supporting things like `doc = $expr` that work on stable.
|
||||
// Non-literal interpolated expressions are rejected after expansion.
|
||||
self.parse_token_tree()
|
||||
} else {
|
||||
self.parse_unsuffixed_lit()?.token_tree()
|
||||
};
|
||||
|
||||
MacArgs::Eq(eq_span, token_tree.into())
|
||||
} else {
|
||||
MacArgs::Empty
|
||||
}
|
||||
} else {
|
||||
return self.unexpected();
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_or_use_outer_attributes(
|
||||
|
@ -338,7 +338,7 @@ impl<'a> Parser<'a> {
|
||||
(None, self.parse_path(PathStyle::Expr)?)
|
||||
};
|
||||
match self.token.kind {
|
||||
token::Not if qself.is_none() => self.parse_pat_mac_invoc(lo, path)?,
|
||||
token::Not if qself.is_none() => self.parse_pat_mac_invoc(path)?,
|
||||
token::DotDotDot | token::DotDotEq | token::DotDot => {
|
||||
self.parse_pat_range_starting_with_path(lo, qself, path)?
|
||||
}
|
||||
@ -593,14 +593,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parse macro invocation
|
||||
fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> {
|
||||
fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
|
||||
self.bump();
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
let args = self.parse_mac_args()?;
|
||||
let mac = Mac {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
span: lo.to(self.prev_span),
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
};
|
||||
Ok(PatKind::Mac(mac))
|
||||
|
@ -2,6 +2,7 @@ use super::{Parser, TokenType};
|
||||
use crate::maybe_whole;
|
||||
use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
|
||||
use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
|
||||
use syntax::ast::MacArgs;
|
||||
use syntax::ThinVec;
|
||||
use syntax::token::{self, Token};
|
||||
use syntax::source_map::{Span, BytePos};
|
||||
@ -114,9 +115,9 @@ impl<'a> Parser<'a> {
|
||||
fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
|
||||
let meta_ident = match self.token.kind {
|
||||
token::Interpolated(ref nt) => match **nt {
|
||||
token::NtMeta(ref item) => match item.tokens.is_empty() {
|
||||
true => Some(item.path.clone()),
|
||||
false => None,
|
||||
token::NtMeta(ref item) => match item.args {
|
||||
MacArgs::Empty => Some(item.path.clone()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
|
@ -10,7 +10,7 @@ use syntax::ThinVec;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind};
|
||||
use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter};
|
||||
use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac};
|
||||
use syntax::util::classify;
|
||||
use syntax::token;
|
||||
use syntax::source_map::{respan, Span};
|
||||
@ -93,10 +93,11 @@ impl<'a> Parser<'a> {
|
||||
}));
|
||||
}
|
||||
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
let args = self.parse_mac_args()?;
|
||||
let delim = args.delim();
|
||||
let hi = self.prev_span;
|
||||
|
||||
let style = if delim == MacDelimiter::Brace {
|
||||
let style = if delim == token::Brace {
|
||||
MacStmtStyle::Braces
|
||||
} else {
|
||||
MacStmtStyle::NoBraces
|
||||
@ -104,12 +105,10 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let mac = Mac {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
span: lo.to(hi),
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
};
|
||||
let kind = if delim == MacDelimiter::Brace ||
|
||||
let kind = if delim == token::Brace ||
|
||||
self.token == token::Semi || self.token == token::Eof {
|
||||
StmtKind::Mac(P((mac, style, attrs.into())))
|
||||
}
|
||||
@ -130,7 +129,7 @@ impl<'a> Parser<'a> {
|
||||
self.warn_missing_semicolon();
|
||||
StmtKind::Mac(P((mac, style, attrs.into())))
|
||||
} else {
|
||||
let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new());
|
||||
let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new());
|
||||
let e = self.maybe_recover_from_bad_qpath(e, true)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
|
||||
|
@ -177,12 +177,10 @@ impl<'a> Parser<'a> {
|
||||
let path = self.parse_path(PathStyle::Type)?;
|
||||
if self.eat(&token::Not) {
|
||||
// Macro invocation in type position
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
let args = self.parse_mac_args()?;
|
||||
let mac = Mac {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
span: lo.to(self.prev_span),
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
};
|
||||
TyKind::Mac(mac)
|
||||
|
@ -2,11 +2,9 @@
|
||||
|
||||
use errors::{PResult, Applicability};
|
||||
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
|
||||
use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem, MetaItemKind};
|
||||
use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind};
|
||||
use syntax::attr::mk_name_value_item_str;
|
||||
use syntax::early_buffered_lints::BufferedEarlyLintId;
|
||||
use syntax::token;
|
||||
use syntax::tokenstream::TokenTree;
|
||||
use syntax::sess::ParseSess;
|
||||
use syntax_pos::{Symbol, sym};
|
||||
|
||||
@ -19,11 +17,9 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
|
||||
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
||||
Some((name, _, template, _)) if name != sym::rustc_dummy =>
|
||||
check_builtin_attribute(sess, attr, name, template),
|
||||
_ => if let Some(TokenTree::Token(token)) = attr.get_normal_item().tokens.trees().next() {
|
||||
if token == token::Eq {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
parse_meta(sess, attr).map_err(|mut err| err.emit()).ok();
|
||||
}
|
||||
_ => if let MacArgs::Eq(..) = attr.get_normal_item().args {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
parse_meta(sess, attr).map_err(|mut err| err.emit()).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,14 +737,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|this| visit::walk_enum_def(this, enum_definition, generics, item_id))
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, mac: &Mac) {
|
||||
// when a new macro kind is added but the author forgets to set it up for expansion
|
||||
// because that's the only part that won't cause a compiler error
|
||||
self.session.diagnostic()
|
||||
.span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \
|
||||
the relevant `fold_*()` method in `PlaceholderExpander`?");
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
|
||||
if let ImplItemKind::Method(ref sig, _) = ii.kind {
|
||||
self.check_fn_decl(&sig.decl);
|
||||
|
@ -1515,14 +1515,6 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, mac: &'l ast::Mac) {
|
||||
// These shouldn't exist in the AST at this point, log a span bug.
|
||||
span_bug!(
|
||||
mac.span,
|
||||
"macro invocation should have been expanded out of AST"
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'l ast::Pat) {
|
||||
self.process_macro_use(p.span);
|
||||
self.process_pat(p);
|
||||
|
@ -482,7 +482,7 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE
|
||||
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
|
||||
LoadedMacro::MacroDef(def, _) => {
|
||||
let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind {
|
||||
let tts: Vec<_> = def.stream().into_trees().collect();
|
||||
let tts: Vec<_> = def.body.inner_tokens().into_trees().collect();
|
||||
tts.chunks(4).map(|arm| arm[0].span()).collect()
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -812,9 +812,50 @@ mod loop_keyword { }
|
||||
//
|
||||
/// Control flow based on pattern matching.
|
||||
///
|
||||
/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
|
||||
/// `match` can be used to run code conditionally. Every pattern must
|
||||
/// be handled exhaustively either explicitly or by using wildcards like
|
||||
/// `_` in the `match`. Since `match` is an expression, values can also be
|
||||
/// returned.
|
||||
///
|
||||
/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
|
||||
/// ```rust
|
||||
/// let opt = Option::None::<usize>;
|
||||
/// let x = match opt {
|
||||
/// Some(int) => int,
|
||||
/// None => 10,
|
||||
/// };
|
||||
/// assert_eq!(x, 10);
|
||||
///
|
||||
/// let a_number = Option::Some(10);
|
||||
/// match a_number {
|
||||
/// Some(x) if x <= 5 => println!("0 to 5 num = {}", x),
|
||||
/// Some(x @ 6..=10) => println!("6 to 10 num = {}", x),
|
||||
/// None => panic!(),
|
||||
/// // all other numbers
|
||||
/// _ => panic!(),
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// `match` can be used to gain access to the inner members of an enum
|
||||
/// and use them directly.
|
||||
///
|
||||
/// ```rust
|
||||
/// enum Outer {
|
||||
/// Double(Option<u8>, Option<String>),
|
||||
/// Single(Option<u8>),
|
||||
/// Empty
|
||||
/// }
|
||||
///
|
||||
/// let get_inner = Outer::Double(None, Some(String::new()));
|
||||
/// match get_inner {
|
||||
/// Outer::Double(None, Some(st)) => println!("{}", st),
|
||||
/// Outer::Single(opt) => println!("{:?}", opt),
|
||||
/// _ => panic!(),
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// For more information on `match` and matching in general, see the [Reference].
|
||||
///
|
||||
/// [Reference]: ../reference/expressions/match-expr.html
|
||||
mod match_keyword { }
|
||||
|
||||
#[doc(keyword = "mod")]
|
||||
@ -831,10 +872,35 @@ mod mod_keyword { }
|
||||
//
|
||||
/// Capture a [closure]'s environment by value.
|
||||
///
|
||||
/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
|
||||
/// `move` converts any variables captured by reference or mutable reference
|
||||
/// to owned by value variables. The three [`Fn` trait]'s mirror the ways to capture
|
||||
/// variables, when `move` is used, the closures is represented by the `FnOnce` trait.
|
||||
///
|
||||
/// [closure]: ../book/second-edition/ch13-01-closures.html
|
||||
/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
|
||||
/// ```rust
|
||||
/// let capture = "hello";
|
||||
/// let closure = move || {
|
||||
/// println!("rust says {}", capture);
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// `move` is often used when [threads] are involved.
|
||||
///
|
||||
/// ```rust
|
||||
/// let x = 5;
|
||||
///
|
||||
/// std::thread::spawn(move || {
|
||||
/// println!("captured {} by value", x)
|
||||
/// }).join().unwrap();
|
||||
///
|
||||
/// // x is no longer available
|
||||
/// ```
|
||||
///
|
||||
/// For more information on the `move` keyword, see the [closure]'s section
|
||||
/// of the Rust book or the [threads] section
|
||||
///
|
||||
/// [`Fn` trait]: ../std/ops/trait.Fn.html
|
||||
/// [closure]: ../book/ch13-01-closures.html
|
||||
/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads
|
||||
mod move_keyword { }
|
||||
|
||||
#[doc(keyword = "mut")]
|
||||
|
@ -27,7 +27,7 @@ pub use syntax_pos::symbol::{Ident, Symbol as Name};
|
||||
use crate::ptr::P;
|
||||
use crate::source_map::{dummy_spanned, respan, Spanned};
|
||||
use crate::token::{self, DelimToken};
|
||||
use crate::tokenstream::TokenStream;
|
||||
use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
|
||||
|
||||
use syntax_pos::symbol::{kw, sym, Symbol};
|
||||
use syntax_pos::{Span, DUMMY_SP, ExpnId};
|
||||
@ -40,6 +40,7 @@ use rustc_index::vec::Idx;
|
||||
use rustc_serialize::{self, Decoder, Encoder};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use std::iter;
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(test)]
|
||||
@ -1372,34 +1373,89 @@ pub enum Movability {
|
||||
Movable,
|
||||
}
|
||||
|
||||
/// Represents a macro invocation. The `Path` indicates which macro
|
||||
/// is being invoked, and the vector of token-trees contains the source
|
||||
/// of the macro invocation.
|
||||
///
|
||||
/// N.B., the additional ident for a `macro_rules`-style macro is actually
|
||||
/// stored in the enclosing item.
|
||||
/// Represents a macro invocation. The `path` indicates which macro
|
||||
/// is being invoked, and the `args` are arguments passed to it.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Mac {
|
||||
pub path: Path,
|
||||
pub delim: MacDelimiter,
|
||||
pub tts: TokenStream,
|
||||
pub span: Span,
|
||||
pub args: P<MacArgs>,
|
||||
pub prior_type_ascription: Option<(Span, bool)>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
|
||||
impl Mac {
|
||||
pub fn span(&self) -> Span {
|
||||
self.path.span.to(self.args.span().unwrap_or(self.path.span))
|
||||
}
|
||||
}
|
||||
|
||||
/// Arguments passed to an attribute or a function-like macro.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
|
||||
pub enum MacArgs {
|
||||
/// No arguments - `#[attr]`.
|
||||
Empty,
|
||||
/// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`.
|
||||
Delimited(DelimSpan, MacDelimiter, TokenStream),
|
||||
/// Arguments of a key-value attribute - `#[attr = "value"]`.
|
||||
Eq(
|
||||
/// Span of the `=` token.
|
||||
Span,
|
||||
/// Token stream of the "value".
|
||||
TokenStream,
|
||||
),
|
||||
}
|
||||
|
||||
impl MacArgs {
|
||||
pub fn delim(&self) -> DelimToken {
|
||||
match self {
|
||||
MacArgs::Delimited(_, delim, _) => delim.to_token(),
|
||||
MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
match *self {
|
||||
MacArgs::Empty => None,
|
||||
MacArgs::Delimited(dspan, ..) => Some(dspan.entire()),
|
||||
MacArgs::Eq(eq_span, ref tokens) => Some(eq_span.to(tokens.span().unwrap_or(eq_span))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tokens inside the delimiters or after `=`.
|
||||
/// Proc macros see these tokens, for example.
|
||||
pub fn inner_tokens(&self) -> TokenStream {
|
||||
match self {
|
||||
MacArgs::Empty => TokenStream::default(),
|
||||
MacArgs::Delimited(.., tokens) |
|
||||
MacArgs::Eq(.., tokens) => tokens.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tokens together with the delimiters or `=`.
|
||||
/// Use of this method generally means that something suboptimal or hacky is happening.
|
||||
pub fn outer_tokens(&self) -> TokenStream {
|
||||
match *self {
|
||||
MacArgs::Empty => TokenStream::default(),
|
||||
MacArgs::Delimited(dspan, delim, ref tokens) =>
|
||||
TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into(),
|
||||
MacArgs::Eq(eq_span, ref tokens) => iter::once(TokenTree::token(token::Eq, eq_span))
|
||||
.chain(tokens.trees()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a macro with these arguments needs a semicolon
|
||||
/// when used as a standalone item or statement.
|
||||
pub fn need_semicolon(&self) -> bool {
|
||||
!matches!(self, MacArgs::Delimited(_, MacDelimiter::Brace ,_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
|
||||
pub enum MacDelimiter {
|
||||
Parenthesis,
|
||||
Bracket,
|
||||
Brace,
|
||||
}
|
||||
|
||||
impl Mac {
|
||||
pub fn stream(&self) -> TokenStream {
|
||||
self.tts.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl MacDelimiter {
|
||||
crate fn to_token(self) -> DelimToken {
|
||||
match self {
|
||||
@ -1408,22 +1464,25 @@ impl MacDelimiter {
|
||||
MacDelimiter::Brace => DelimToken::Brace,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_token(delim: DelimToken) -> Option<MacDelimiter> {
|
||||
match delim {
|
||||
token::Paren => Some(MacDelimiter::Parenthesis),
|
||||
token::Bracket => Some(MacDelimiter::Bracket),
|
||||
token::Brace => Some(MacDelimiter::Brace),
|
||||
token::NoDelim => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a macro definition.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct MacroDef {
|
||||
pub tokens: TokenStream,
|
||||
pub body: P<MacArgs>,
|
||||
/// `true` if macro was defined with `macro_rules`.
|
||||
pub legacy: bool,
|
||||
}
|
||||
|
||||
impl MacroDef {
|
||||
pub fn stream(&self) -> TokenStream {
|
||||
self.tokens.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
// Clippy uses Hash and PartialEq
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq, HashStable_Generic)]
|
||||
pub enum StrStyle {
|
||||
@ -2323,7 +2382,7 @@ impl rustc_serialize::Decodable for AttrId {
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
|
||||
pub struct AttrItem {
|
||||
pub path: Path,
|
||||
pub tokens: TokenStream,
|
||||
pub args: MacArgs,
|
||||
}
|
||||
|
||||
/// Metadata associated with an item.
|
||||
|
@ -10,7 +10,7 @@ pub use crate::ast::Attribute;
|
||||
|
||||
use crate::ast;
|
||||
use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment};
|
||||
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
|
||||
use crate::mut_visit::visit_clobber;
|
||||
use crate::source_map::{BytePos, Spanned};
|
||||
@ -198,7 +198,7 @@ impl Attribute {
|
||||
|
||||
pub fn is_word(&self) -> bool {
|
||||
if let AttrKind::Normal(item) = &self.kind {
|
||||
item.tokens.is_empty()
|
||||
matches!(item.args, MacArgs::Empty)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -278,17 +278,9 @@ impl MetaItem {
|
||||
|
||||
impl AttrItem {
|
||||
pub fn meta(&self, span: Span) -> Option<MetaItem> {
|
||||
let mut tokens = self.tokens.trees().peekable();
|
||||
Some(MetaItem {
|
||||
path: self.path.clone(),
|
||||
kind: if let Some(kind) = MetaItemKind::from_tokens(&mut tokens) {
|
||||
if tokens.peek().is_some() {
|
||||
return None;
|
||||
}
|
||||
kind
|
||||
} else {
|
||||
return None;
|
||||
},
|
||||
kind: MetaItemKind::from_mac_args(&self.args)?,
|
||||
span,
|
||||
})
|
||||
}
|
||||
@ -362,8 +354,8 @@ crate fn mk_attr_id() -> AttrId {
|
||||
AttrId(id)
|
||||
}
|
||||
|
||||
pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
|
||||
mk_attr_from_item(style, AttrItem { path, tokens }, span)
|
||||
pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
|
||||
mk_attr_from_item(style, AttrItem { path, args }, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute {
|
||||
@ -377,12 +369,12 @@ pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attrib
|
||||
|
||||
/// Returns an inner attribute with the given value and span.
|
||||
pub fn mk_attr_inner(item: MetaItem) -> Attribute {
|
||||
mk_attr(AttrStyle::Inner, item.path, item.kind.tokens(item.span), item.span)
|
||||
mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
|
||||
}
|
||||
|
||||
/// Returns an outer attribute with the given value and span.
|
||||
pub fn mk_attr_outer(item: MetaItem) -> Attribute {
|
||||
mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span)
|
||||
mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
|
||||
}
|
||||
|
||||
pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute {
|
||||
@ -520,7 +512,26 @@ impl MetaItem {
|
||||
}
|
||||
|
||||
impl MetaItemKind {
|
||||
pub fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> {
|
||||
pub fn mac_args(&self, span: Span) -> MacArgs {
|
||||
match self {
|
||||
MetaItemKind::Word => MacArgs::Empty,
|
||||
MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()),
|
||||
MetaItemKind::List(list) => {
|
||||
let mut tts = Vec::new();
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if i > 0 {
|
||||
tts.push(TokenTree::token(token::Comma, span).into());
|
||||
}
|
||||
tts.extend(item.token_trees_and_joints())
|
||||
}
|
||||
MacArgs::Delimited(
|
||||
DelimSpan::from_single(span), MacDelimiter::Parenthesis, TokenStream::new(tts)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> {
|
||||
match *self {
|
||||
MetaItemKind::Word => vec![],
|
||||
MetaItemKind::NameValue(ref lit) => {
|
||||
@ -548,33 +559,8 @@ impl MetaItemKind {
|
||||
}
|
||||
}
|
||||
|
||||
// Premature conversions of `TokenTree`s to `TokenStream`s can hurt
|
||||
// performance. Do not use this function if `token_trees_and_joints()` can
|
||||
// be used instead.
|
||||
pub fn tokens(&self, span: Span) -> TokenStream {
|
||||
TokenStream::new(self.token_trees_and_joints(span))
|
||||
}
|
||||
|
||||
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind>
|
||||
where I: Iterator<Item = TokenTree>,
|
||||
{
|
||||
let delimited = match tokens.peek().cloned() {
|
||||
Some(TokenTree::Token(token)) if token == token::Eq => {
|
||||
tokens.next();
|
||||
return if let Some(TokenTree::Token(token)) = tokens.next() {
|
||||
Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => {
|
||||
tokens.next();
|
||||
tts.clone()
|
||||
}
|
||||
_ => return Some(MetaItemKind::Word),
|
||||
};
|
||||
|
||||
let mut tokens = delimited.into_trees().peekable();
|
||||
fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
|
||||
let mut tokens = tokens.into_trees().peekable();
|
||||
let mut result = Vec::new();
|
||||
while let Some(..) = tokens.peek() {
|
||||
let item = NestedMetaItem::from_tokens(&mut tokens)?;
|
||||
@ -586,6 +572,47 @@ impl MetaItemKind {
|
||||
}
|
||||
Some(MetaItemKind::List(result))
|
||||
}
|
||||
|
||||
fn name_value_from_tokens(
|
||||
tokens: &mut impl Iterator<Item = TokenTree>,
|
||||
) -> Option<MetaItemKind> {
|
||||
match tokens.next() {
|
||||
Some(TokenTree::Token(token)) =>
|
||||
Lit::from_token(&token).ok().map(MetaItemKind::NameValue),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
|
||||
match args {
|
||||
MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) =>
|
||||
MetaItemKind::list_from_tokens(tokens.clone()),
|
||||
MacArgs::Delimited(..) => None,
|
||||
MacArgs::Eq(_, tokens) => {
|
||||
assert!(tokens.len() == 1);
|
||||
MetaItemKind::name_value_from_tokens(&mut tokens.trees())
|
||||
}
|
||||
MacArgs::Empty => Some(MetaItemKind::Word),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_tokens(
|
||||
tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
|
||||
) -> Option<MetaItemKind> {
|
||||
match tokens.peek() {
|
||||
Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => {
|
||||
let inner_tokens = inner_tokens.clone();
|
||||
tokens.next();
|
||||
MetaItemKind::list_from_tokens(inner_tokens)
|
||||
}
|
||||
Some(TokenTree::Delimited(..)) => None,
|
||||
Some(TokenTree::Token(Token { kind: token::Eq, .. })) => {
|
||||
tokens.next();
|
||||
MetaItemKind::name_value_from_tokens(tokens)
|
||||
}
|
||||
_ => Some(MetaItemKind::Word),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NestedMetaItem {
|
||||
|
@ -12,6 +12,7 @@
|
||||
#![feature(const_transmute)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(label_break_value)]
|
||||
#![feature(matches_macro)]
|
||||
#![feature(nll)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(slice_patterns)]
|
||||
|
@ -359,6 +359,26 @@ pub fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl }: &mut FnSig, vis: &mut
|
||||
vis.visit_fn_decl(decl);
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
|
||||
match args {
|
||||
MacArgs::Empty => {}
|
||||
MacArgs::Delimited(dspan, _delim, tokens) => {
|
||||
visit_delim_span(dspan, vis);
|
||||
vis.visit_tts(tokens);
|
||||
}
|
||||
MacArgs::Eq(eq_span, tokens) => {
|
||||
vis.visit_span(eq_span);
|
||||
vis.visit_tts(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_delim_span<T: MutVisitor>(dspan: &mut DelimSpan, vis: &mut T) {
|
||||
vis.visit_span(&mut dspan.open);
|
||||
vis.visit_span(&mut dspan.close);
|
||||
}
|
||||
|
||||
pub fn noop_flat_map_field_pattern<T: MutVisitor>(
|
||||
mut fp: FieldPat,
|
||||
vis: &mut T,
|
||||
@ -550,9 +570,9 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
|
||||
pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
|
||||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(AttrItem { path, tokens }) => {
|
||||
AttrKind::Normal(AttrItem { path, args }) => {
|
||||
vis.visit_path(path);
|
||||
vis.visit_tts(tokens);
|
||||
visit_mac_args(args, vis);
|
||||
}
|
||||
AttrKind::DocComment(_) => {}
|
||||
}
|
||||
@ -560,15 +580,14 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
|
||||
}
|
||||
|
||||
pub fn noop_visit_mac<T: MutVisitor>(mac: &mut Mac, vis: &mut T) {
|
||||
let Mac { path, delim: _, tts, span, prior_type_ascription: _ } = mac;
|
||||
let Mac { path, args, prior_type_ascription: _ } = mac;
|
||||
vis.visit_path(path);
|
||||
vis.visit_tts(tts);
|
||||
vis.visit_span(span);
|
||||
visit_mac_args(args, vis);
|
||||
}
|
||||
|
||||
pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) {
|
||||
let MacroDef { tokens, legacy: _ } = macro_def;
|
||||
vis.visit_tts(tokens);
|
||||
let MacroDef { body, legacy: _ } = macro_def;
|
||||
visit_mac_args(body, vis);
|
||||
}
|
||||
|
||||
pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) {
|
||||
@ -682,9 +701,9 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
|
||||
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
|
||||
token::NtLifetime(ident) => vis.visit_ident(ident),
|
||||
token::NtLiteral(expr) => vis.visit_expr(expr),
|
||||
token::NtMeta(AttrItem { path, tokens }) => {
|
||||
token::NtMeta(AttrItem { path, args }) => {
|
||||
vis.visit_path(path);
|
||||
vis.visit_tts(tokens);
|
||||
visit_mac_args(args, vis);
|
||||
}
|
||||
token::NtPath(path) => vis.visit_path(path),
|
||||
token::NtTT(tt) => vis.visit_tt(tt),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
|
||||
use crate::ast::{SelfKind, GenericBound, TraitBoundModifier};
|
||||
use crate::ast::{Attribute, MacDelimiter, GenericArg};
|
||||
use crate::ast::{Attribute, GenericArg, MacArgs};
|
||||
use crate::util::parser::{self, AssocOp, Fixity};
|
||||
use crate::util::comments;
|
||||
use crate::attr;
|
||||
@ -639,17 +639,22 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
|
||||
fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
|
||||
self.ibox(0);
|
||||
match item.tokens.trees().next() {
|
||||
Some(TokenTree::Delimited(_, delim, tts)) => {
|
||||
self.print_mac_common(
|
||||
Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span
|
||||
);
|
||||
}
|
||||
tree => {
|
||||
match &item.args {
|
||||
MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
|
||||
Some(MacHeader::Path(&item.path)),
|
||||
false,
|
||||
None,
|
||||
delim.to_token(),
|
||||
tokens.clone(),
|
||||
true,
|
||||
span,
|
||||
),
|
||||
MacArgs::Empty | MacArgs::Eq(..) => {
|
||||
self.print_path(&item.path, false, 0);
|
||||
if tree.is_some() {
|
||||
if let MacArgs::Eq(_, tokens) = &item.args {
|
||||
self.space();
|
||||
self.print_tts(item.tokens.clone(), true);
|
||||
self.word_space("=");
|
||||
self.print_tts(tokens.clone(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1097,9 +1102,8 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::ForeignItemKind::Macro(ref m) => {
|
||||
self.print_mac(m);
|
||||
match m.delim {
|
||||
MacDelimiter::Brace => {},
|
||||
_ => self.s.word(";")
|
||||
if m.args.need_semicolon() {
|
||||
self.s.word(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1361,9 +1365,8 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::ItemKind::Mac(ref mac) => {
|
||||
self.print_mac(mac);
|
||||
match mac.delim {
|
||||
MacDelimiter::Brace => {}
|
||||
_ => self.s.word(";"),
|
||||
if mac.args.need_semicolon() {
|
||||
self.s.word(";");
|
||||
}
|
||||
}
|
||||
ast::ItemKind::MacroDef(ref macro_def) => {
|
||||
@ -1377,8 +1380,8 @@ impl<'a> State<'a> {
|
||||
Some(MacHeader::Keyword(kw)),
|
||||
has_bang,
|
||||
Some(item.ident),
|
||||
DelimToken::Brace,
|
||||
macro_def.stream(),
|
||||
macro_def.body.delim(),
|
||||
macro_def.body.inner_tokens(),
|
||||
true,
|
||||
item.span,
|
||||
);
|
||||
@ -1578,9 +1581,8 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::TraitItemKind::Macro(ref mac) => {
|
||||
self.print_mac(mac);
|
||||
match mac.delim {
|
||||
MacDelimiter::Brace => {}
|
||||
_ => self.s.word(";"),
|
||||
if mac.args.need_semicolon() {
|
||||
self.s.word(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1608,9 +1610,8 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::ImplItemKind::Macro(ref mac) => {
|
||||
self.print_mac(mac);
|
||||
match mac.delim {
|
||||
MacDelimiter::Brace => {}
|
||||
_ => self.s.word(";"),
|
||||
if mac.args.need_semicolon() {
|
||||
self.s.word(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1775,10 +1776,10 @@ impl<'a> State<'a> {
|
||||
Some(MacHeader::Path(&m.path)),
|
||||
true,
|
||||
None,
|
||||
m.delim.to_token(),
|
||||
m.stream(),
|
||||
m.args.delim(),
|
||||
m.args.inner_tokens(),
|
||||
true,
|
||||
m.span,
|
||||
m.span(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,14 @@ impl TokenStream {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
match &**self.0 {
|
||||
[] => None,
|
||||
[(tt, _)] => Some(tt.span()),
|
||||
[(tt_start, _), .., (tt_end, _)] => Some(tt_start.span().to(tt_end.span())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream {
|
||||
match streams.len() {
|
||||
0 => TokenStream::default(),
|
||||
|
@ -841,11 +841,19 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
|
||||
|
||||
pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) {
|
||||
match attr.kind {
|
||||
AttrKind::Normal(ref item) => visitor.visit_tts(item.tokens.clone()),
|
||||
AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args),
|
||||
AttrKind::DocComment(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
|
||||
match args {
|
||||
MacArgs::Empty => {}
|
||||
MacArgs::Delimited(_dspan, _delim, tokens) => visitor.visit_tts(tokens.clone()),
|
||||
MacArgs::Eq(_eq_span, tokens) => visitor.visit_tts(tokens.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) {
|
||||
match tt {
|
||||
TokenTree::Token(token) => visitor.visit_token(token),
|
||||
|
@ -11,7 +11,7 @@ use rustc_parse::DirectoryOwnership;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse::validate_attr;
|
||||
use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
|
||||
use syntax::ast::{MacStmtStyle, StmtKind, ItemKind};
|
||||
use syntax::ast::{MacArgs, MacStmtStyle, StmtKind, ItemKind};
|
||||
use syntax::attr::{self, HasAttrs, is_builtin_attr};
|
||||
use syntax::source_map::respan;
|
||||
use syntax::feature_gate::{self, feature_err};
|
||||
@ -597,13 +597,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
InvocationKind::Bang { mac, .. } => match ext {
|
||||
SyntaxExtensionKind::Bang(expander) => {
|
||||
self.gate_proc_macro_expansion_kind(span, fragment_kind);
|
||||
let tok_result = expander.expand(self.cx, span, mac.stream());
|
||||
let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens());
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
|
||||
}
|
||||
SyntaxExtensionKind::LegacyBang(expander) => {
|
||||
let prev = self.cx.current_expansion.prior_type_ascription;
|
||||
self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription;
|
||||
let tok_result = expander.expand(self.cx, span, mac.stream());
|
||||
let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens());
|
||||
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
|
||||
result
|
||||
} else {
|
||||
@ -642,8 +642,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
=> panic!("unexpected annotatable"),
|
||||
})), DUMMY_SP).into();
|
||||
let item = attr.unwrap_normal_item();
|
||||
let input = self.extract_proc_macro_attr_input(item.tokens, span);
|
||||
let tok_result = expander.expand(self.cx, span, input, item_tok);
|
||||
if let MacArgs::Eq(..) = item.args {
|
||||
self.cx.span_err(span, "key-value macro attributes are not supported");
|
||||
}
|
||||
let tok_result =
|
||||
expander.expand(self.cx, span, item.args.inner_tokens(), item_tok);
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span)
|
||||
}
|
||||
SyntaxExtensionKind::LegacyAttr(expander) => {
|
||||
@ -687,23 +690,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream {
|
||||
let mut trees = tokens.trees();
|
||||
match trees.next() {
|
||||
Some(TokenTree::Delimited(_, _, tts)) => {
|
||||
if trees.next().is_none() {
|
||||
return tts.into()
|
||||
}
|
||||
}
|
||||
Some(TokenTree::Token(..)) => {}
|
||||
None => return TokenStream::default(),
|
||||
}
|
||||
self.cx.span_err(span, "custom attribute invocations must be \
|
||||
of the form `#[foo]` or `#[foo(..)]`, the macro name must only be \
|
||||
followed by a delimiter token");
|
||||
TokenStream::default()
|
||||
}
|
||||
|
||||
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
|
||||
let kind = match item {
|
||||
Annotatable::Item(item) => match &item.kind {
|
||||
@ -1560,7 +1546,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
||||
let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
|
||||
*at = attr::Attribute {
|
||||
kind: ast::AttrKind::Normal(
|
||||
AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
|
||||
AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span) },
|
||||
),
|
||||
span: at.span,
|
||||
id: at.id,
|
||||
|
@ -318,8 +318,8 @@ pub fn compile_declarative_macro(
|
||||
let tt_spec = ast::Ident::new(sym::tt, def.span);
|
||||
|
||||
// Parse the macro_rules! invocation
|
||||
let body = match def.kind {
|
||||
ast::ItemKind::MacroDef(ref body) => body,
|
||||
let (is_legacy, body) = match &def.kind {
|
||||
ast::ItemKind::MacroDef(macro_def) => (macro_def.legacy, macro_def.body.inner_tokens()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@ -338,7 +338,7 @@ pub fn compile_declarative_macro(
|
||||
mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
|
||||
],
|
||||
separator: Some(Token::new(
|
||||
if body.legacy { token::Semi } else { token::Comma },
|
||||
if is_legacy { token::Semi } else { token::Comma },
|
||||
def.span,
|
||||
)),
|
||||
kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span),
|
||||
@ -350,7 +350,7 @@ pub fn compile_declarative_macro(
|
||||
DelimSpan::dummy(),
|
||||
Lrc::new(mbe::SequenceRepetition {
|
||||
tts: vec![mbe::TokenTree::token(
|
||||
if body.legacy { token::Semi } else { token::Comma },
|
||||
if is_legacy { token::Semi } else { token::Comma },
|
||||
def.span,
|
||||
)],
|
||||
separator: None,
|
||||
@ -360,7 +360,7 @@ pub fn compile_declarative_macro(
|
||||
),
|
||||
];
|
||||
|
||||
let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) {
|
||||
let argument_map = match parse(sess, body, &argument_gram, None, true) {
|
||||
Success(m) => m,
|
||||
Failure(token, msg) => {
|
||||
let s = parse_failure_msg(&token);
|
||||
@ -435,7 +435,7 @@ pub fn compile_declarative_macro(
|
||||
// that is not lint-checked and trigger the "failed to process buffered lint here" bug.
|
||||
valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses);
|
||||
|
||||
let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy);
|
||||
let (transparency, transparency_error) = attr::find_transparency(&def.attrs, is_legacy);
|
||||
match transparency_error {
|
||||
Some(TransparencyError::UnknownTransparency(value, span)) =>
|
||||
diag.span_err(span, &format!("unknown macro transparency: `{}`", value)),
|
||||
|
@ -30,13 +30,6 @@ impl MutVisitor for Marker {
|
||||
}
|
||||
}
|
||||
|
||||
impl Marker {
|
||||
fn visit_delim_span(&mut self, dspan: &mut DelimSpan) {
|
||||
self.visit_span(&mut dspan.open);
|
||||
self.visit_span(&mut dspan.close);
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
|
||||
enum Frame {
|
||||
Delimited { forest: Lrc<mbe::Delimited>, idx: usize, span: DelimSpan },
|
||||
@ -271,7 +264,7 @@ pub(super) fn transcribe(
|
||||
// jump back out of the Delimited, pop the result_stack and add the new results back to
|
||||
// the previous results (from outside the Delimited).
|
||||
mbe::TokenTree::Delimited(mut span, delimited) => {
|
||||
marker.visit_delim_span(&mut span);
|
||||
mut_visit::visit_delim_span(&mut span, &mut marker);
|
||||
stack.push(Frame::Delimited { forest: delimited, idx: 0, span });
|
||||
result_stack.push(mem::take(&mut result));
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ fn ttdelim_span() {
|
||||
"foo!( fn main() { body } )".to_string(), &sess).unwrap();
|
||||
|
||||
let tts: Vec<_> = match expr.kind {
|
||||
ast::ExprKind::Mac(ref mac) => mac.stream().trees().collect(),
|
||||
ast::ExprKind::Mac(ref mac) => mac.args.inner_tokens().trees().collect(),
|
||||
_ => panic!("not a macro"),
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,6 @@ use crate::expand::{AstFragment, AstFragmentKind};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::source_map::{DUMMY_SP, dummy_spanned};
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use syntax::mut_visit::*;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ThinVec;
|
||||
@ -17,9 +16,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visi
|
||||
fn mac_placeholder() -> ast::Mac {
|
||||
ast::Mac {
|
||||
path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
|
||||
tts: TokenStream::default().into(),
|
||||
delim: ast::MacDelimiter::Brace,
|
||||
span: DUMMY_SP,
|
||||
args: P(ast::MacArgs::Empty),
|
||||
prior_type_ascription: None,
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::base::{self, *};
|
||||
use crate::proc_macro_server;
|
||||
|
||||
use syntax::ast::{self, ItemKind};
|
||||
use syntax::ast::{self, ItemKind, MacArgs};
|
||||
use syntax::errors::{Applicability, FatalError};
|
||||
use syntax::symbol::sym;
|
||||
use syntax::token;
|
||||
@ -183,7 +183,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
|
||||
}
|
||||
|
||||
let parse_derive_paths = |attr: &ast::Attribute| {
|
||||
if attr.get_normal_item().tokens.is_empty() {
|
||||
if let MacArgs::Empty = attr.get_normal_item().args {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths())
|
||||
|
@ -6,7 +6,7 @@ use syntax::token::{self, TokenKind};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{sym, Symbol};
|
||||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
||||
use syntax_expand::base::*;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
@ -26,19 +26,19 @@ pub fn expand_assert<'cx>(
|
||||
// `core::panic` and `std::panic` are different macros, so we use call-site
|
||||
// context to pick up whichever is currently in scope.
|
||||
let sp = cx.with_call_site_ctxt(sp);
|
||||
let tokens = custom_message.unwrap_or_else(|| {
|
||||
TokenStream::from(TokenTree::token(
|
||||
TokenKind::lit(token::Str, Symbol::intern(&format!(
|
||||
"assertion failed: {}",
|
||||
pprust::expr_to_string(&cond_expr).escape_debug()
|
||||
)), None),
|
||||
DUMMY_SP,
|
||||
))
|
||||
});
|
||||
let args = P(MacArgs::Delimited(DelimSpan::from_single(sp), MacDelimiter::Parenthesis, tokens));
|
||||
let panic_call = Mac {
|
||||
path: Path::from_ident(Ident::new(sym::panic, sp)),
|
||||
tts: custom_message.unwrap_or_else(|| {
|
||||
TokenStream::from(TokenTree::token(
|
||||
TokenKind::lit(token::Str, Symbol::intern(&format!(
|
||||
"assertion failed: {}",
|
||||
pprust::expr_to_string(&cond_expr).escape_debug()
|
||||
)), None),
|
||||
DUMMY_SP,
|
||||
))
|
||||
}).into(),
|
||||
delim: MacDelimiter::Parenthesis,
|
||||
span: sp,
|
||||
args,
|
||||
prior_type_ascription: None,
|
||||
};
|
||||
let if_expr = cx.expr_if(
|
||||
|
@ -16,7 +16,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
|
||||
);
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { path, tokens } = panictry!(parser.parse_attr_item());
|
||||
let AttrItem { path, args } = panictry!(parser.parse_attr_item());
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
parse_sess.span_diagnostic
|
||||
@ -24,7 +24,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
|
||||
continue;
|
||||
}
|
||||
|
||||
krate.attrs.push(mk_attr(AttrStyle::Inner, path, tokens, start_span.to(end_span)));
|
||||
krate.attrs.push(mk_attr(AttrStyle::Inner, path, args, start_span.to(end_span)));
|
||||
}
|
||||
|
||||
krate
|
||||
|
@ -340,14 +340,12 @@ pub fn combine_substructure(f: CombineSubstructureFunc<'_>)
|
||||
fn find_type_parameters(
|
||||
ty: &ast::Ty,
|
||||
ty_param_names: &[ast::Name],
|
||||
span: Span,
|
||||
cx: &ExtCtxt<'_>,
|
||||
) -> Vec<P<ast::Ty>> {
|
||||
use syntax::visit;
|
||||
|
||||
struct Visitor<'a, 'b> {
|
||||
cx: &'a ExtCtxt<'b>,
|
||||
span: Span,
|
||||
ty_param_names: &'a [ast::Name],
|
||||
types: Vec<P<ast::Ty>>,
|
||||
}
|
||||
@ -366,18 +364,11 @@ fn find_type_parameters(
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, mac: &ast::Mac) {
|
||||
let span = mac.span.with_ctxt(self.span.ctxt());
|
||||
self.cx.span_err(span, "`derive` cannot be used on items with type macros");
|
||||
self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = Visitor {
|
||||
ty_param_names,
|
||||
types: Vec::new(),
|
||||
span,
|
||||
cx,
|
||||
};
|
||||
|
||||
let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() };
|
||||
visit::Visitor::visit_ty(&mut visitor, ty);
|
||||
|
||||
visitor.types
|
||||
@ -605,7 +596,7 @@ impl<'a> TraitDef<'a> {
|
||||
.collect();
|
||||
|
||||
for field_ty in field_tys {
|
||||
let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx);
|
||||
let tys = find_type_parameters(&field_ty, &ty_param_names, cx);
|
||||
|
||||
for ty in tys {
|
||||
// if we have already handled this type, skip it
|
||||
|
@ -280,6 +280,7 @@ symbols! {
|
||||
Err,
|
||||
Eq,
|
||||
Equal,
|
||||
enclosing_scope,
|
||||
except,
|
||||
exclusive_range_pattern,
|
||||
exhaustive_integer_patterns,
|
||||
|
@ -1,8 +1,14 @@
|
||||
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-on-option-in-async.rs:8:9
|
||||
|
|
||||
LL | x?;
|
||||
| ^^ cannot use the `?` operator in an async block that returns `{integer}`
|
||||
LL | async {
|
||||
| ___________-
|
||||
LL | | let x: Option<u32> = None;
|
||||
LL | | x?;
|
||||
| | ^^ cannot use the `?` operator in an async block that returns `{integer}`
|
||||
LL | | 22
|
||||
LL | | }.await
|
||||
| |_____- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `{integer}`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
@ -10,8 +16,14 @@ LL | x?;
|
||||
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-on-option-in-async.rs:16:9
|
||||
|
|
||||
LL | x?;
|
||||
| ^^ cannot use the `?` operator in an async closure that returns `u32`
|
||||
LL | let async_closure = async || {
|
||||
| __________________________________-
|
||||
LL | | let x: Option<u32> = None;
|
||||
LL | | x?;
|
||||
| | ^^ cannot use the `?` operator in an async closure that returns `u32`
|
||||
LL | | 22_u32
|
||||
LL | | };
|
||||
| |_____- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `u32`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
@ -19,8 +31,14 @@ LL | x?;
|
||||
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-on-option-in-async.rs:25:5
|
||||
|
|
||||
LL | x?;
|
||||
| ^^ cannot use the `?` operator in an async function that returns `u32`
|
||||
LL | async fn an_async_function() -> u32 {
|
||||
| _____________________________________-
|
||||
LL | | let x: Option<u32> = None;
|
||||
LL | | x?;
|
||||
| | ^^ cannot use the `?` operator in an async function that returns `u32`
|
||||
LL | | 22
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `u32`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
|
@ -11,9 +11,9 @@ macro_rules! foo{
|
||||
pub fn main() {
|
||||
foo!();
|
||||
|
||||
assert!({one! two()}); //~ ERROR expected open delimiter
|
||||
assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
|
||||
|
||||
// regardless of whether nested macro_rules works, the following should at
|
||||
// least throw a conventional error.
|
||||
assert!({one! two}); //~ ERROR expected open delimiter
|
||||
assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
error: expected open delimiter
|
||||
error: expected one of `(`, `[`, or `{`, found `two`
|
||||
--> $DIR/issue-10536.rs:14:19
|
||||
|
|
||||
LL | assert!({one! two()});
|
||||
| ^^^ expected open delimiter
|
||||
| ^^^ expected one of `(`, `[`, or `{`
|
||||
|
||||
error: expected open delimiter
|
||||
error: expected one of `(`, `[`, or `{`, found `two`
|
||||
--> $DIR/issue-10536.rs:18:19
|
||||
|
|
||||
LL | assert!({one! two});
|
||||
| ^^^ expected open delimiter
|
||||
| ^^^ expected one of `(`, `[`, or `{`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
27
src/test/ui/on-unimplemented/enclosing-scope.rs
Normal file
27
src/test/ui/on-unimplemented/enclosing-scope.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Test scope annotations from `enclosing_scope` parameter
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_on_unimplemented(enclosing_scope="in this scope")]
|
||||
trait Trait{}
|
||||
|
||||
struct Foo;
|
||||
|
||||
fn f<T: Trait>(x: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = || {
|
||||
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
|
||||
let y = || {
|
||||
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
|
||||
};
|
||||
};
|
||||
|
||||
{
|
||||
{
|
||||
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
|
||||
}
|
||||
}
|
||||
|
||||
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
|
||||
}
|
66
src/test/ui/on-unimplemented/enclosing-scope.stderr
Normal file
66
src/test/ui/on-unimplemented/enclosing-scope.stderr
Normal file
@ -0,0 +1,66 @@
|
||||
error[E0277]: the trait bound `Foo: Trait` is not satisfied
|
||||
--> $DIR/enclosing-scope.rs:14:11
|
||||
|
|
||||
LL | fn f<T: Trait>(x: T) {}
|
||||
| - ----- required by this bound in `f`
|
||||
...
|
||||
LL | let x = || {
|
||||
| _____________-
|
||||
LL | | f(Foo{});
|
||||
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
|
||||
LL | | let y = || {
|
||||
LL | | f(Foo{});
|
||||
LL | | };
|
||||
LL | | };
|
||||
| |_____- in this scope
|
||||
|
||||
error[E0277]: the trait bound `Foo: Trait` is not satisfied
|
||||
--> $DIR/enclosing-scope.rs:16:15
|
||||
|
|
||||
LL | fn f<T: Trait>(x: T) {}
|
||||
| - ----- required by this bound in `f`
|
||||
...
|
||||
LL | let y = || {
|
||||
| _________________-
|
||||
LL | | f(Foo{});
|
||||
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
|
||||
LL | | };
|
||||
| |_________- in this scope
|
||||
|
||||
error[E0277]: the trait bound `Foo: Trait` is not satisfied
|
||||
--> $DIR/enclosing-scope.rs:22:15
|
||||
|
|
||||
LL | fn f<T: Trait>(x: T) {}
|
||||
| - ----- required by this bound in `f`
|
||||
LL |
|
||||
LL | / fn main() {
|
||||
LL | | let x = || {
|
||||
LL | | f(Foo{});
|
||||
LL | | let y = || {
|
||||
... |
|
||||
LL | | f(Foo{});
|
||||
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
|
||||
... |
|
||||
LL | | f(Foo{});
|
||||
LL | | }
|
||||
| |_- in this scope
|
||||
|
||||
error[E0277]: the trait bound `Foo: Trait` is not satisfied
|
||||
--> $DIR/enclosing-scope.rs:26:7
|
||||
|
|
||||
LL | fn f<T: Trait>(x: T) {}
|
||||
| - ----- required by this bound in `f`
|
||||
LL |
|
||||
LL | / fn main() {
|
||||
LL | | let x = || {
|
||||
LL | | f(Foo{});
|
||||
LL | | let y = || {
|
||||
... |
|
||||
LL | | f(Foo{});
|
||||
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
|
||||
LL | | }
|
||||
| |_- in this scope
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -6,35 +6,40 @@
|
||||
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
|
||||
fn main() {
|
||||
// Get the fatal error out of the way
|
||||
match (0u8,) {
|
||||
match (0,) {
|
||||
(0 | _,) => {}
|
||||
//~^ ERROR or-patterns are not fully implemented yet
|
||||
}
|
||||
|
||||
match (0u8,) {
|
||||
match (0,) {
|
||||
(1 | 2,) => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match (0u8,) {
|
||||
(1 | 1,) => {} // FIXME(or_patterns): redundancy not detected for now.
|
||||
_ => {}
|
||||
}
|
||||
match (0u8, 0u8) {
|
||||
match (0, 0) {
|
||||
(1 | 2, 3 | 4) => {}
|
||||
(1, 2) => {}
|
||||
(2, 1) => {}
|
||||
(3, 1) => {}
|
||||
_ => {}
|
||||
}
|
||||
match (Some(0u8),) {
|
||||
(None | Some(0 | 1),) => {}
|
||||
(Some(2..=255),) => {}
|
||||
}
|
||||
match ((0u8,),) {
|
||||
match ((0,),) {
|
||||
((0 | 1,) | (2 | 3,),) => {},
|
||||
((_,),) => {},
|
||||
}
|
||||
match (&[0u8][..],) {
|
||||
([] | [0 | 1..=255] | [_, ..],) => {},
|
||||
}
|
||||
|
||||
match ((0, 0),) {
|
||||
((0, 0) | (0, 1),) => {}
|
||||
_ => {}
|
||||
}
|
||||
match ((0, 0),) {
|
||||
((0, 0) | (1, 0),) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -48,4 +48,32 @@ fn main() {
|
||||
((1..=4,),) => {}, //~ ERROR unreachable pattern
|
||||
_ => {},
|
||||
}
|
||||
|
||||
match (0,) {
|
||||
(1
|
||||
| 1,) => {} //~ ERROR unreachable
|
||||
_ => {}
|
||||
}
|
||||
match [0; 2] {
|
||||
[0
|
||||
| 0 //~ ERROR unreachable
|
||||
, 0
|
||||
| 0] => {} //~ ERROR unreachable
|
||||
_ => {}
|
||||
}
|
||||
match &[][..] {
|
||||
[0] => {}
|
||||
[0, _] => {}
|
||||
[0, _, _] => {}
|
||||
[1, ..] => {}
|
||||
[1 //~ ERROR unreachable
|
||||
| 2, ..] => {}
|
||||
_ => {}
|
||||
}
|
||||
match Some(0) {
|
||||
Some(0) => {}
|
||||
Some(0 //~ ERROR unreachable
|
||||
| 1) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -70,11 +70,41 @@ error: unreachable pattern
|
||||
LL | ((1..=4,),) => {},
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:54:12
|
||||
|
|
||||
LL | | 1,) => {}
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:61:15
|
||||
|
|
||||
LL | | 0] => {}
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:59:15
|
||||
|
|
||||
LL | | 0
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:69:10
|
||||
|
|
||||
LL | [1
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:75:14
|
||||
|
|
||||
LL | Some(0
|
||||
| ^
|
||||
|
||||
error: or-patterns are not fully implemented yet
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:10:10
|
||||
|
|
||||
LL | (0 | _,) => {}
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
fn main() {
|
||||
foo! bar < //~ ERROR expected open delimiter
|
||||
foo! bar < //~ ERROR expected one of `(`, `[`, or `{`, found `bar`
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: expected open delimiter
|
||||
error: expected one of `(`, `[`, or `{`, found `bar`
|
||||
--> $DIR/macro-bad-delimiter-ident.rs:2:10
|
||||
|
|
||||
LL | foo! bar <
|
||||
| ^^^ expected open delimiter
|
||||
| ^^^ expected one of `(`, `[`, or `{`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
56
src/test/ui/pattern/usefulness/top-level-alternation.rs
Normal file
56
src/test/ui/pattern/usefulness/top-level-alternation.rs
Normal file
@ -0,0 +1,56 @@
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
fn main() {
|
||||
while let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
|
||||
if let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
|
||||
|
||||
match 0u8 {
|
||||
0
|
||||
| 0 => {} //~ ERROR unreachable pattern
|
||||
_ => {}
|
||||
}
|
||||
match Some(0u8) {
|
||||
Some(0)
|
||||
| Some(0) => {} //~ ERROR unreachable pattern
|
||||
_ => {}
|
||||
}
|
||||
match (0u8, 0u8) {
|
||||
(0, _) | (_, 0) => {}
|
||||
(0, 0) => {} //~ ERROR unreachable pattern
|
||||
(1, 1) => {}
|
||||
_ => {}
|
||||
}
|
||||
match (0u8, 0u8) {
|
||||
(0, 1) | (2, 3) => {}
|
||||
(0, 3) => {}
|
||||
(2, 1) => {}
|
||||
_ => {}
|
||||
}
|
||||
match (0u8, 0u8) {
|
||||
(_, 0) | (_, 1) => {}
|
||||
_ => {}
|
||||
}
|
||||
match (0u8, 0u8) {
|
||||
(0, _) | (1, _) => {}
|
||||
_ => {}
|
||||
}
|
||||
match Some(0u8) {
|
||||
None | Some(_) => {}
|
||||
_ => {} //~ ERROR unreachable pattern
|
||||
}
|
||||
match Some(0u8) {
|
||||
None | Some(_) => {}
|
||||
Some(_) => {} //~ ERROR unreachable pattern
|
||||
None => {} //~ ERROR unreachable pattern
|
||||
}
|
||||
match Some(0u8) {
|
||||
Some(_) => {}
|
||||
None => {}
|
||||
None | Some(_) => {} //~ ERROR unreachable pattern
|
||||
}
|
||||
match 0u8 {
|
||||
1 | 2 => {},
|
||||
1..=2 => {}, //~ ERROR unreachable pattern
|
||||
_ => {},
|
||||
}
|
||||
}
|
68
src/test/ui/pattern/usefulness/top-level-alternation.stderr
Normal file
68
src/test/ui/pattern/usefulness/top-level-alternation.stderr
Normal file
@ -0,0 +1,68 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:4:23
|
||||
|
|
||||
LL | while let 0..=2 | 1 = 0 {}
|
||||
| ^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/top-level-alternation.rs:1:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:5:20
|
||||
|
|
||||
LL | if let 0..=2 | 1 = 0 {}
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:9:15
|
||||
|
|
||||
LL | | 0 => {}
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:14:15
|
||||
|
|
||||
LL | | Some(0) => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:19:9
|
||||
|
|
||||
LL | (0, 0) => {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:39:9
|
||||
|
|
||||
LL | _ => {}
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:43:9
|
||||
|
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:44:9
|
||||
|
|
||||
LL | None => {}
|
||||
| ^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:49:9
|
||||
|
|
||||
LL | None | Some(_) => {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/top-level-alternation.rs:53:9
|
||||
|
|
||||
LL | 1..=2 => {},
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
@ -18,7 +18,7 @@ mod _test2_inner {
|
||||
//~| ERROR: non-builtin inner attributes are unstable
|
||||
}
|
||||
|
||||
#[empty_attr = "y"] //~ ERROR: must only be followed by a delimiter token
|
||||
#[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported
|
||||
fn _test3() {}
|
||||
|
||||
fn attrs() {
|
||||
|
@ -34,7 +34,7 @@ LL | #![empty_attr]
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/54727
|
||||
= help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
|
||||
|
||||
error: custom attribute invocations must be of the form `#[foo]` or `#[foo(..)]`, the macro name must only be followed by a delimiter token
|
||||
error: key-value macro attributes are not supported
|
||||
--> $DIR/proc-macro-gates.rs:21:1
|
||||
|
|
||||
LL | #[empty_attr = "y"]
|
||||
|
@ -575,8 +575,17 @@ LL | if (let 0 = 0)? {}
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/disallowed-positions.rs:46:8
|
||||
|
|
||||
LL | if (let 0 = 0)? {}
|
||||
| ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
LL | / fn nested_within_if_expr() {
|
||||
LL | | if &let 0 = 0 {}
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | if (let 0 = 0)? {}
|
||||
| | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
... |
|
||||
LL | | if let true = let true = true {}
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
@ -754,8 +763,17 @@ LL | while (let 0 = 0)? {}
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/disallowed-positions.rs:110:11
|
||||
|
|
||||
LL | while (let 0 = 0)? {}
|
||||
| ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
LL | / fn nested_within_while_expr() {
|
||||
LL | | while &let 0 = 0 {}
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | while (let 0 = 0)? {}
|
||||
| | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
... |
|
||||
LL | | while let true = let true = true {}
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
@ -924,8 +942,17 @@ LL | (let 0 = 0)?;
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/disallowed-positions.rs:183:5
|
||||
|
|
||||
LL | (let 0 = 0)?;
|
||||
| ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
LL | / fn outside_if_and_while_expr() {
|
||||
LL | | &let 0 = 0;
|
||||
LL | |
|
||||
LL | | !let 0 = 0;
|
||||
... |
|
||||
LL | | (let 0 = 0)?;
|
||||
| | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
... |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
|
@ -1,8 +1,13 @@
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-on-option-diagnostics.rs:7:5
|
||||
|
|
||||
LL | x?;
|
||||
| ^^ cannot use the `?` operator in a function that returns `u32`
|
||||
LL | / fn a_function() -> u32 {
|
||||
LL | | let x: Option<u32> = None;
|
||||
LL | | x?;
|
||||
| | ^^ cannot use the `?` operator in a function that returns `u32`
|
||||
LL | | 22
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `u32`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
@ -10,8 +15,14 @@ LL | x?;
|
||||
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-on-option-diagnostics.rs:14:9
|
||||
|
|
||||
LL | x?;
|
||||
| ^^ cannot use the `?` operator in a closure that returns `{integer}`
|
||||
LL | let a_closure = || {
|
||||
| _____________________-
|
||||
LL | | let x: Option<u32> = None;
|
||||
LL | | x?;
|
||||
| | ^^ cannot use the `?` operator in a closure that returns `{integer}`
|
||||
LL | | 22
|
||||
LL | | };
|
||||
| |_____- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `{integer}`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
|
@ -10,8 +10,13 @@ LL | x?;
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-on-option.rs:13:5
|
||||
|
|
||||
LL | x?;
|
||||
| ^^ cannot use the `?` operator in a function that returns `u32`
|
||||
LL | / fn bar() -> u32 {
|
||||
LL | | let x: Option<u32> = None;
|
||||
LL | | x?;
|
||||
| | ^^ cannot use the `?` operator in a function that returns `u32`
|
||||
LL | | 22
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `u32`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
|
@ -1,8 +1,15 @@
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> $DIR/try-operator-on-main.rs:9:5
|
||||
|
|
||||
LL | std::fs::File::open("foo")?;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
LL | / fn main() {
|
||||
LL | | // error for a `Try` type on a non-`Try` fn
|
||||
LL | | std::fs::File::open("foo")?;
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
LL | |
|
||||
... |
|
||||
LL | | try_trait_generic::<()>();
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
|
Loading…
Reference in New Issue
Block a user