Auto merge of #63575 - Centril:rollup-anlv9g5, r=Centril
Rollup of 11 pull requests Successful merges: - #62984 (Add lint for excess trailing semicolons) - #63075 (Miri: Check that a ptr is aligned and inbounds already when evaluating `*`) - #63490 (libsyntax: cleanup and refactor `pat.rs`) - #63507 (When needing type annotations in local bindings, account for impl Trait and closures) - #63509 (Point at the right enclosing scope when using `await` in non-async fn) - #63528 (syntax: Remove `DummyResult::expr_only`) - #63537 (expand: Unimplement `MutVisitor` on `MacroExpander`) - #63542 (Add NodeId for Arm, Field and FieldPat) - #63543 (Merge Variant and Variant_) - #63560 (move test that shouldn't be in test/run-pass/) - #63570 (Adjust tracking issues for `MaybeUninit<T>` gates) Failed merges: r? @ghost
This commit is contained in:
commit
9e9a136fce
102 changed files with 1078 additions and 559 deletions
|
|
@ -312,7 +312,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// without dropping it, so be careful not to use this twice unless you want to
|
||||
/// skip running the destructor. For your convenience, this also returns a mutable
|
||||
/// reference to the (now safely initialized) contents of `self`.
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub fn write(&mut self, val: T) -> &mut T {
|
||||
unsafe {
|
||||
|
|
@ -502,7 +502,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// // We now created two copies of the same vector, leading to a double-free when
|
||||
/// // they both get dropped!
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn read(&self) -> T {
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
|
|
@ -516,7 +516,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
|
||||
/// state. Calling this when the content is not yet fully initialized causes undefined
|
||||
/// behavior.
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_ref(&self) -> &T {
|
||||
&*self.value
|
||||
|
|
@ -532,21 +532,21 @@ impl<T> MaybeUninit<T> {
|
|||
// FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
|
||||
// to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
|
||||
// a final decision about the rules before stabilization.
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_mut(&mut self) -> &mut T {
|
||||
&mut *self.value
|
||||
}
|
||||
|
||||
/// Gets a pointer to the first element of the array.
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[inline(always)]
|
||||
pub fn first_ptr(this: &[MaybeUninit<T>]) -> *const T {
|
||||
this as *const [MaybeUninit<T>] as *const T
|
||||
}
|
||||
|
||||
/// Gets a mutable pointer to the first element of the array.
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[inline(always)]
|
||||
pub fn first_ptr_mut(this: &mut [MaybeUninit<T>]) -> *mut T {
|
||||
this as *mut [MaybeUninit<T>] as *mut T
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
|||
fn is_c_like_enum(item: &hir::Item) -> bool {
|
||||
if let hir::ItemKind::Enum(ref def, _) = item.node {
|
||||
for variant in &def.variants {
|
||||
match variant.node.data {
|
||||
match variant.data {
|
||||
hir::VariantData::Unit(..) => { /* continue */ }
|
||||
_ => { return false; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -577,15 +577,15 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
variant: &'v Variant,
|
||||
generics: &'v Generics,
|
||||
parent_item_id: HirId) {
|
||||
visitor.visit_ident(variant.node.ident);
|
||||
visitor.visit_id(variant.node.id);
|
||||
visitor.visit_variant_data(&variant.node.data,
|
||||
variant.node.ident.name,
|
||||
visitor.visit_ident(variant.ident);
|
||||
visitor.visit_id(variant.id);
|
||||
visitor.visit_variant_data(&variant.data,
|
||||
variant.ident.name,
|
||||
generics,
|
||||
parent_item_id,
|
||||
variant.span);
|
||||
walk_list!(visitor, visit_anon_const, &variant.node.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.node.attrs);
|
||||
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
|
||||
|
|
|
|||
|
|
@ -677,6 +677,7 @@ impl LoweringContext<'_> {
|
|||
let fn_decl = self.lower_fn_decl(decl, None, false, None);
|
||||
|
||||
self.with_new_scopes(|this| {
|
||||
let prev = this.current_item;
|
||||
this.current_item = Some(fn_decl_span);
|
||||
let mut generator_kind = None;
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
|
|
@ -690,8 +691,10 @@ impl LoweringContext<'_> {
|
|||
generator_kind,
|
||||
movability,
|
||||
);
|
||||
let capture_clause = this.lower_capture_clause(capture_clause);
|
||||
this.current_item = prev;
|
||||
hir::ExprKind::Closure(
|
||||
this.lower_capture_clause(capture_clause),
|
||||
capture_clause,
|
||||
fn_decl,
|
||||
body_id,
|
||||
fn_decl_span,
|
||||
|
|
|
|||
|
|
@ -757,14 +757,12 @@ impl LoweringContext<'_> {
|
|||
}
|
||||
|
||||
fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
|
||||
Spanned {
|
||||
node: hir::VariantKind {
|
||||
ident: v.node.ident,
|
||||
id: self.lower_node_id(v.node.id),
|
||||
attrs: self.lower_attrs(&v.node.attrs),
|
||||
data: self.lower_variant_data(&v.node.data),
|
||||
disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
|
||||
},
|
||||
hir::Variant {
|
||||
attrs: self.lower_attrs(&v.attrs),
|
||||
data: self.lower_variant_data(&v.data),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
|
||||
id: self.lower_node_id(v.id),
|
||||
ident: v.ident,
|
||||
span: v.span,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -544,11 +544,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: HirId) {
|
||||
self.insert(v.span, v.node.id, Node::Variant(v));
|
||||
self.with_parent(v.node.id, |this| {
|
||||
self.insert(v.span, v.id, Node::Variant(v));
|
||||
self.with_parent(v.id, |this| {
|
||||
// Register the constructor of this variant.
|
||||
if let Some(ctor_hir_id) = v.node.data.ctor_hir_id() {
|
||||
this.insert(v.span, ctor_hir_id, Node::Ctor(&v.node.data));
|
||||
if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
|
||||
this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
|
||||
}
|
||||
intravisit::walk_variant(this, v, g, item_id);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -155,11 +155,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
|
||||
let def = self.create_def(v.node.id,
|
||||
DefPathData::TypeNs(v.node.ident.as_interned_str()),
|
||||
let def = self.create_def(v.id,
|
||||
DefPathData::TypeNs(v.ident.as_interned_str()),
|
||||
v.span);
|
||||
self.with_parent(def, |this| {
|
||||
if let Some(ctor_hir_id) = v.node.data.ctor_id() {
|
||||
if let Some(ctor_hir_id) = v.data.ctor_id() {
|
||||
this.create_def(ctor_hir_id, DefPathData::Ctor, v.span);
|
||||
}
|
||||
visit::walk_variant(this, v, g, item_id)
|
||||
|
|
|
|||
|
|
@ -649,12 +649,34 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_const_scope(&self, hir_id: HirId) -> bool {
|
||||
self.walk_parent_nodes(hir_id, |node| match *node {
|
||||
Node::Item(Item { node: ItemKind::Const(_, _), .. }) => true,
|
||||
Node::Item(Item { node: ItemKind::Fn(_, header, _, _), .. }) => header.is_const(),
|
||||
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
|
||||
/// Used exclusively for diagnostics, to avoid suggestion function calls.
|
||||
pub fn is_const_context(&self, hir_id: HirId) -> bool {
|
||||
let parent_id = self.get_parent_item(hir_id);
|
||||
match self.get(parent_id) {
|
||||
Node::Item(&Item {
|
||||
node: ItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(&TraitItem {
|
||||
node: TraitItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(&ImplItem {
|
||||
node: ImplItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::AnonConst(_)
|
||||
| Node::Item(&Item {
|
||||
node: ItemKind::Static(..),
|
||||
..
|
||||
}) => true,
|
||||
Node::Item(&Item {
|
||||
node: ItemKind::Fn(_, header, ..),
|
||||
..
|
||||
}) => header.constness == Constness::Const,
|
||||
_ => false,
|
||||
}, |_| false).map(|id| id != CRATE_HIR_ID).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// If there is some error when walking the parents (e.g., a node does not
|
||||
|
|
@ -885,7 +907,7 @@ impl<'hir> Map<'hir> {
|
|||
_ => bug!("struct ID bound to non-struct {}", self.node_to_string(id))
|
||||
}
|
||||
}
|
||||
Some(Node::Variant(variant)) => &variant.node.data,
|
||||
Some(Node::Variant(variant)) => &variant.data,
|
||||
Some(Node::Ctor(data)) => data,
|
||||
_ => bug!("expected struct or variant, found {}", self.node_to_string(id))
|
||||
}
|
||||
|
|
@ -918,7 +940,7 @@ impl<'hir> Map<'hir> {
|
|||
Node::ForeignItem(fi) => fi.ident.name,
|
||||
Node::ImplItem(ii) => ii.ident.name,
|
||||
Node::TraitItem(ti) => ti.ident.name,
|
||||
Node::Variant(v) => v.node.ident.name,
|
||||
Node::Variant(v) => v.ident.name,
|
||||
Node::Field(f) => f.ident.name,
|
||||
Node::Lifetime(lt) => lt.name.ident().name,
|
||||
Node::GenericParam(param) => param.name.ident().name,
|
||||
|
|
@ -939,7 +961,7 @@ impl<'hir> Map<'hir> {
|
|||
Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
|
||||
Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]),
|
||||
Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]),
|
||||
Some(Node::Variant(ref v)) => Some(&v.node.attrs[..]),
|
||||
Some(Node::Variant(ref v)) => Some(&v.attrs[..]),
|
||||
Some(Node::Field(ref f)) => Some(&f.attrs[..]),
|
||||
Some(Node::Expr(ref e)) => Some(&*e.attrs),
|
||||
Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
|
||||
|
|
@ -1133,7 +1155,7 @@ impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() }
|
|||
|
||||
impl Named for Item { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for VariantKind { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for Variant { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for StructField { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
|
||||
|
|
@ -1310,7 +1332,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String {
|
|||
}
|
||||
Some(Node::Variant(ref variant)) => {
|
||||
format!("variant {} in {}{}",
|
||||
variant.node.ident,
|
||||
variant.ident,
|
||||
path_str(), id_str)
|
||||
}
|
||||
Some(Node::Field(ref field)) => {
|
||||
|
|
|
|||
|
|
@ -1541,7 +1541,7 @@ pub enum ExprKind {
|
|||
Match(P<Expr>, HirVec<Arm>, MatchSource),
|
||||
/// A closure (e.g., `move |a, b, c| {a + b + c}`).
|
||||
///
|
||||
/// The final span is the span of the argument block `|...|`.
|
||||
/// The `Span` is the argument block `|...|`.
|
||||
///
|
||||
/// This may also be a generator literal or an `async block` as indicated by the
|
||||
/// `Option<GeneratorMovability>`.
|
||||
|
|
@ -2193,7 +2193,7 @@ pub struct EnumDef {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct VariantKind {
|
||||
pub struct Variant {
|
||||
/// Name of the variant.
|
||||
#[stable_hasher(project(name))]
|
||||
pub ident: Ident,
|
||||
|
|
@ -2205,10 +2205,10 @@ pub struct VariantKind {
|
|||
pub data: VariantData,
|
||||
/// Explicit discriminant (e.g., `Foo = 1`).
|
||||
pub disr_expr: Option<AnonConst>,
|
||||
/// Span
|
||||
pub span: Span
|
||||
}
|
||||
|
||||
pub type Variant = Spanned<VariantKind>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum UseKind {
|
||||
/// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
|
||||
|
|
|
|||
|
|
@ -737,7 +737,7 @@ impl<'a> State<'a> {
|
|||
for v in variants {
|
||||
self.space_if_not_bol();
|
||||
self.maybe_print_comment(v.span.lo());
|
||||
self.print_outer_attributes(&v.node.attrs);
|
||||
self.print_outer_attributes(&v.attrs);
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.print_variant(v);
|
||||
self.s.word(",");
|
||||
|
|
@ -829,8 +829,8 @@ impl<'a> State<'a> {
|
|||
pub fn print_variant(&mut self, v: &hir::Variant) {
|
||||
self.head("");
|
||||
let generics = hir::Generics::empty();
|
||||
self.print_struct(&v.node.data, &generics, v.node.ident.name, v.span, false);
|
||||
if let Some(ref d) = v.node.disr_expr {
|
||||
self.print_struct(&v.data, &generics, v.ident.name, v.span, false);
|
||||
if let Some(ref d) = v.disr_expr {
|
||||
self.s.space();
|
||||
self.word_space("=");
|
||||
self.print_anon_const(d);
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
|
|||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for_spanned!(hir::VariantKind);
|
||||
impl_stable_hash_for_spanned!(hir::Variant);
|
||||
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::hir::def::Namespace;
|
||||
use crate::hir::{self, Local, Pat, Body, HirId};
|
||||
use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat};
|
||||
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::type_variable::TypeVariableOriginKind;
|
||||
|
|
@ -7,7 +7,7 @@ use crate::ty::{self, Ty, Infer, TyVar};
|
|||
use crate::ty::print::Print;
|
||||
use syntax::source_map::DesugaringKind;
|
||||
use syntax_pos::Span;
|
||||
use errors::DiagnosticBuilder;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
|
||||
struct FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
|
|
@ -16,9 +16,26 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
|
|||
found_local_pattern: Option<&'tcx Pat>,
|
||||
found_arg_pattern: Option<&'tcx Pat>,
|
||||
found_ty: Option<Ty<'tcx>>,
|
||||
found_closure: Option<&'tcx ExprKind>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
target_ty: Ty<'tcx>,
|
||||
hir_map: &'a hir::map::Map<'tcx>,
|
||||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
target_ty,
|
||||
hir_map,
|
||||
found_local_pattern: None,
|
||||
found_arg_pattern: None,
|
||||
found_ty: None,
|
||||
found_closure: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
|
||||
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
|
||||
tables.borrow().node_type_opt(hir_id)
|
||||
|
|
@ -72,6 +89,60 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
|
|||
}
|
||||
intravisit::walk_body(self, body);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
|
||||
&expr.node,
|
||||
self.node_matches_type(expr.hir_id),
|
||||
) {
|
||||
self.found_closure = Some(&expr.node);
|
||||
}
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Suggest giving an appropriate return type to a closure expression.
|
||||
fn closure_return_type_suggestion(
|
||||
span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
output: &FunctionRetTy,
|
||||
body: &Body,
|
||||
name: &str,
|
||||
ret: &str,
|
||||
) {
|
||||
let (arrow, post) = match output {
|
||||
FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
|
||||
_ => ("", ""),
|
||||
};
|
||||
let suggestion = match body.value.node {
|
||||
ExprKind::Block(..) => {
|
||||
vec![(output.span(), format!("{}{}{}", arrow, ret, post))]
|
||||
}
|
||||
_ => {
|
||||
vec![
|
||||
(output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
|
||||
(body.value.span.shrink_to_hi(), " }".to_string()),
|
||||
]
|
||||
}
|
||||
};
|
||||
err.multipart_suggestion(
|
||||
"give this closure an explicit return type without `_` placeholders",
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
err.span_label(span, InferCtxt::missing_type_msg(&name));
|
||||
}
|
||||
|
||||
/// Given a closure signature, return a `String` containing a list of all its argument types.
|
||||
fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
|
||||
fn_sig.inputs()
|
||||
.skip_binder()
|
||||
.iter()
|
||||
.next()
|
||||
.map(|args| args.tuple_fields()
|
||||
.map(|arg| arg.to_string())
|
||||
.collect::<Vec<_>>().join(", "))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
|
|
@ -106,16 +177,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let ty = self.resolve_vars_if_possible(&ty);
|
||||
let name = self.extract_type_name(&ty, None);
|
||||
|
||||
let mut err_span = span;
|
||||
|
||||
let mut local_visitor = FindLocalByTypeVisitor {
|
||||
infcx: &self,
|
||||
target_ty: ty,
|
||||
hir_map: &self.tcx.hir(),
|
||||
found_local_pattern: None,
|
||||
found_arg_pattern: None,
|
||||
found_ty: None,
|
||||
};
|
||||
let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
|
||||
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
||||
let mut s = String::new();
|
||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||
|
|
@ -136,6 +198,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let expr = self.tcx.hir().expect_expr(body_id.hir_id);
|
||||
local_visitor.visit_expr(expr);
|
||||
}
|
||||
let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||
pattern.span
|
||||
} else {
|
||||
span
|
||||
};
|
||||
|
||||
let is_named_and_not_impl_trait = |ty: Ty<'_>| {
|
||||
&ty.to_string() != "_" &&
|
||||
// FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
|
||||
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
|
||||
};
|
||||
|
||||
let ty_msg = match local_visitor.found_ty {
|
||||
Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
|
||||
let fn_sig = substs.closure_sig(*def_id, self.tcx);
|
||||
let args = closure_args(&fn_sig);
|
||||
let ret = fn_sig.output().skip_binder().to_string();
|
||||
format!(" for the closure `fn({}) -> {}`", args, ret)
|
||||
}
|
||||
Some(ty) if is_named_and_not_impl_trait(ty) => {
|
||||
let ty = ty_to_string(ty);
|
||||
format!(" for `{}`", ty)
|
||||
}
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
// When `name` corresponds to a type argument, show the path of the full type we're
|
||||
// trying to infer. In the following example, `ty_msg` contains
|
||||
|
|
@ -150,27 +237,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
|
||||
// | the type parameter `E` is specified
|
||||
// ```
|
||||
let (ty_msg, suffix) = match &local_visitor.found_ty {
|
||||
Some(ty) if &ty.to_string() != "_" && name == "_" => {
|
||||
let ty = ty_to_string(ty);
|
||||
(format!(" for `{}`", ty),
|
||||
format!("the explicit type `{}`, with the type parameters specified", ty))
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed{}",
|
||||
ty_msg,
|
||||
);
|
||||
|
||||
let suffix = match local_visitor.found_ty {
|
||||
Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
|
||||
let fn_sig = substs.closure_sig(*def_id, self.tcx);
|
||||
let ret = fn_sig.output().skip_binder().to_string();
|
||||
|
||||
if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
|
||||
if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) {
|
||||
closure_return_type_suggestion(
|
||||
span,
|
||||
&mut err,
|
||||
&decl.output,
|
||||
&body,
|
||||
&name,
|
||||
&ret,
|
||||
);
|
||||
// We don't want to give the other suggestions when the problem is the
|
||||
// closure return type.
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// This shouldn't be reachable, but just in case we leave a reasonable fallback.
|
||||
let args = closure_args(&fn_sig);
|
||||
// This suggestion is incomplete, as the user will get further type inference
|
||||
// errors due to the `_` placeholders and the introduction of `Box`, but it does
|
||||
// nudge them in the right direction.
|
||||
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
|
||||
}
|
||||
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
|
||||
Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
|
||||
let ty = ty_to_string(ty);
|
||||
(format!(" for `{}`", ty),
|
||||
format!(
|
||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||
format!("the explicit type `{}`, with the type parameters specified", ty)
|
||||
}
|
||||
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
|
||||
let ty = ty_to_string(ty);
|
||||
format!(
|
||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||
ty,
|
||||
name,
|
||||
))
|
||||
)
|
||||
}
|
||||
_ => (String::new(), "a type".to_owned()),
|
||||
_ => "a type".to_string(),
|
||||
};
|
||||
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
|
||||
|
||||
if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||
err_span = pattern.span;
|
||||
// We don't want to show the default label for closures.
|
||||
//
|
||||
// So, before clearing, the output would look something like this:
|
||||
|
|
@ -187,39 +305,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// ^ consider giving this closure parameter the type `[_; 0]`
|
||||
// with the type parameter `_` specified
|
||||
// ```
|
||||
labels.clear();
|
||||
labels.push((
|
||||
err.span_label(
|
||||
pattern.span,
|
||||
format!("consider giving this closure parameter {}", suffix),
|
||||
));
|
||||
);
|
||||
} else if let Some(pattern) = local_visitor.found_local_pattern {
|
||||
if let Some(simple_ident) = pattern.simple_ident() {
|
||||
let msg = if let Some(simple_ident) = pattern.simple_ident() {
|
||||
match pattern.span.desugaring_kind() {
|
||||
None => labels.push((
|
||||
pattern.span,
|
||||
format!("consider giving `{}` {}", simple_ident, suffix),
|
||||
)),
|
||||
Some(DesugaringKind::ForLoop) => labels.push((
|
||||
pattern.span,
|
||||
"the element type for this iterator is not specified".to_owned(),
|
||||
)),
|
||||
_ => {}
|
||||
None => {
|
||||
format!("consider giving `{}` {}", simple_ident, suffix)
|
||||
}
|
||||
Some(DesugaringKind::ForLoop) => {
|
||||
"the element type for this iterator is not specified".to_string()
|
||||
}
|
||||
_ => format!("this needs {}", suffix),
|
||||
}
|
||||
} else {
|
||||
labels.push((pattern.span, format!("consider giving this pattern {}", suffix)));
|
||||
}
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed{}",
|
||||
ty_msg,
|
||||
);
|
||||
|
||||
for (target_span, label_message) in labels {
|
||||
err.span_label(target_span, label_message);
|
||||
format!("consider giving this pattern {}", suffix)
|
||||
};
|
||||
err.span_label(pattern.span, msg);
|
||||
}
|
||||
if !err.span.span_labels().iter().any(|span_label| {
|
||||
span_label.label.is_some() && span_label.span == span
|
||||
}) && local_visitor.found_arg_pattern.is_none()
|
||||
{ // Avoid multiple labels pointing at `span`.
|
||||
err.span_label(span, InferCtxt::missing_type_msg(&name));
|
||||
}
|
||||
|
||||
err
|
||||
|
|
|
|||
|
|
@ -1060,7 +1060,7 @@ for LateContextAndPass<'a, 'tcx, T> {
|
|||
v: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
item_id: hir::HirId) {
|
||||
self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| {
|
||||
self.with_lint_attrs(v.id, &v.attrs, |cx| {
|
||||
lint_callback!(cx, check_variant, v, g);
|
||||
hir_visit::walk_variant(cx, v, g, item_id);
|
||||
lint_callback!(cx, check_variant_post, v, g);
|
||||
|
|
@ -1236,7 +1236,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
|
||||
self.with_lint_attrs(item_id, &v.node.attrs, |cx| {
|
||||
self.with_lint_attrs(item_id, &v.attrs, |cx| {
|
||||
run_early_pass!(cx, check_variant, v, g);
|
||||
ast_visit::walk_variant(cx, v, g, item_id);
|
||||
run_early_pass!(cx, check_variant_post, v, g);
|
||||
|
|
|
|||
|
|
@ -846,7 +846,7 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
|
|||
v: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
item_id: hir::HirId) {
|
||||
self.with_lint_attrs(v.node.id, &v.node.attrs, |builder| {
|
||||
self.with_lint_attrs(v.id, &v.attrs, |builder| {
|
||||
intravisit::walk_variant(builder, v, g, item_id);
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,12 +366,12 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
|
|||
match item.node {
|
||||
hir::ItemKind::Enum(ref enum_def, _) => {
|
||||
if allow_dead_code {
|
||||
self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
|
||||
self.worklist.extend(enum_def.variants.iter().map(|variant| variant.id));
|
||||
}
|
||||
|
||||
for variant in &enum_def.variants {
|
||||
if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
|
||||
self.struct_constructors.insert(ctor_hir_id, variant.node.id);
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
self.struct_constructors.insert(ctor_hir_id, variant.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -497,7 +497,7 @@ impl DeadVisitor<'tcx> {
|
|||
&& !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id, &field.attrs)
|
||||
}
|
||||
|
||||
fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool {
|
||||
fn should_warn_about_variant(&mut self, variant: &hir::Variant) -> bool {
|
||||
!self.symbol_is_live(variant.id)
|
||||
&& !has_allow_dead_code_or_lang_attr(self.tcx,
|
||||
variant.id,
|
||||
|
|
@ -596,8 +596,8 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
|
|||
variant: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
id: hir::HirId) {
|
||||
if self.should_warn_about_variant(&variant.node) {
|
||||
self.warn_dead_code(variant.node.id, variant.span, variant.node.ident.name,
|
||||
if self.should_warn_about_variant(&variant) {
|
||||
self.warn_dead_code(variant.id, variant.span, variant.ident.name,
|
||||
"variant", "constructed");
|
||||
} else {
|
||||
intravisit::walk_variant(self, variant, g, id);
|
||||
|
|
|
|||
|
|
@ -290,10 +290,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
|
||||
self.annotate(var.node.id, &var.node.attrs, var.span, AnnotationKind::Required,
|
||||
self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required,
|
||||
|v| {
|
||||
if let Some(ctor_hir_id) = var.node.data.ctor_hir_id() {
|
||||
v.annotate(ctor_hir_id, &var.node.attrs, var.span, AnnotationKind::Required,
|
||||
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
|
||||
v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required,
|
||||
|_| {});
|
||||
}
|
||||
|
||||
|
|
@ -372,7 +372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
|
||||
self.check_missing_stability(var.node.id, var.span, "variant");
|
||||
self.check_missing_stability(var.id, var.span, "variant");
|
||||
intravisit::walk_variant(self, var, g, item_id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -189,8 +189,11 @@ impl<'tcx, Tag> Pointer<Tag> {
|
|||
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
|
||||
}
|
||||
|
||||
/// Test if the pointer is "inbounds" of an allocation of the given size.
|
||||
/// A pointer is "inbounds" even if its offset is equal to the size; this is
|
||||
/// a "one-past-the-end" pointer.
|
||||
#[inline(always)]
|
||||
pub fn check_in_alloc(
|
||||
pub fn check_inbounds_alloc(
|
||||
self,
|
||||
allocation_size: Size,
|
||||
msg: CheckInAllocMsg,
|
||||
|
|
|
|||
|
|
@ -2068,6 +2068,9 @@ impl<'tcx> TyS<'tcx> {
|
|||
Error => { // ignore errors (#54954)
|
||||
ty::Binder::dummy(FnSig::fake())
|
||||
}
|
||||
Closure(..) => bug!(
|
||||
"to get the signature of a closure, use `closure_sig()` not `fn_sig()`",
|
||||
),
|
||||
_ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,8 +484,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
|||
|
||||
fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) {
|
||||
self.check_missing_docs_attrs(cx,
|
||||
Some(v.node.id),
|
||||
&v.node.attrs,
|
||||
Some(v.id),
|
||||
&v.attrs,
|
||||
v.span,
|
||||
"a variant");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ extern crate rustc;
|
|||
|
||||
mod error_codes;
|
||||
mod nonstandard_style;
|
||||
mod redundant_semicolon;
|
||||
pub mod builtin;
|
||||
mod types;
|
||||
mod unused;
|
||||
|
|
@ -55,6 +56,7 @@ use session::Session;
|
|||
use lint::LintId;
|
||||
use lint::FutureIncompatibleInfo;
|
||||
|
||||
use redundant_semicolon::*;
|
||||
use nonstandard_style::*;
|
||||
use builtin::*;
|
||||
use types::*;
|
||||
|
|
@ -98,6 +100,7 @@ macro_rules! early_lint_passes {
|
|||
WhileTrue: WhileTrue,
|
||||
NonAsciiIdents: NonAsciiIdents,
|
||||
IncompleteFeatures: IncompleteFeatures,
|
||||
RedundantSemicolon: RedundantSemicolon,
|
||||
]);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
|
|||
}
|
||||
|
||||
fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant, _: &ast::Generics) {
|
||||
self.check_case(cx, "variant", &v.node.ident);
|
||||
self.check_case(cx, "variant", &v.ident);
|
||||
}
|
||||
|
||||
fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
|
||||
|
|
|
|||
52
src/librustc_lint/redundant_semicolon.rs
Normal file
52
src/librustc_lint/redundant_semicolon.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use crate::lint::{EarlyLintPass, LintPass, EarlyContext, LintArray, LintContext};
|
||||
use syntax::ast::{Stmt, StmtKind, ExprKind};
|
||||
use syntax::errors::Applicability;
|
||||
|
||||
declare_lint! {
|
||||
pub REDUNDANT_SEMICOLON,
|
||||
Warn,
|
||||
"detects unnecessary trailing semicolons"
|
||||
}
|
||||
|
||||
declare_lint_pass!(RedundantSemicolon => [REDUNDANT_SEMICOLON]);
|
||||
|
||||
impl EarlyLintPass for RedundantSemicolon {
|
||||
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
|
||||
if let StmtKind::Semi(expr) = &stmt.node {
|
||||
if let ExprKind::Tup(ref v) = &expr.node {
|
||||
if v.is_empty() {
|
||||
// Strings of excess semicolons are encoded as empty tuple expressions
|
||||
// during the parsing stage, so we check for empty tuple expressions
|
||||
// which span only semicolons
|
||||
if let Ok(source_str) = cx.sess().source_map().span_to_snippet(stmt.span) {
|
||||
if source_str.chars().all(|c| c == ';') {
|
||||
let multiple = (stmt.span.hi() - stmt.span.lo()).0 > 1;
|
||||
let msg = if multiple {
|
||||
"unnecessary trailing semicolons"
|
||||
} else {
|
||||
"unnecessary trailing semicolon"
|
||||
};
|
||||
let mut err = cx.struct_span_lint(
|
||||
REDUNDANT_SEMICOLON,
|
||||
stmt.span,
|
||||
&msg
|
||||
);
|
||||
let suggest_msg = if multiple {
|
||||
"remove these semicolons"
|
||||
} else {
|
||||
"remove this semicolon"
|
||||
};
|
||||
err.span_suggestion(
|
||||
stmt.span,
|
||||
&suggest_msg,
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -976,7 +976,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
|||
let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
|
||||
|
||||
debug!("- variant `{}` is {} bytes large",
|
||||
variant.node.ident,
|
||||
variant.ident,
|
||||
bytes);
|
||||
bytes
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1676,7 +1676,7 @@ impl Visitor<'tcx> for EncodeContext<'tcx> {
|
|||
id: hir::HirId) {
|
||||
intravisit::walk_variant(self, v, g, id);
|
||||
|
||||
if let Some(ref discr) = v.node.disr_expr {
|
||||
if let Some(ref discr) = v.disr_expr {
|
||||
let def_id = self.tcx.hir().local_def_id(discr.hir_id);
|
||||
self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
// It is sufficient to check this for the end pointer. The addition
|
||||
// checks for overflow.
|
||||
let end_ptr = ptr.offset(size, self)?;
|
||||
end_ptr.check_in_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?;
|
||||
end_ptr.check_inbounds_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?;
|
||||
// Test align. Check this last; if both bounds and alignment are violated
|
||||
// we want the error to be about the bounds.
|
||||
if let Some(align) = align {
|
||||
|
|
@ -400,7 +400,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
) -> bool {
|
||||
let (size, _align) = self.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)
|
||||
.expect("alloc info with MaybeDead cannot fail");
|
||||
ptr.check_in_alloc(size, CheckInAllocMsg::NullPointerTest).is_err()
|
||||
ptr.check_inbounds_alloc(size, CheckInAllocMsg::NullPointerTest).is_err()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -246,7 +246,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let ptr = match self.check_mplace_access(mplace, None)? {
|
||||
let ptr = match self.check_mplace_access(mplace, None)
|
||||
.expect("places should be checked on creation")
|
||||
{
|
||||
Some(ptr) => ptr,
|
||||
None => return Ok(Some(ImmTy { // zero-sized type
|
||||
imm: Scalar::zst().into(),
|
||||
|
|
|
|||
|
|
@ -277,6 +277,10 @@ where
|
|||
{
|
||||
/// Take a value, which represents a (thin or fat) reference, and make it a place.
|
||||
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
|
||||
///
|
||||
/// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
|
||||
/// want to ever use the place for memory access!
|
||||
/// Generally prefer `deref_operand`.
|
||||
pub fn ref_to_mplace(
|
||||
&self,
|
||||
val: ImmTy<'tcx, M::PointerTag>,
|
||||
|
|
@ -304,7 +308,8 @@ where
|
|||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
let val = self.read_immediate(src)?;
|
||||
trace!("deref to {} on {:?}", val.layout.ty, *val);
|
||||
self.ref_to_mplace(val)
|
||||
let place = self.ref_to_mplace(val)?;
|
||||
self.mplace_access_checked(place)
|
||||
}
|
||||
|
||||
/// Check if the given place is good for memory access with the given
|
||||
|
|
@ -327,6 +332,23 @@ where
|
|||
self.memory.check_ptr_access(place.ptr, size, place.align)
|
||||
}
|
||||
|
||||
/// Return the "access-checked" version of this `MPlace`, where for non-ZST
|
||||
/// this is definitely a `Pointer`.
|
||||
pub fn mplace_access_checked(
|
||||
&self,
|
||||
mut place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
let (size, align) = self.size_and_align_of_mplace(place)?
|
||||
.unwrap_or((place.layout.size, place.layout.align.abi));
|
||||
assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
|
||||
place.mplace.align = align; // maximally strict checking
|
||||
// When dereferencing a pointer, it must be non-NULL, aligned, and live.
|
||||
if let Some(ptr) = self.check_mplace_access(place, Some(size))? {
|
||||
place.mplace.ptr = ptr.into();
|
||||
}
|
||||
Ok(place)
|
||||
}
|
||||
|
||||
/// Force `place.ptr` to a `Pointer`.
|
||||
/// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
|
||||
pub fn force_mplace_ptr(
|
||||
|
|
@ -750,7 +772,9 @@ where
|
|||
// to handle padding properly, which is only correct if we never look at this data with the
|
||||
// wrong type.
|
||||
|
||||
let ptr = match self.check_mplace_access(dest, None)? {
|
||||
let ptr = match self.check_mplace_access(dest, None)
|
||||
.expect("places should be checked on creation")
|
||||
{
|
||||
Some(ptr) => ptr,
|
||||
None => return Ok(()), // zero-sized access
|
||||
};
|
||||
|
|
@ -853,8 +877,10 @@ where
|
|||
});
|
||||
assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
|
||||
|
||||
let src = self.check_mplace_access(src, Some(size))?;
|
||||
let dest = self.check_mplace_access(dest, Some(size))?;
|
||||
let src = self.check_mplace_access(src, Some(size))
|
||||
.expect("places should be checked on creation");
|
||||
let dest = self.check_mplace_access(dest, Some(size))
|
||||
.expect("places should be checked on creation");
|
||||
let (src_ptr, dest_ptr) = match (src, dest) {
|
||||
(Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr),
|
||||
(None, None) => return Ok(()), // zero-sized copy
|
||||
|
|
|
|||
|
|
@ -240,8 +240,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
Ref(_, _, ref place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let val = self.force_allocation(src)?;
|
||||
self.write_immediate(val.to_ref(), dest)?;
|
||||
let place = self.force_allocation(src)?;
|
||||
if place.layout.size.bytes() > 0 {
|
||||
// definitely not a ZST
|
||||
assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
|
||||
}
|
||||
self.write_immediate(place.to_ref(), dest)?;
|
||||
}
|
||||
|
||||
NullaryOp(mir::NullOp::Box, _) => {
|
||||
|
|
|
|||
|
|
@ -602,7 +602,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
ItemKind::Enum(ref def, _) => {
|
||||
for variant in &def.variants {
|
||||
for field in variant.node.data.fields() {
|
||||
for field in variant.data.fields() {
|
||||
self.invalid_visibility(&field.vis, None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -687,11 +687,11 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||
match item.node {
|
||||
hir::ItemKind::Enum(ref def, _) => {
|
||||
for variant in &def.variants {
|
||||
let variant_level = self.update(variant.node.id, item_level);
|
||||
if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
|
||||
let variant_level = self.update(variant.id, item_level);
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
self.update(ctor_hir_id, item_level);
|
||||
}
|
||||
for field in variant.node.data.fields() {
|
||||
for field in variant.data.fields() {
|
||||
self.update(field.hir_id, variant_level);
|
||||
}
|
||||
}
|
||||
|
|
@ -810,9 +810,9 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||
self.reach(item.hir_id, item_level).generics().predicates();
|
||||
}
|
||||
for variant in &def.variants {
|
||||
let variant_level = self.get(variant.node.id);
|
||||
let variant_level = self.get(variant.id);
|
||||
if variant_level.is_some() {
|
||||
for field in variant.node.data.fields() {
|
||||
for field in variant.data.fields() {
|
||||
self.reach(field.hir_id, variant_level).ty();
|
||||
}
|
||||
// Corner case: if the variant is reachable, but its
|
||||
|
|
@ -1647,7 +1647,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||
v: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
item_id: hir::HirId) {
|
||||
if self.access_levels.is_reachable(v.node.id) {
|
||||
if self.access_levels.is_reachable(v.id) {
|
||||
self.in_variant = true;
|
||||
intravisit::walk_variant(self, v, g, item_id);
|
||||
self.in_variant = false;
|
||||
|
|
@ -1898,7 +1898,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
|||
self.check(item.hir_id, item_visibility).generics().predicates();
|
||||
|
||||
for variant in &def.variants {
|
||||
for field in variant.node.data.fields() {
|
||||
for field in variant.data.fields() {
|
||||
self.check(field.hir_id, item_visibility).ty();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -799,17 +799,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
parent: Module<'a>,
|
||||
vis: ty::Visibility,
|
||||
expn_id: ExpnId) {
|
||||
let ident = variant.node.ident;
|
||||
let ident = variant.ident;
|
||||
|
||||
// Define a name in the type namespace.
|
||||
let def_id = self.r.definitions.local_def_id(variant.node.id);
|
||||
let def_id = self.r.definitions.local_def_id(variant.id);
|
||||
let res = Res::Def(DefKind::Variant, def_id);
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
|
||||
|
||||
// If the variant is marked as non_exhaustive then lower the visibility to within the
|
||||
// crate.
|
||||
let mut ctor_vis = vis;
|
||||
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive);
|
||||
let has_non_exhaustive = attr::contains_name(&variant.attrs, sym::non_exhaustive);
|
||||
if has_non_exhaustive && vis == ty::Visibility::Public {
|
||||
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
|
@ -819,9 +819,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
// value namespace, they are reserved for possible future use.
|
||||
// It's ok to use the variant's id as a ctor id since an
|
||||
// error will be reported on any use of such resolution anyway.
|
||||
let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id);
|
||||
let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
|
||||
let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id);
|
||||
let ctor_kind = CtorKind::from_ast(&variant.node.data);
|
||||
let ctor_kind = CtorKind::from_ast(&variant.data);
|
||||
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
|
||||
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,11 +557,11 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
let access = access_from!(self.save_ctxt, item, hir_id);
|
||||
|
||||
for variant in &enum_definition.variants {
|
||||
let name = variant.node.ident.name.to_string();
|
||||
let name = variant.ident.name.to_string();
|
||||
let qualname = format!("{}::{}", enum_data.qualname, name);
|
||||
let name_span = variant.node.ident.span;
|
||||
let name_span = variant.ident.span;
|
||||
|
||||
match variant.node.data {
|
||||
match variant.data {
|
||||
ast::VariantData::Struct(ref fields, ..) => {
|
||||
let fields_str = fields
|
||||
.iter()
|
||||
|
|
@ -574,7 +574,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
|
||||
if !self.span.filter_generated(name_span) {
|
||||
let span = self.span_from_span(name_span);
|
||||
let id = id_from_node_id(variant.node.id, &self.save_ctxt);
|
||||
let id = id_from_node_id(variant.id, &self.save_ctxt);
|
||||
let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
|
||||
|
||||
self.dumper.dump_def(
|
||||
|
|
@ -589,10 +589,10 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
parent,
|
||||
children: vec![],
|
||||
decl_id: None,
|
||||
docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
|
||||
docs: self.save_ctxt.docs_for_attrs(&variant.attrs),
|
||||
sig: sig::variant_signature(variant, &self.save_ctxt),
|
||||
attributes: lower_attributes(
|
||||
variant.node.attrs.clone(),
|
||||
variant.attrs.clone(),
|
||||
&self.save_ctxt,
|
||||
),
|
||||
},
|
||||
|
|
@ -612,7 +612,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
}
|
||||
if !self.span.filter_generated(name_span) {
|
||||
let span = self.span_from_span(name_span);
|
||||
let id = id_from_node_id(variant.node.id, &self.save_ctxt);
|
||||
let id = id_from_node_id(variant.id, &self.save_ctxt);
|
||||
let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
|
||||
|
||||
self.dumper.dump_def(
|
||||
|
|
@ -627,10 +627,10 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
parent,
|
||||
children: vec![],
|
||||
decl_id: None,
|
||||
docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
|
||||
docs: self.save_ctxt.docs_for_attrs(&variant.attrs),
|
||||
sig: sig::variant_signature(variant, &self.save_ctxt),
|
||||
attributes: lower_attributes(
|
||||
variant.node.attrs.clone(),
|
||||
variant.attrs.clone(),
|
||||
&self.save_ctxt,
|
||||
),
|
||||
},
|
||||
|
|
@ -640,8 +640,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
|
||||
for field in variant.node.data.fields() {
|
||||
self.process_struct_field_def(field, variant.node.id);
|
||||
for field in variant.data.fields() {
|
||||
self.process_struct_field_def(field, variant.id);
|
||||
self.visit_ty(&field.ty);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
|
|||
filter!(self.span_utils, item.ident.span);
|
||||
let variants_str = def.variants
|
||||
.iter()
|
||||
.map(|v| v.node.ident.to_string())
|
||||
.map(|v| v.ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let value = format!("{}::{{{}}}", name, variants_str);
|
||||
|
|
@ -291,7 +291,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
|
|||
parent: None,
|
||||
children: def.variants
|
||||
.iter()
|
||||
.map(|v| id_from_node_id(v.node.id, self))
|
||||
.map(|v| id_from_node_id(v.id, self))
|
||||
.collect(),
|
||||
decl_id: None,
|
||||
docs: self.docs_for_attrs(&item.attrs),
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext<'_, '_>) -> O
|
|||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
variant.node.make(0, None, scx).ok()
|
||||
variant.make(0, None, scx).ok()
|
||||
}
|
||||
|
||||
pub fn method_signature(
|
||||
|
|
@ -699,7 +699,7 @@ impl Sig for ast::StructField {
|
|||
}
|
||||
|
||||
|
||||
impl Sig for ast::Variant_ {
|
||||
impl Sig for ast::Variant {
|
||||
fn make(&self, offset: usize, parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
|
||||
let mut text = self.ident.to_string();
|
||||
match self.data {
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_missing_await(&mut err, expr, expected, expr_ty);
|
||||
|
||||
(expected, Some(err))
|
||||
|
|
@ -548,7 +549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
checked_ty: Ty<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
if self.tcx.hir().is_const_scope(expr.hir_id) {
|
||||
if self.tcx.hir().is_const_context(expr.hir_id) {
|
||||
// Shouldn't suggest `.into()` on `const`s.
|
||||
// FIXME(estebank): modify once we decide to suggest `as` casts
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2048,19 +2048,19 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i
|
|||
}
|
||||
|
||||
for v in vs {
|
||||
if let Some(ref e) = v.node.disr_expr {
|
||||
if let Some(ref e) = v.disr_expr {
|
||||
tcx.typeck_tables_of(tcx.hir().local_def_id(e.hir_id));
|
||||
}
|
||||
}
|
||||
|
||||
if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
|
||||
let is_unit =
|
||||
|var: &hir::Variant| match var.node.data {
|
||||
|var: &hir::Variant| match var.data {
|
||||
hir::VariantData::Unit(..) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
let has_disr = |var: &hir::Variant| var.node.disr_expr.is_some();
|
||||
let has_disr = |var: &hir::Variant| var.disr_expr.is_some();
|
||||
let has_non_units = vs.iter().any(|var| !is_unit(var));
|
||||
let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
|
||||
let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
|
||||
|
|
@ -2079,11 +2079,11 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i
|
|||
let variant_did = def.variants[VariantIdx::new(i)].def_id;
|
||||
let variant_i_hir_id = tcx.hir().as_local_hir_id(variant_did).unwrap();
|
||||
let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
|
||||
let i_span = match variant_i.node.disr_expr {
|
||||
let i_span = match variant_i.disr_expr {
|
||||
Some(ref expr) => tcx.hir().span(expr.hir_id),
|
||||
None => tcx.hir().span(variant_i_hir_id)
|
||||
};
|
||||
let span = match v.node.disr_expr {
|
||||
let span = match v.disr_expr {
|
||||
Some(ref expr) => tcx.hir().span(expr.hir_id),
|
||||
None => v.span
|
||||
};
|
||||
|
|
@ -3900,6 +3900,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err, &fn_decl, expected, found, can_suggest);
|
||||
}
|
||||
self.suggest_ref_or_into(err, expression, expected, found);
|
||||
self.suggest_boxing_when_appropriate(err, expression, expected, found);
|
||||
pointing_at_return_type
|
||||
}
|
||||
|
||||
|
|
@ -4060,6 +4061,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
|
||||
/// in the heap by calling `Box::new()`.
|
||||
fn suggest_boxing_when_appropriate(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
expr: &hir::Expr,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) {
|
||||
if self.tcx.hir().is_const_context(expr.hir_id) {
|
||||
// Do not suggest `Box::new` in const context.
|
||||
return;
|
||||
}
|
||||
if !expected.is_box() || found.is_box() {
|
||||
return;
|
||||
}
|
||||
let boxed_found = self.tcx.mk_box(found);
|
||||
if let (true, Ok(snippet)) = (
|
||||
self.can_coerce(boxed_found, expected),
|
||||
self.sess().source_map().span_to_snippet(expr.span),
|
||||
) {
|
||||
err.span_suggestion(
|
||||
expr.span,
|
||||
"store this in the heap by calling `Box::new`",
|
||||
format!("Box::new({})", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.note("for more on the distinction between the stack and the \
|
||||
heap, read https://doc.rust-lang.org/book/ch15-01-box.html, \
|
||||
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
|
||||
https://doc.rust-lang.org/std/boxed/index.html");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A common error is to forget to add a semicolon at the end of a block, e.g.,
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -1119,7 +1119,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec<AdtVariant<'tcx>> {
|
||||
enum_def.variants.iter()
|
||||
.map(|variant| self.non_enum_variant(&variant.node.data))
|
||||
.map(|variant| self.non_enum_variant(&variant.data))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ use rustc_target::spec::abi;
|
|||
use syntax::ast;
|
||||
use syntax::ast::{Ident, MetaItemKind};
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used};
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::feature_gate;
|
||||
use syntax::symbol::{InternedString, kw, Symbol, sym};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
|
@ -520,7 +519,11 @@ fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
|
|||
tcx.predicates_of(def_id);
|
||||
}
|
||||
|
||||
fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants: &[hir::Variant]) {
|
||||
fn convert_enum_variant_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
variants: &[hir::Variant]
|
||||
) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let repr_type = def.repr.discr_type();
|
||||
let initial = repr_type.initial_discriminant(tcx);
|
||||
|
|
@ -530,7 +533,7 @@ fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants:
|
|||
for variant in variants {
|
||||
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
|
||||
prev_discr = Some(
|
||||
if let Some(ref e) = variant.node.disr_expr {
|
||||
if let Some(ref e) = variant.disr_expr {
|
||||
let expr_did = tcx.hir().local_def_id(e.hir_id);
|
||||
def.eval_explicit_discr(tcx, expr_did)
|
||||
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
|
||||
|
|
@ -546,14 +549,14 @@ fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants:
|
|||
format!("overflowed on value after {}", prev_discr.unwrap()),
|
||||
).note(&format!(
|
||||
"explicitly set `{} = {}` if that is desired outcome",
|
||||
variant.node.ident, wrapped_discr
|
||||
variant.ident, wrapped_discr
|
||||
))
|
||||
.emit();
|
||||
None
|
||||
}.unwrap_or(wrapped_discr),
|
||||
);
|
||||
|
||||
for f in variant.node.data.fields() {
|
||||
for f in variant.data.fields() {
|
||||
let def_id = tcx.hir().local_def_id(f.hir_id);
|
||||
tcx.generics_of(def_id);
|
||||
tcx.type_of(def_id);
|
||||
|
|
@ -562,7 +565,7 @@ fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants:
|
|||
|
||||
// Convert the ctor, if any. This also registers the variant as
|
||||
// an item.
|
||||
if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
convert_variant_ctor(tcx, ctor_hir_id);
|
||||
}
|
||||
}
|
||||
|
|
@ -641,11 +644,11 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef {
|
|||
let variants = def.variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let variant_did = Some(tcx.hir().local_def_id(v.node.id));
|
||||
let ctor_did = v.node.data.ctor_hir_id()
|
||||
let variant_did = Some(tcx.hir().local_def_id(v.id));
|
||||
let ctor_did = v.data.ctor_hir_id()
|
||||
.map(|hir_id| tcx.hir().local_def_id(hir_id));
|
||||
|
||||
let discr = if let Some(ref e) = v.node.disr_expr {
|
||||
let discr = if let Some(ref e) = v.disr_expr {
|
||||
distance_from_explicit = 0;
|
||||
ty::VariantDiscr::Explicit(tcx.hir().local_def_id(e.hir_id))
|
||||
} else {
|
||||
|
|
@ -653,8 +656,8 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef {
|
|||
};
|
||||
distance_from_explicit += 1;
|
||||
|
||||
convert_variant(tcx, variant_did, ctor_did, v.node.ident, discr,
|
||||
&v.node.data, AdtKind::Enum, def_id)
|
||||
convert_variant(tcx, variant_did, ctor_did, v.ident, discr,
|
||||
&v.data, AdtKind::Enum, def_id)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -1314,10 +1317,9 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
|
|||
ForeignItemKind::Type => tcx.mk_foreign(def_id),
|
||||
},
|
||||
|
||||
Node::Ctor(&ref def) | Node::Variant(&Spanned {
|
||||
node: hir::VariantKind { data: ref def, .. },
|
||||
..
|
||||
}) => match *def {
|
||||
Node::Ctor(&ref def) | Node::Variant(
|
||||
hir::Variant { data: ref def, .. }
|
||||
) => match *def {
|
||||
VariantData::Unit(..) | VariantData::Struct(..) => {
|
||||
tcx.type_of(tcx.hir().get_parent_did(hir_id))
|
||||
}
|
||||
|
|
@ -1363,12 +1365,8 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
|
|||
tcx.types.usize
|
||||
}
|
||||
|
||||
Node::Variant(&Spanned {
|
||||
node:
|
||||
VariantKind {
|
||||
disr_expr: Some(ref e),
|
||||
..
|
||||
},
|
||||
Node::Variant(Variant {
|
||||
disr_expr: Some(ref e),
|
||||
..
|
||||
}) if e.hir_id == hir_id =>
|
||||
{
|
||||
|
|
@ -1809,10 +1807,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
|||
compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
|
||||
}
|
||||
|
||||
Ctor(data) | Variant(Spanned {
|
||||
node: hir::VariantKind { data, .. },
|
||||
..
|
||||
}) if data.ctor_hir_id().is_some() => {
|
||||
Ctor(data) | Variant(
|
||||
hir::Variant { data, .. }
|
||||
) if data.ctor_hir_id().is_some() => {
|
||||
let ty = tcx.type_of(tcx.hir().get_parent_did(hir_id));
|
||||
let inputs = data.fields()
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
|
|||
self.visit_node_helper(item.hir_id);
|
||||
|
||||
for variant in &enum_def.variants {
|
||||
if let hir::VariantData::Tuple(..) = variant.node.data {
|
||||
self.visit_node_helper(variant.node.data.ctor_hir_id().unwrap());
|
||||
if let hir::VariantData::Tuple(..) = variant.data {
|
||||
self.visit_node_helper(variant.data.ctor_hir_id().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
|
|||
self.add_inferreds_for_item(item.hir_id);
|
||||
|
||||
for variant in &enum_def.variants {
|
||||
if let hir::VariantData::Tuple(..) = variant.node.data {
|
||||
self.add_inferreds_for_item(variant.node.data.ctor_hir_id().unwrap());
|
||||
if let hir::VariantData::Tuple(..) = variant.data {
|
||||
self.add_inferreds_for_item(variant.data.ctor_hir_id().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -951,7 +951,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
|
|||
v: &'hir hir::Variant,
|
||||
g: &'hir hir::Generics,
|
||||
item_id: hir::HirId) {
|
||||
self.visit_testable(v.node.ident.to_string(), &v.node.attrs, |this| {
|
||||
self.visit_testable(v.ident.to_string(), &v.attrs, |this| {
|
||||
intravisit::walk_variant(this, v, g, item_id);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,10 +130,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
Enum {
|
||||
name,
|
||||
variants: def.variants.iter().map(|v| Variant {
|
||||
name: v.node.ident.name,
|
||||
id: v.node.id,
|
||||
attrs: &v.node.attrs,
|
||||
def: &v.node.data,
|
||||
name: v.ident.name,
|
||||
id: v.id,
|
||||
attrs: &v.attrs,
|
||||
def: &v.data,
|
||||
whence: v.span,
|
||||
}).collect(),
|
||||
vis: &it.vis,
|
||||
|
|
|
|||
|
|
@ -608,6 +608,7 @@ pub struct FieldPat {
|
|||
pub pat: P<Pat>,
|
||||
pub is_shorthand: bool,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub id: NodeId,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
|
|
@ -925,6 +926,7 @@ pub struct Arm {
|
|||
pub guard: Option<P<Expr>>,
|
||||
pub body: P<Expr>,
|
||||
pub span: Span,
|
||||
pub id: NodeId,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
|
|
@ -934,6 +936,7 @@ pub struct Field {
|
|||
pub span: Span,
|
||||
pub is_shorthand: bool,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub id: NodeId,
|
||||
}
|
||||
|
||||
pub type SpannedIdent = Spanned<Ident>;
|
||||
|
|
@ -2038,7 +2041,7 @@ pub struct EnumDef {
|
|||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Variant_ {
|
||||
pub struct Variant {
|
||||
/// Name of the variant.
|
||||
pub ident: Ident,
|
||||
/// Attributes of the variant.
|
||||
|
|
@ -2049,10 +2052,10 @@ pub struct Variant_ {
|
|||
pub data: VariantData,
|
||||
/// Explicit discriminant, e.g., `Foo = 1`.
|
||||
pub disr_expr: Option<AnonConst>,
|
||||
/// Span
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub type Variant = Spanned<Variant_>;
|
||||
|
||||
/// Part of `use` item to the right of its prefix.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum UseTreeKind {
|
||||
|
|
|
|||
|
|
@ -712,7 +712,7 @@ macro_rules! derive_has_attrs {
|
|||
|
||||
derive_has_attrs! {
|
||||
Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
|
||||
ast::Field, ast::FieldPat, ast::Variant_, ast::Arg
|
||||
ast::Field, ast::FieldPat, ast::Variant, ast::Arg
|
||||
}
|
||||
|
||||
pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => {
|
||||
variants.flat_map_in_place(|variant| self.configure(variant));
|
||||
for variant in variants {
|
||||
self.configure_variant_data(&mut variant.node.data);
|
||||
self.configure_variant_data(&mut variant.data);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -405,7 +405,6 @@ impl MacResult for MacEager {
|
|||
/// after hitting errors.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DummyResult {
|
||||
expr_only: bool,
|
||||
is_error: bool,
|
||||
span: Span,
|
||||
}
|
||||
|
|
@ -416,21 +415,12 @@ impl DummyResult {
|
|||
/// Use this as a return value after hitting any errors and
|
||||
/// calling `span_err`.
|
||||
pub fn any(span: Span) -> Box<dyn MacResult+'static> {
|
||||
Box::new(DummyResult { expr_only: false, is_error: true, span })
|
||||
Box::new(DummyResult { is_error: true, span })
|
||||
}
|
||||
|
||||
/// Same as `any`, but must be a valid fragment, not error.
|
||||
pub fn any_valid(span: Span) -> Box<dyn MacResult+'static> {
|
||||
Box::new(DummyResult { expr_only: false, is_error: false, span })
|
||||
}
|
||||
|
||||
/// Creates a default MacResult that can only be an expression.
|
||||
///
|
||||
/// Use this for macros that must expand to an expression, so even
|
||||
/// if an error is encountered internally, the user will receive
|
||||
/// an error that they also used it in the wrong place.
|
||||
pub fn expr(span: Span) -> Box<dyn MacResult+'static> {
|
||||
Box::new(DummyResult { expr_only: true, is_error: true, span })
|
||||
Box::new(DummyResult { is_error: false, span })
|
||||
}
|
||||
|
||||
/// A plain dummy expression.
|
||||
|
|
@ -472,36 +462,19 @@ impl MacResult for DummyResult {
|
|||
}
|
||||
|
||||
fn make_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
|
||||
// this code needs a comment... why not always just return the Some() ?
|
||||
if self.expr_only {
|
||||
None
|
||||
} else {
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
|
||||
fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
|
||||
if self.expr_only {
|
||||
None
|
||||
} else {
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
|
||||
fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
|
||||
if self.expr_only {
|
||||
None
|
||||
} else {
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
|
||||
fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[ast::ForeignItem; 1]>> {
|
||||
if self.expr_only {
|
||||
None
|
||||
} else {
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
Some(SmallVec::new())
|
||||
}
|
||||
|
||||
fn make_stmts(self: Box<DummyResult>) -> Option<SmallVec<[ast::Stmt; 1]>> {
|
||||
|
|
@ -947,8 +920,10 @@ pub fn expr_to_spanned_string<'a>(
|
|||
// Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation.
|
||||
expr.span = expr.span.apply_mark(cx.current_expansion.id);
|
||||
|
||||
// we want to be able to handle e.g., `concat!("foo", "bar")`
|
||||
cx.expander().visit_expr(&mut expr);
|
||||
// Perform eager expansion on the expression.
|
||||
// We want to be able to handle e.g., `concat!("foo", "bar")`.
|
||||
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
|
||||
|
||||
Err(match expr.node {
|
||||
ast::ExprKind::Lit(ref l) => match l.node {
|
||||
ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))),
|
||||
|
|
@ -1013,8 +988,12 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>,
|
|||
let mut p = cx.new_parser_from_tts(tts);
|
||||
let mut es = Vec::new();
|
||||
while p.token != token::Eof {
|
||||
let mut expr = panictry!(p.parse_expr());
|
||||
cx.expander().visit_expr(&mut expr);
|
||||
let expr = panictry!(p.parse_expr());
|
||||
|
||||
// Perform eager expansion on the expression.
|
||||
// We want to be able to handle e.g., `concat!("foo", "bar")`.
|
||||
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
|
||||
|
||||
es.push(expr);
|
||||
if p.eat(&token::Comma) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
span,
|
||||
is_shorthand: false,
|
||||
attrs: ThinVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
}
|
||||
}
|
||||
pub fn expr_struct(
|
||||
|
|
@ -612,6 +613,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
guard: None,
|
||||
body: expr,
|
||||
span,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -781,14 +783,14 @@ impl<'a> ExtCtxt<'a> {
|
|||
ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID)
|
||||
};
|
||||
|
||||
respan(span,
|
||||
ast::Variant_ {
|
||||
ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: Vec::new(),
|
||||
data: vdata,
|
||||
disr_expr: None,
|
||||
})
|
||||
ast::Variant {
|
||||
attrs: Vec::new(),
|
||||
data: vdata,
|
||||
disr_expr: None,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
ident,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn item_enum_poly(&self, span: Span, name: Ident,
|
||||
|
|
|
|||
|
|
@ -116,18 +116,6 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> MutVisitor for MacroExpander<'a, 'b> {
|
||||
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
||||
self.expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr()
|
||||
}
|
||||
$($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) {
|
||||
visit_clobber(ast, |ast| self.expand_fragment(AstFragment::$Kind(ast)).$make_ast());
|
||||
})?)*
|
||||
$($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy {
|
||||
self.expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast()
|
||||
})?)*
|
||||
}
|
||||
|
||||
impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> {
|
||||
$(fn $make_ast(self: Box<crate::ext::tt::macro_rules::ParserAnyMacro<'a>>)
|
||||
-> Option<$AstTy> {
|
||||
|
|
@ -265,7 +253,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
tokens: None,
|
||||
})]);
|
||||
|
||||
match self.expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
|
||||
match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
|
||||
Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => {
|
||||
krate.attrs = attrs;
|
||||
krate.module = module;
|
||||
|
|
@ -285,8 +273,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
krate
|
||||
}
|
||||
|
||||
// Fully expand all macro invocations in this AST fragment.
|
||||
fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
|
||||
// Recursively expand all macro invocations in this AST fragment.
|
||||
pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
|
||||
let orig_expansion_data = self.cx.current_expansion.clone();
|
||||
self.cx.current_expansion.depth = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1956,7 +1956,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
|
||||
ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => {
|
||||
for variant in variants {
|
||||
match (&variant.node.data, &variant.node.disr_expr) {
|
||||
match (&variant.data, &variant.disr_expr) {
|
||||
(ast::VariantData::Unit(..), _) => {},
|
||||
(_, Some(disr_expr)) =>
|
||||
gate_feature_post!(
|
||||
|
|
|
|||
|
|
@ -383,10 +383,11 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
|
|||
}
|
||||
|
||||
pub fn noop_visit_arm<T: MutVisitor>(
|
||||
Arm { attrs, pats, guard, body, span }: &mut Arm,
|
||||
Arm { attrs, pats, guard, body, span, id }: &mut Arm,
|
||||
vis: &mut T,
|
||||
) {
|
||||
visit_attrs(attrs, vis);
|
||||
vis.visit_id(id);
|
||||
visit_vec(pats, |pat| vis.visit_pat(pat));
|
||||
visit_opt(guard, |guard| vis.visit_expr(guard));
|
||||
vis.visit_expr(body);
|
||||
|
|
@ -455,7 +456,7 @@ pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis:
|
|||
}
|
||||
|
||||
pub fn noop_visit_variant<T: MutVisitor>(variant: &mut Variant, vis: &mut T) {
|
||||
let Spanned { node: Variant_ { ident, attrs, id, data, disr_expr }, span } = variant;
|
||||
let Variant { ident, attrs, id, data, disr_expr, span } = variant;
|
||||
vis.visit_ident(ident);
|
||||
visit_attrs(attrs, vis);
|
||||
vis.visit_id(id);
|
||||
|
|
@ -808,9 +809,10 @@ pub fn noop_visit_struct_field<T: MutVisitor>(f: &mut StructField, visitor: &mut
|
|||
}
|
||||
|
||||
pub fn noop_visit_field<T: MutVisitor>(f: &mut Field, vis: &mut T) {
|
||||
let Field { ident, expr, span, is_shorthand: _, attrs } = f;
|
||||
let Field { ident, expr, span, is_shorthand: _, attrs, id } = f;
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_id(id);
|
||||
vis.visit_span(span);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
}
|
||||
|
|
@ -1040,8 +1042,12 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
}
|
||||
PatKind::Struct(path, fields, _etc) => {
|
||||
vis.visit_path(path);
|
||||
for Spanned { node: FieldPat { ident, pat, is_shorthand: _, attrs }, span } in fields {
|
||||
for Spanned {
|
||||
node: FieldPat { ident, pat, is_shorthand: _, attrs, id },
|
||||
span
|
||||
} in fields {
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_id(id);
|
||||
vis.visit_pat(pat);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
vis.visit_span(span);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, Token
|
|||
use crate::parse::token::{self, TokenKind};
|
||||
use crate::print::pprust;
|
||||
use crate::ptr::P;
|
||||
use crate::source_map::Spanned;
|
||||
use crate::symbol::{kw, sym};
|
||||
use crate::ThinVec;
|
||||
use crate::util::parser::AssocOp;
|
||||
|
|
@ -592,18 +591,18 @@ impl<'a> Parser<'a> {
|
|||
|
||||
crate fn maybe_report_invalid_custom_discriminants(
|
||||
sess: &ParseSess,
|
||||
variants: &[Spanned<ast::Variant_>],
|
||||
variants: &[ast::Variant],
|
||||
) {
|
||||
let has_fields = variants.iter().any(|variant| match variant.node.data {
|
||||
let has_fields = variants.iter().any(|variant| match variant.data {
|
||||
VariantData::Tuple(..) | VariantData::Struct(..) => true,
|
||||
VariantData::Unit(..) => false,
|
||||
});
|
||||
|
||||
let discriminant_spans = variants.iter().filter(|variant| match variant.node.data {
|
||||
let discriminant_spans = variants.iter().filter(|variant| match variant.data {
|
||||
VariantData::Tuple(..) | VariantData::Struct(..) => false,
|
||||
VariantData::Unit(..) => true,
|
||||
})
|
||||
.filter_map(|variant| variant.node.disr_expr.as_ref().map(|c| c.value.span))
|
||||
.filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !discriminant_spans.is_empty() && has_fields {
|
||||
|
|
@ -618,7 +617,7 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(sp, "disallowed custom discriminant");
|
||||
}
|
||||
for variant in variants.iter() {
|
||||
match &variant.node.data {
|
||||
match &variant.data {
|
||||
VariantData::Struct(..) => {
|
||||
err.span_label(
|
||||
variant.span,
|
||||
|
|
|
|||
|
|
@ -1448,6 +1448,7 @@ impl<'a> Parser<'a> {
|
|||
guard,
|
||||
body: expr,
|
||||
span: lo.to(hi),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1603,6 +1604,7 @@ impl<'a> Parser<'a> {
|
|||
expr: self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new()),
|
||||
is_shorthand: false,
|
||||
attrs: ThinVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1688,6 +1690,7 @@ impl<'a> Parser<'a> {
|
|||
expr,
|
||||
is_shorthand,
|
||||
attrs: attrs.into(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1564,14 +1564,15 @@ impl<'a> Parser<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
let vr = ast::Variant_ {
|
||||
let vr = ast::Variant {
|
||||
ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: variant_attrs,
|
||||
data: struct_def,
|
||||
disr_expr,
|
||||
span: vlo.to(self.prev_span),
|
||||
};
|
||||
variants.push(respan(vlo.to(self.prev_span), vr));
|
||||
variants.push(vr);
|
||||
|
||||
if !self.eat(&token::Comma) {
|
||||
if self.token.is_ident() && !self.token.is_reserved_ident() {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use super::{Parser, PResult, PathStyle};
|
|||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
use crate::ptr::P;
|
||||
use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac_};
|
||||
use crate::ast::{BindingMode, Ident, Mutability, Expr, ExprKind};
|
||||
use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
|
||||
use crate::parse::token::{self};
|
||||
use crate::print::pprust;
|
||||
use crate::source_map::{respan, Span, Spanned};
|
||||
|
|
@ -108,93 +108,52 @@ impl<'a> Parser<'a> {
|
|||
maybe_whole!(self, NtPat, |x| x);
|
||||
|
||||
let lo = self.token.span;
|
||||
let pat;
|
||||
match self.token.kind {
|
||||
token::BinOp(token::And) | token::AndAnd => {
|
||||
// Parse &pat / &mut pat
|
||||
self.expect_and()?;
|
||||
let mutbl = self.parse_mutability();
|
||||
if let token::Lifetime(name) = self.token.kind {
|
||||
let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
|
||||
err.span_label(self.token.span, "unexpected lifetime");
|
||||
return Err(err);
|
||||
}
|
||||
let subpat = self.parse_pat_with_range_pat(false, expected)?;
|
||||
pat = PatKind::Ref(subpat, mutbl);
|
||||
}
|
||||
token::OpenDelim(token::Paren) => {
|
||||
// Parse a tuple or parenthesis pattern.
|
||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
|
||||
// Here, `(pat,)` is a tuple pattern.
|
||||
// For backward compatibility, `(..)` is a tuple pattern as well.
|
||||
pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
|
||||
PatKind::Paren(fields.into_iter().nth(0).unwrap())
|
||||
} else {
|
||||
PatKind::Tuple(fields)
|
||||
};
|
||||
}
|
||||
let pat = match self.token.kind {
|
||||
token::BinOp(token::And) | token::AndAnd => self.parse_pat_deref(expected)?,
|
||||
token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?,
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
// Parse `[pat, pat,...]` as a slice pattern.
|
||||
let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?;
|
||||
pat = PatKind::Slice(slice);
|
||||
PatKind::Slice(self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?.0)
|
||||
}
|
||||
token::DotDot => {
|
||||
self.bump();
|
||||
pat = if self.is_pat_range_end_start() {
|
||||
if self.is_pat_range_end_start() {
|
||||
// Parse `..42` for recovery.
|
||||
self.parse_pat_range_to(RangeEnd::Excluded, "..")?
|
||||
} else {
|
||||
// A rest pattern `..`.
|
||||
PatKind::Rest
|
||||
};
|
||||
}
|
||||
}
|
||||
token::DotDotEq => {
|
||||
// Parse `..=42` for recovery.
|
||||
self.bump();
|
||||
pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?;
|
||||
self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?
|
||||
}
|
||||
token::DotDotDot => {
|
||||
// Parse `...42` for recovery.
|
||||
self.bump();
|
||||
pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?;
|
||||
self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?
|
||||
}
|
||||
// At this point, token != &, &&, (, [
|
||||
_ => if self.eat_keyword(kw::Underscore) {
|
||||
// Parse _
|
||||
pat = PatKind::Wild;
|
||||
PatKind::Wild
|
||||
} else if self.eat_keyword(kw::Mut) {
|
||||
// Parse mut ident @ pat / mut ref ident @ pat
|
||||
let mutref_span = self.prev_span.to(self.token.span);
|
||||
let binding_mode = if self.eat_keyword(kw::Ref) {
|
||||
self.diagnostic()
|
||||
.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
|
||||
.span_suggestion(
|
||||
mutref_span,
|
||||
"try switching the order",
|
||||
"ref mut".into(),
|
||||
Applicability::MachineApplicable
|
||||
).emit();
|
||||
BindingMode::ByRef(Mutability::Mutable)
|
||||
} else {
|
||||
BindingMode::ByValue(Mutability::Mutable)
|
||||
};
|
||||
pat = self.parse_pat_ident(binding_mode)?;
|
||||
self.recover_pat_ident_mut_first()?
|
||||
} else if self.eat_keyword(kw::Ref) {
|
||||
// Parse ref ident @ pat / ref mut ident @ pat
|
||||
let mutbl = self.parse_mutability();
|
||||
pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?;
|
||||
self.parse_pat_ident(BindingMode::ByRef(mutbl))?
|
||||
} else if self.eat_keyword(kw::Box) {
|
||||
// Parse box pat
|
||||
let subpat = self.parse_pat_with_range_pat(false, None)?;
|
||||
pat = PatKind::Box(subpat);
|
||||
// Parse `box pat`
|
||||
PatKind::Box(self.parse_pat_with_range_pat(false, None)?)
|
||||
} else if self.token.is_ident() && !self.token.is_reserved_ident() &&
|
||||
self.parse_as_ident() {
|
||||
// Parse ident @ pat
|
||||
// Parse `ident @ pat`
|
||||
// This can give false positives and parse nullary enums,
|
||||
// they are dealt with later in resolve
|
||||
let binding_mode = BindingMode::ByValue(Mutability::Immutable);
|
||||
pat = self.parse_pat_ident(binding_mode)?;
|
||||
// they are dealt with later in resolve.
|
||||
self.parse_pat_ident(BindingMode::ByValue(Mutability::Immutable))?
|
||||
} else if self.token.is_path_start() {
|
||||
// Parse pattern starting with a path
|
||||
let (qself, path) = if self.eat_lt() {
|
||||
|
|
@ -206,136 +165,186 @@ impl<'a> Parser<'a> {
|
|||
(None, self.parse_path(PathStyle::Expr)?)
|
||||
};
|
||||
match self.token.kind {
|
||||
token::Not if qself.is_none() => {
|
||||
// Parse macro invocation
|
||||
self.bump();
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
let mac = respan(lo.to(self.prev_span), Mac_ {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
});
|
||||
pat = PatKind::Mac(mac);
|
||||
}
|
||||
token::Not if qself.is_none() => self.parse_pat_mac_invoc(lo, path)?,
|
||||
token::DotDotDot | token::DotDotEq | token::DotDot => {
|
||||
let (end_kind, form) = match self.token.kind {
|
||||
token::DotDot => (RangeEnd::Excluded, ".."),
|
||||
token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
|
||||
token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
|
||||
_ => panic!("can only parse `..`/`...`/`..=` for ranges \
|
||||
(checked above)"),
|
||||
};
|
||||
let op_span = self.token.span;
|
||||
// Parse range
|
||||
let span = lo.to(self.prev_span);
|
||||
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
|
||||
self.bump();
|
||||
let end = self.parse_pat_range_end_opt(&begin, form)?;
|
||||
pat = PatKind::Range(begin, end, respan(op_span, end_kind));
|
||||
self.parse_pat_range_starting_with_path(lo, qself, path)?
|
||||
}
|
||||
token::OpenDelim(token::Brace) => {
|
||||
if qself.is_some() {
|
||||
let msg = "unexpected `{` after qualified path";
|
||||
let mut err = self.fatal(msg);
|
||||
err.span_label(self.token.span, msg);
|
||||
return Err(err);
|
||||
}
|
||||
// Parse struct pattern
|
||||
self.bump();
|
||||
let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
|
||||
e.emit();
|
||||
self.recover_stmt();
|
||||
(vec![], true)
|
||||
});
|
||||
self.bump();
|
||||
pat = PatKind::Struct(path, fields, etc);
|
||||
}
|
||||
token::OpenDelim(token::Paren) => {
|
||||
if qself.is_some() {
|
||||
let msg = "unexpected `(` after qualified path";
|
||||
let mut err = self.fatal(msg);
|
||||
err.span_label(self.token.span, msg);
|
||||
return Err(err);
|
||||
}
|
||||
// Parse tuple struct or enum pattern
|
||||
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
pat = PatKind::TupleStruct(path, fields)
|
||||
}
|
||||
_ => pat = PatKind::Path(qself, path),
|
||||
token::OpenDelim(token::Brace) => self.parse_pat_struct(qself, path)?,
|
||||
token::OpenDelim(token::Paren) => self.parse_pat_tuple_struct(qself, path)?,
|
||||
_ => PatKind::Path(qself, path),
|
||||
}
|
||||
} else {
|
||||
// Try to parse everything else as literal with optional minus
|
||||
match self.parse_literal_maybe_minus() {
|
||||
Ok(begin) => {
|
||||
let op_span = self.token.span;
|
||||
if self.check(&token::DotDot) || self.check(&token::DotDotEq) ||
|
||||
self.check(&token::DotDotDot) {
|
||||
let (end_kind, form) = if self.eat(&token::DotDotDot) {
|
||||
(RangeEnd::Included(RangeSyntax::DotDotDot), "...")
|
||||
} else if self.eat(&token::DotDotEq) {
|
||||
(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
|
||||
} else if self.eat(&token::DotDot) {
|
||||
(RangeEnd::Excluded, "..")
|
||||
} else {
|
||||
panic!("impossible case: we already matched \
|
||||
on a range-operator token")
|
||||
};
|
||||
let end = self.parse_pat_range_end_opt(&begin, form)?;
|
||||
pat = PatKind::Range(begin, end, respan(op_span, end_kind))
|
||||
} else {
|
||||
pat = PatKind::Lit(begin);
|
||||
}
|
||||
}
|
||||
Err(mut err) => {
|
||||
self.cancel(&mut err);
|
||||
let expected = expected.unwrap_or("pattern");
|
||||
let msg = format!(
|
||||
"expected {}, found {}",
|
||||
expected,
|
||||
self.this_token_descr(),
|
||||
);
|
||||
let mut err = self.fatal(&msg);
|
||||
err.span_label(self.token.span, format!("expected {}", expected));
|
||||
let sp = self.sess.source_map().start_point(self.token.span);
|
||||
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
|
||||
self.sess.expr_parentheses_needed(&mut err, *sp, None);
|
||||
}
|
||||
return Err(err);
|
||||
Ok(begin)
|
||||
if self.check(&token::DotDot)
|
||||
|| self.check(&token::DotDotEq)
|
||||
|| self.check(&token::DotDotDot) =>
|
||||
{
|
||||
self.parse_pat_range_starting_with_lit(begin)?
|
||||
}
|
||||
Ok(begin) => PatKind::Lit(begin),
|
||||
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let pat = self.mk_pat(lo.to(self.prev_span), pat);
|
||||
let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
|
||||
|
||||
if !allow_range_pat {
|
||||
match pat.node {
|
||||
PatKind::Range(
|
||||
_, _, Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. }
|
||||
) => {},
|
||||
PatKind::Range(..) => {
|
||||
let mut err = self.struct_span_err(
|
||||
pat.span,
|
||||
"the range pattern here has ambiguous interpretation",
|
||||
);
|
||||
err.span_suggestion(
|
||||
pat.span,
|
||||
"add parentheses to clarify the precedence",
|
||||
format!("({})", pprust::pat_to_string(&pat)),
|
||||
// "ambiguous interpretation" implies that we have to be guessing
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.ban_pat_range_if_ambiguous(&pat)?
|
||||
}
|
||||
|
||||
Ok(pat)
|
||||
}
|
||||
|
||||
/// Ban a range pattern if it has an ambiguous interpretation.
|
||||
fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> {
|
||||
match pat.node {
|
||||
PatKind::Range(
|
||||
.., Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. }
|
||||
) => return Ok(()),
|
||||
PatKind::Range(..) => {}
|
||||
_ => return Ok(()),
|
||||
}
|
||||
|
||||
let mut err = self.struct_span_err(
|
||||
pat.span,
|
||||
"the range pattern here has ambiguous interpretation",
|
||||
);
|
||||
err.span_suggestion(
|
||||
pat.span,
|
||||
"add parentheses to clarify the precedence",
|
||||
format!("({})", pprust::pat_to_string(&pat)),
|
||||
// "ambiguous interpretation" implies that we have to be guessing
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
Err(err)
|
||||
}
|
||||
|
||||
/// Parse `&pat` / `&mut pat`.
|
||||
fn parse_pat_deref(&mut self, expected: Option<&'static str>) -> PResult<'a, PatKind> {
|
||||
self.expect_and()?;
|
||||
let mutbl = self.parse_mutability();
|
||||
|
||||
if let token::Lifetime(name) = self.token.kind {
|
||||
let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
|
||||
err.span_label(self.token.span, "unexpected lifetime");
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let subpat = self.parse_pat_with_range_pat(false, expected)?;
|
||||
Ok(PatKind::Ref(subpat, mutbl))
|
||||
}
|
||||
|
||||
/// Parse a tuple or parenthesis pattern.
|
||||
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
|
||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
|
||||
// Here, `(pat,)` is a tuple pattern.
|
||||
// For backward compatibility, `(..)` is a tuple pattern as well.
|
||||
Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
|
||||
PatKind::Paren(fields.into_iter().nth(0).unwrap())
|
||||
} else {
|
||||
PatKind::Tuple(fields)
|
||||
})
|
||||
}
|
||||
|
||||
/// Recover on `mut ref? ident @ pat` and suggest
|
||||
/// that the order of `mut` and `ref` is incorrect.
|
||||
fn recover_pat_ident_mut_first(&mut self) -> PResult<'a, PatKind> {
|
||||
let mutref_span = self.prev_span.to(self.token.span);
|
||||
let binding_mode = if self.eat_keyword(kw::Ref) {
|
||||
self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
|
||||
.span_suggestion(
|
||||
mutref_span,
|
||||
"try switching the order",
|
||||
"ref mut".into(),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
BindingMode::ByRef(Mutability::Mutable)
|
||||
} else {
|
||||
BindingMode::ByValue(Mutability::Mutable)
|
||||
};
|
||||
self.parse_pat_ident(binding_mode)
|
||||
}
|
||||
|
||||
/// Parse macro invocation
|
||||
fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> {
|
||||
self.bump();
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
let mac = respan(lo.to(self.prev_span), Mac_ {
|
||||
path,
|
||||
tts,
|
||||
delim,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
});
|
||||
Ok(PatKind::Mac(mac))
|
||||
}
|
||||
|
||||
/// Parse a range pattern `$path $form $end?` where `$form = ".." | "..." | "..=" ;`.
|
||||
/// The `$path` has already been parsed and the next token is the `$form`.
|
||||
fn parse_pat_range_starting_with_path(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
qself: Option<QSelf>,
|
||||
path: Path
|
||||
) -> PResult<'a, PatKind> {
|
||||
let (end_kind, form) = match self.token.kind {
|
||||
token::DotDot => (RangeEnd::Excluded, ".."),
|
||||
token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
|
||||
token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
|
||||
_ => panic!("can only parse `..`/`...`/`..=` for ranges (checked above)"),
|
||||
};
|
||||
let op_span = self.token.span;
|
||||
// Parse range
|
||||
let span = lo.to(self.prev_span);
|
||||
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
|
||||
self.bump();
|
||||
let end = self.parse_pat_range_end_opt(&begin, form)?;
|
||||
Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
|
||||
}
|
||||
|
||||
/// Parse a range pattern `$literal $form $end?` where `$form = ".." | "..." | "..=" ;`.
|
||||
/// The `$path` has already been parsed and the next token is the `$form`.
|
||||
fn parse_pat_range_starting_with_lit(&mut self, begin: P<Expr>) -> PResult<'a, PatKind> {
|
||||
let op_span = self.token.span;
|
||||
let (end_kind, form) = if self.eat(&token::DotDotDot) {
|
||||
(RangeEnd::Included(RangeSyntax::DotDotDot), "...")
|
||||
} else if self.eat(&token::DotDotEq) {
|
||||
(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
|
||||
} else if self.eat(&token::DotDot) {
|
||||
(RangeEnd::Excluded, "..")
|
||||
} else {
|
||||
panic!("impossible case: we already matched on a range-operator token")
|
||||
};
|
||||
let end = self.parse_pat_range_end_opt(&begin, form)?;
|
||||
Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
|
||||
}
|
||||
|
||||
fn fatal_unexpected_non_pat(
|
||||
&mut self,
|
||||
mut err: DiagnosticBuilder<'a>,
|
||||
expected: Option<&'static str>,
|
||||
) -> PResult<'a, P<Pat>> {
|
||||
self.cancel(&mut err);
|
||||
|
||||
let expected = expected.unwrap_or("pattern");
|
||||
let msg = format!("expected {}, found {}", expected, self.this_token_descr());
|
||||
|
||||
let mut err = self.fatal(&msg);
|
||||
err.span_label(self.token.span, format!("expected {}", expected));
|
||||
|
||||
let sp = self.sess.source_map().start_point(self.token.span);
|
||||
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
|
||||
self.sess.expr_parentheses_needed(&mut err, *sp, None);
|
||||
}
|
||||
|
||||
Err(err)
|
||||
}
|
||||
|
||||
// Helper function to decide whether to parse as ident binding
|
||||
// or to try to do something more complex like range patterns.
|
||||
fn parse_as_ident(&mut self) -> bool {
|
||||
|
|
@ -421,11 +430,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Parses `ident` or `ident @ pat`.
|
||||
/// used by the copy foo and ref foo patterns to give a good
|
||||
/// Used by the copy foo and ref foo patterns to give a good
|
||||
/// error message when parsing mistakes like `ref foo(a, b)`.
|
||||
fn parse_pat_ident(&mut self,
|
||||
binding_mode: ast::BindingMode)
|
||||
-> PResult<'a, PatKind> {
|
||||
fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
|
||||
let ident = self.parse_ident()?;
|
||||
let sub = if self.eat(&token::At) {
|
||||
Some(self.parse_pat(Some("binding pattern"))?)
|
||||
|
|
@ -433,21 +440,52 @@ impl<'a> Parser<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
// just to be friendly, if they write something like
|
||||
// ref Some(i)
|
||||
// we end up here with ( as the current token. This shortly
|
||||
// leads to a parse error. Note that if there is no explicit
|
||||
// Just to be friendly, if they write something like `ref Some(i)`,
|
||||
// we end up here with `(` as the current token.
|
||||
// This shortly leads to a parse error. Note that if there is no explicit
|
||||
// binding mode then we do not end up here, because the lookahead
|
||||
// will direct us over to parse_enum_variant()
|
||||
// will direct us over to `parse_enum_variant()`.
|
||||
if self.token == token::OpenDelim(token::Paren) {
|
||||
return Err(self.span_fatal(
|
||||
self.prev_span,
|
||||
"expected identifier, found enum pattern"))
|
||||
"expected identifier, found enum pattern",
|
||||
))
|
||||
}
|
||||
|
||||
Ok(PatKind::Ident(binding_mode, ident, sub))
|
||||
}
|
||||
|
||||
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
|
||||
fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
|
||||
if qself.is_some() {
|
||||
let msg = "unexpected `{` after qualified path";
|
||||
let mut err = self.fatal(msg);
|
||||
err.span_label(self.token.span, msg);
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
self.bump();
|
||||
let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
|
||||
e.emit();
|
||||
self.recover_stmt();
|
||||
(vec![], true)
|
||||
});
|
||||
self.bump();
|
||||
Ok(PatKind::Struct(path, fields, etc))
|
||||
}
|
||||
|
||||
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
|
||||
fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
|
||||
if qself.is_some() {
|
||||
let msg = "unexpected `(` after qualified path";
|
||||
let mut err = self.fatal(msg);
|
||||
err.span_label(self.token.span, msg);
|
||||
return Err(err);
|
||||
}
|
||||
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
Ok(PatKind::TupleStruct(path, fields))
|
||||
}
|
||||
|
||||
/// Parses the fields of a struct-like pattern.
|
||||
fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<Spanned<FieldPat>>, bool)> {
|
||||
let mut fields = Vec::new();
|
||||
|
|
@ -482,17 +520,7 @@ impl<'a> Parser<'a> {
|
|||
etc = true;
|
||||
let mut etc_sp = self.token.span;
|
||||
|
||||
if self.token == token::DotDotDot { // Issue #46718
|
||||
// Accept `...` as if it were `..` to avoid further errors
|
||||
self.struct_span_err(self.token.span, "expected field pattern, found `...`")
|
||||
.span_suggestion(
|
||||
self.token.span,
|
||||
"to omit remaining fields, use one fewer `.`",
|
||||
"..".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.recover_one_fewer_dotdot();
|
||||
self.bump(); // `..` || `...`
|
||||
|
||||
if self.token == token::CloseDelim(token::Brace) {
|
||||
|
|
@ -574,6 +602,23 @@ impl<'a> Parser<'a> {
|
|||
return Ok((fields, etc));
|
||||
}
|
||||
|
||||
/// Recover on `...` as if it were `..` to avoid further errors.
|
||||
/// See issue #46718.
|
||||
fn recover_one_fewer_dotdot(&self) {
|
||||
if self.token != token::DotDotDot {
|
||||
return;
|
||||
}
|
||||
|
||||
self.struct_span_err(self.token.span, "expected field pattern, found `...`")
|
||||
.span_suggestion(
|
||||
self.token.span,
|
||||
"to omit remaining fields, use one fewer `.`",
|
||||
"..".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn parse_pat_field(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
|
|
@ -620,6 +665,7 @@ impl<'a> Parser<'a> {
|
|||
pat: subpat,
|
||||
is_shorthand,
|
||||
attrs: attrs.into(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,22 @@ impl<'a> Parser<'a> {
|
|||
if self.token == token::Semi {
|
||||
unused_attrs(&attrs, self);
|
||||
self.bump();
|
||||
return Ok(None);
|
||||
let mut last_semi = lo;
|
||||
while self.token == token::Semi {
|
||||
last_semi = self.token.span;
|
||||
self.bump();
|
||||
}
|
||||
// We are encoding a string of semicolons as an
|
||||
// an empty tuple that spans the excess semicolons
|
||||
// to preserve this info until the lint stage
|
||||
return Ok(Some(Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: lo.to(last_semi),
|
||||
node: StmtKind::Semi(self.mk_expr(lo.to(last_semi),
|
||||
ExprKind::Tup(Vec::new()),
|
||||
ThinVec::new()
|
||||
)),
|
||||
}));
|
||||
}
|
||||
|
||||
if self.token == token::CloseDelim(token::Brace) {
|
||||
|
|
|
|||
|
|
@ -1402,7 +1402,7 @@ impl<'a> State<'a> {
|
|||
for v in variants {
|
||||
self.space_if_not_bol();
|
||||
self.maybe_print_comment(v.span.lo());
|
||||
self.print_outer_attributes(&v.node.attrs);
|
||||
self.print_outer_attributes(&v.attrs);
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.print_variant(v);
|
||||
self.s.word(",");
|
||||
|
|
@ -1492,8 +1492,8 @@ impl<'a> State<'a> {
|
|||
crate fn print_variant(&mut self, v: &ast::Variant) {
|
||||
self.head("");
|
||||
let generics = ast::Generics::default();
|
||||
self.print_struct(&v.node.data, &generics, v.node.ident, v.span, false);
|
||||
match v.node.disr_expr {
|
||||
self.print_struct(&v.data, &generics, v.ident, v.span, false);
|
||||
match v.disr_expr {
|
||||
Some(ref d) => {
|
||||
self.s.space();
|
||||
self.word_space("=");
|
||||
|
|
|
|||
|
|
@ -54,14 +54,15 @@ fn test_variant_to_string() {
|
|||
with_default_globals(|| {
|
||||
let ident = ast::Ident::from_str("principal_skinner");
|
||||
|
||||
let var = source_map::respan(syntax_pos::DUMMY_SP, ast::Variant_ {
|
||||
let var = ast::Variant {
|
||||
ident,
|
||||
attrs: Vec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
// making this up as I go.... ?
|
||||
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
|
||||
disr_expr: None,
|
||||
});
|
||||
span: syntax_pos::DUMMY_SP,
|
||||
};
|
||||
|
||||
let varstr = variant_to_string(&var);
|
||||
assert_eq!(varstr, "principal_skinner");
|
||||
|
|
|
|||
|
|
@ -311,11 +311,11 @@ pub fn walk_variant<'a, V>(visitor: &mut V,
|
|||
item_id: NodeId)
|
||||
where V: Visitor<'a>,
|
||||
{
|
||||
visitor.visit_ident(variant.node.ident);
|
||||
visitor.visit_variant_data(&variant.node.data, variant.node.ident,
|
||||
visitor.visit_ident(variant.ident);
|
||||
visitor.visit_variant_data(&variant.data, variant.ident,
|
||||
generics, item_id, variant.span);
|
||||
walk_list!(visitor, visit_anon_const, &variant.node.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.node.attrs);
|
||||
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
|||
-> Box<dyn base::MacResult + 'cx> {
|
||||
let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
|
||||
Ok(Some(inline_asm)) => inline_asm,
|
||||
Ok(None) => return DummyResult::expr(sp),
|
||||
Ok(None) => return DummyResult::any(sp),
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
return DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub fn expand_assert<'cx>(
|
|||
Ok(assert) => assert,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
return DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub fn expand_cfg(
|
|||
}
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
DummyResult::expr(sp)
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use syntax::ast;
|
||||
use syntax::ext::base;
|
||||
use syntax::ext::base::{self, DummyResult};
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::tokenstream;
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ pub fn expand_syntax_ext(
|
|||
) -> Box<dyn base::MacResult + 'static> {
|
||||
let es = match base::get_exprs_from_tts(cx, sp, tts) {
|
||||
Some(e) => e,
|
||||
None => return base::DummyResult::expr(sp),
|
||||
None => return DummyResult::any(sp),
|
||||
};
|
||||
let mut accumulator = String::new();
|
||||
let mut missing_literal = vec![];
|
||||
|
|
@ -55,9 +55,9 @@ pub fn expand_syntax_ext(
|
|||
let mut err = cx.struct_span_err(missing_literal, "expected a literal");
|
||||
err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`");
|
||||
err.emit();
|
||||
return base::DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
} else if has_errors {
|
||||
return base::DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
let sp = sp.apply_mark(cx.current_expansion.id);
|
||||
base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ fn cs_clone_shallow(name: &str,
|
|||
}
|
||||
StaticEnum(enum_def, ..) => {
|
||||
for variant in &enum_def.variants {
|
||||
process_variant(cx, &mut stmts, &variant.node.data);
|
||||
process_variant(cx, &mut stmts, &variant.data);
|
||||
}
|
||||
}
|
||||
_ => cx.span_bug(trait_span, &format!("unexpected substructure in \
|
||||
|
|
@ -170,9 +170,9 @@ fn cs_clone(name: &str,
|
|||
vdata = vdata_;
|
||||
}
|
||||
EnumMatching(.., variant, ref af) => {
|
||||
ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.ident]);
|
||||
ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]);
|
||||
all_fields = af;
|
||||
vdata = &variant.node.data;
|
||||
vdata = &variant.data;
|
||||
}
|
||||
EnumNonMatchingCollapsed(..) => {
|
||||
cx.span_bug(trait_span,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>,
|
|||
}
|
||||
StaticEnum(enum_def, ..) => {
|
||||
for variant in &enum_def.variants {
|
||||
process_variant(cx, &mut stmts, &variant.node.data);
|
||||
process_variant(cx, &mut stmts, &variant.data);
|
||||
}
|
||||
}
|
||||
_ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`")
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
|||
// based on the "shape".
|
||||
let (ident, vdata, fields) = match substr.fields {
|
||||
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
|
||||
EnumMatching(_, _, v, fields) => (v.node.ident, &v.node.data, fields),
|
||||
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
|
||||
EnumNonMatchingCollapsed(..) |
|
||||
StaticStruct(..) |
|
||||
StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"),
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ fn encodable_substructure(cx: &mut ExtCtxt<'_>,
|
|||
}
|
||||
|
||||
let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
|
||||
let name = cx.expr_str(trait_span, variant.node.ident.name);
|
||||
let name = cx.expr_str(trait_span, variant.ident.name);
|
||||
let call = cx.expr_method_call(trait_span,
|
||||
blkencoder,
|
||||
cx.ident_of("emit_enum_variant"),
|
||||
|
|
|
|||
|
|
@ -758,7 +758,7 @@ impl<'a> TraitDef<'a> {
|
|||
let mut field_tys = Vec::new();
|
||||
|
||||
for variant in &enum_def.variants {
|
||||
field_tys.extend(variant.node
|
||||
field_tys.extend(variant
|
||||
.data
|
||||
.fields()
|
||||
.iter()
|
||||
|
|
@ -1220,7 +1220,7 @@ impl<'a> MethodDef<'a> {
|
|||
let catch_all_substructure =
|
||||
EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]);
|
||||
|
||||
let first_fieldless = variants.iter().find(|v| v.node.data.fields().is_empty());
|
||||
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
|
||||
|
||||
// These arms are of the form:
|
||||
// (Variant1, Variant1, ...) => Body1
|
||||
|
|
@ -1229,7 +1229,7 @@ impl<'a> MethodDef<'a> {
|
|||
// where each tuple has length = self_args.len()
|
||||
let mut match_arms: Vec<ast::Arm> = variants.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, v)| !(self.unify_fieldless_variants && v.node.data.fields().is_empty()))
|
||||
.filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
|
||||
.map(|(index, variant)| {
|
||||
let mk_self_pat = |cx: &mut ExtCtxt<'_>, self_arg_name: &str| {
|
||||
let (p, idents) = trait_.create_enum_variant_pattern(cx,
|
||||
|
|
@ -1513,8 +1513,8 @@ impl<'a> MethodDef<'a> {
|
|||
.iter()
|
||||
.map(|v| {
|
||||
let sp = v.span.with_ctxt(trait_.span.ctxt());
|
||||
let summary = trait_.summarise_struct(cx, &v.node.data);
|
||||
(v.node.ident, sp, summary)
|
||||
let summary = trait_.summarise_struct(cx, &v.data);
|
||||
(v.ident, sp, summary)
|
||||
})
|
||||
.collect();
|
||||
self.call_substructure_method(cx,
|
||||
|
|
@ -1613,6 +1613,7 @@ impl<'a> TraitDef<'a> {
|
|||
source_map::Spanned {
|
||||
span: pat.span.with_ctxt(self.span.ctxt()),
|
||||
node: ast::FieldPat {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
ident: ident.unwrap(),
|
||||
pat,
|
||||
is_shorthand: false,
|
||||
|
|
@ -1643,9 +1644,9 @@ impl<'a> TraitDef<'a> {
|
|||
mutbl: ast::Mutability)
|
||||
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
|
||||
let sp = variant.span.with_ctxt(self.span.ctxt());
|
||||
let variant_path = cx.path(sp, vec![enum_ident, variant.node.ident]);
|
||||
let variant_path = cx.path(sp, vec![enum_ident, variant.ident]);
|
||||
let use_temporaries = false; // enums can't be repr(packed)
|
||||
self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl,
|
||||
self.create_struct_pattern(cx, variant_path, &variant.data, prefix, mutbl,
|
||||
use_temporaries)
|
||||
}
|
||||
}
|
||||
|
|
@ -1776,7 +1777,7 @@ pub fn is_type_without_fields(item: &Annotatable) -> bool {
|
|||
if let Annotatable::Item(ref item) = *item {
|
||||
match item.node {
|
||||
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||
enum_def.variants.iter().all(|v| v.node.data.fields().is_empty())
|
||||
enum_def.variants.iter().all(|v| v.data.fields().is_empty())
|
||||
}
|
||||
ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(),
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
|||
tts: &[tokenstream::TokenTree])
|
||||
-> Box<dyn base::MacResult + 'cx> {
|
||||
let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
|
||||
None => return DummyResult::expr(sp),
|
||||
None => return DummyResult::any(sp),
|
||||
Some(v) => v,
|
||||
};
|
||||
|
||||
|
|
@ -50,21 +50,21 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
|||
let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
|
||||
Some(ref exprs) if exprs.is_empty() => {
|
||||
cx.span_err(sp, "env! takes 1 or 2 arguments");
|
||||
return DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
None => return DummyResult::expr(sp),
|
||||
None => return DummyResult::any(sp),
|
||||
Some(exprs) => exprs.into_iter(),
|
||||
};
|
||||
|
||||
let var = match expr_to_string(cx, exprs.next().unwrap(), "expected string literal") {
|
||||
None => return DummyResult::expr(sp),
|
||||
None => return DummyResult::any(sp),
|
||||
Some((v, _style)) => v,
|
||||
};
|
||||
let msg = match exprs.next() {
|
||||
None => Symbol::intern(&format!("environment variable `{}` not defined", var)),
|
||||
Some(second) => {
|
||||
match expr_to_string(cx, second, "expected string literal") {
|
||||
None => return DummyResult::expr(sp),
|
||||
None => return DummyResult::any(sp),
|
||||
Some((s, _style)) => s,
|
||||
}
|
||||
}
|
||||
|
|
@ -72,13 +72,13 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
|||
|
||||
if exprs.next().is_some() {
|
||||
cx.span_err(sp, "env! takes 1 or 2 arguments");
|
||||
return DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
||||
let e = match env::var(&*var.as_str()) {
|
||||
Err(_) => {
|
||||
cx.span_err(sp, &msg.as_str());
|
||||
return DummyResult::expr(sp);
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
Ok(s) => cx.expr_str(sp, Symbol::intern(&s)),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -805,7 +805,7 @@ fn expand_format_args_impl<'cx>(
|
|||
}
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
DummyResult::expr(sp)
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
use std::mem;
|
||||
|
||||
use smallvec::smallvec;
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::attr;
|
||||
use syntax::source_map::{ExpnInfo, ExpnKind, respan};
|
||||
use syntax::ext::base::{ExtCtxt, MacroKind};
|
||||
use syntax::ext::expand::ExpansionConfig;
|
||||
use syntax::ext::expand::{AstFragment, ExpansionConfig};
|
||||
use syntax::ext::hygiene::ExpnId;
|
||||
use syntax::ext::proc_macro::is_proc_macro_attr;
|
||||
use syntax::mut_visit::MutVisitor;
|
||||
use syntax::parse::ParseSess;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
struct ProcMacroDerive {
|
||||
|
|
@ -409,5 +408,7 @@ fn mk_decls(
|
|||
i
|
||||
});
|
||||
|
||||
cx.monotonic_expander().flat_map_item(module).pop().unwrap()
|
||||
// Integrate the new module into existing module structures.
|
||||
let module = AstFragment::Items(smallvec![module]);
|
||||
cx.monotonic_expander().fully_expand_fragment(module).make_items().pop().unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To
|
|||
-> Box<dyn base::MacResult+'static> {
|
||||
let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
|
||||
Some(f) => f,
|
||||
None => return DummyResult::expr(sp)
|
||||
None => return DummyResult::any(sp)
|
||||
};
|
||||
let file = cx.resolve_path(file, sp);
|
||||
match fs::read_to_string(&file) {
|
||||
|
|
@ -126,11 +126,11 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To
|
|||
},
|
||||
Err(ref e) if e.kind() == ErrorKind::InvalidData => {
|
||||
cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display()));
|
||||
DummyResult::expr(sp)
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
Err(e) => {
|
||||
cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
|
||||
DummyResult::expr(sp)
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
|
|||
-> Box<dyn base::MacResult+'static> {
|
||||
let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
|
||||
Some(f) => f,
|
||||
None => return DummyResult::expr(sp)
|
||||
None => return DummyResult::any(sp)
|
||||
};
|
||||
let file = cx.resolve_path(file, sp);
|
||||
match fs::read(&file) {
|
||||
|
|
@ -158,7 +158,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
|
|||
},
|
||||
Err(e) => {
|
||||
cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
|
||||
DummyResult::expr(sp)
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use syntax::ast::{self, Ident};
|
|||
use syntax::attr;
|
||||
use syntax::entry::{self, EntryPointType};
|
||||
use syntax::ext::base::{ExtCtxt, Resolver};
|
||||
use syntax::ext::expand::ExpansionConfig;
|
||||
use syntax::ext::expand::{AstFragment, ExpansionConfig};
|
||||
use syntax::ext::hygiene::{ExpnId, MacroKind};
|
||||
use syntax::feature_gate::Features;
|
||||
use syntax::mut_visit::{*, ExpectOne};
|
||||
|
|
@ -74,12 +74,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
|||
noop_visit_crate(c, self);
|
||||
|
||||
// Create a main function to run our tests
|
||||
let test_main = {
|
||||
let unresolved = mk_main(&mut self.cx);
|
||||
self.cx.ext_cx.monotonic_expander().flat_map_item(unresolved).pop().unwrap()
|
||||
};
|
||||
|
||||
c.module.items.push(test_main);
|
||||
c.module.items.push(mk_main(&mut self.cx));
|
||||
}
|
||||
|
||||
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||
|
|
@ -216,7 +211,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
|
|||
let name = Ident::from_str("__test_reexports").gensym();
|
||||
let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
|
||||
cx.ext_cx.current_expansion.id = cx.ext_cx.resolver.get_module_scope(parent);
|
||||
let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item {
|
||||
let module = P(ast::Item {
|
||||
ident: name,
|
||||
attrs: Vec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
|
@ -224,9 +219,14 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
|
|||
vis: dummy_spanned(ast::VisibilityKind::Public),
|
||||
span: DUMMY_SP,
|
||||
tokens: None,
|
||||
})).pop().unwrap();
|
||||
});
|
||||
|
||||
(it, name)
|
||||
// Integrate the new module into existing module structures.
|
||||
let module = AstFragment::Items(smallvec![module]);
|
||||
let module =
|
||||
cx.ext_cx.monotonic_expander().fully_expand_fragment(module).make_items().pop().unwrap();
|
||||
|
||||
(module, name)
|
||||
}
|
||||
|
||||
/// Crawl over the crate, inserting test reexports and the test main function
|
||||
|
|
@ -321,7 +321,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
|
|||
None => Ident::from_str_and_span("main", sp).gensym(),
|
||||
};
|
||||
|
||||
P(ast::Item {
|
||||
let main = P(ast::Item {
|
||||
ident: main_id,
|
||||
attrs: vec![main_attr],
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
|
@ -329,8 +329,11 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
|
|||
vis: dummy_spanned(ast::VisibilityKind::Public),
|
||||
span: sp,
|
||||
tokens: None,
|
||||
})
|
||||
});
|
||||
|
||||
// Integrate the new item into existing module structures.
|
||||
let main = AstFragment::Items(smallvec![main]);
|
||||
cx.ext_cx.monotonic_expander().fully_expand_fragment(main).make_items().pop().unwrap()
|
||||
}
|
||||
|
||||
fn path_name_i(idents: &[Ident]) -> String {
|
||||
|
|
|
|||
12
src/test/ui/async-await/issues/non-async-enclosing-span.rs
Normal file
12
src/test/ui/async-await/issues/non-async-enclosing-span.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// edition:2018
|
||||
#![feature(async_await)]
|
||||
|
||||
async fn do_the_thing() -> u8 {
|
||||
8
|
||||
}
|
||||
// #63398: point at the enclosing scope and not the previously seen closure
|
||||
fn main() { //~ NOTE this is not `async`
|
||||
let x = move || {};
|
||||
let y = do_the_thing().await; //~ ERROR `await` is only allowed inside `async` functions
|
||||
//~^ NOTE only allowed inside `async` functions and blocks
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||
--> $DIR/non-async-enclosing-span.rs:10:13
|
||||
|
|
||||
LL | fn main() {
|
||||
| ---- this is not `async`
|
||||
LL | let x = move || {};
|
||||
LL | let y = do_the_thing().await;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
8
src/test/ui/block-expr-precedence.stderr
Normal file
8
src/test/ui/block-expr-precedence.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
warning: unnecessary trailing semicolons
|
||||
--> $DIR/block-expr-precedence.rs:60:21
|
||||
|
|
||||
LL | if (true) { 12; };;; -num;
|
||||
| ^^ help: remove these semicolons
|
||||
|
|
||||
= note: `#[warn(redundant_semicolon)]` on by default
|
||||
|
||||
|
|
@ -11,10 +11,11 @@ const NON_NULL_PTR: NonNull<u8> = unsafe { mem::transmute(&1) };
|
|||
const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
|
||||
#[deny(const_err)] // this triggers a `const_err` so validation does not even happen
|
||||
const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
|
||||
let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic
|
||||
let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
|
||||
// Use address-of-element for pointer arithmetic. This could wrap around to NULL!
|
||||
let out_of_bounds_ptr = &ptr[255]; //~ ERROR any use of this value will cause an error
|
||||
mem::transmute(out_of_bounds_ptr)
|
||||
} };
|
||||
|
||||
|
|
|
|||
|
|
@ -6,21 +6,26 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
|
|||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:14:1
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/ub-nonnull.rs:18:29
|
||||
|
|
||||
LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
|
||||
LL | |
|
||||
LL | | let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
|
||||
LL | | let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic
|
||||
LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
|
||||
LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
|
||||
LL | | let out_of_bounds_ptr = &ptr[255];
|
||||
| | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1
|
||||
LL | | mem::transmute(out_of_bounds_ptr)
|
||||
LL | | } };
|
||||
| |____^ type validation failed: encountered a potentially NULL pointer, but expected something that cannot possibly fail to be greater or equal to 1
|
||||
| |____-
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
note: lint level defined here
|
||||
--> $DIR/ub-nonnull.rs:14:8
|
||||
|
|
||||
LL | #[deny(const_err)] // this triggers a `const_err` so validation does not even happen
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:21:1
|
||||
--> $DIR/ub-nonnull.rs:22:1
|
||||
|
|
||||
LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
|
||||
|
|
@ -28,7 +33,7 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
|
|||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:23:1
|
||||
--> $DIR/ub-nonnull.rs:24:1
|
||||
|
|
||||
LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
|
||||
|
|
@ -36,7 +41,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
|
|||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:30:1
|
||||
--> $DIR/ub-nonnull.rs:31:1
|
||||
|
|
||||
LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1
|
||||
|
|
@ -44,7 +49,7 @@ LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out };
|
|||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:38:1
|
||||
--> $DIR/ub-nonnull.rs:39:1
|
||||
|
|
||||
LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30
|
||||
|
|
@ -52,7 +57,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
|
|||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-nonnull.rs:44:1
|
||||
--> $DIR/ub-nonnull.rs:45:1
|
||||
|
|
||||
LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ error: expected `{`, found `;`
|
|||
LL | if not // lack of braces is [sic]
|
||||
| -- this `if` statement has a condition, but no block
|
||||
LL | println!("Then when?");
|
||||
| ^ expected `{`
|
||||
| ^
|
||||
| |
|
||||
| expected `{`
|
||||
| help: try placing this code inside a block: `{ ; }`
|
||||
|
||||
error: unexpected `2` after identifier
|
||||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@ error[E0282]: type annotations needed
|
|||
--> $DIR/E0282.rs:2:9
|
||||
|
|
||||
LL | let x = "hello".chars().rev().collect();
|
||||
| ^
|
||||
| |
|
||||
| cannot infer type
|
||||
| consider giving `x` a type
|
||||
| ^ consider giving `x` a type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@ error[E0282]: type annotations needed
|
|||
--> $DIR/for-loop-unconstrained-element-type.rs:8:14
|
||||
|
|
||||
LL | for i in Vec::new() { }
|
||||
| ^^^^^^^^^^
|
||||
| |
|
||||
| cannot infer type
|
||||
| the element type for this iterator is not specified
|
||||
| ^^^^^^^^^^ the element type for this iterator is not specified
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// Test that niche finding works with captured generator upvars.
|
||||
|
||||
// run-pass
|
||||
|
||||
#![feature(generators)]
|
||||
|
||||
use std::mem::size_of_val;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// edition:2018
|
||||
#![feature(async_await)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
|
||||
|
||||
use std::io::Error;
|
||||
|
||||
fn make_unit() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let fut = async {
|
||||
make_unit()?; //~ ERROR type annotations needed
|
||||
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:3:12
|
||||
|
|
||||
LL | #![feature(impl_trait_in_bindings)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0282]: type annotations needed for `impl std::future::Future`
|
||||
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:14:9
|
||||
|
|
||||
LL | let fut = async {
|
||||
| --- consider giving `fut` the explicit type `impl std::future::Future`, with the type parameters specified
|
||||
LL | make_unit()?;
|
||||
| ^^^^^^^^^^^^ cannot infer type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
16
src/test/ui/inference/cannot-infer-async.rs
Normal file
16
src/test/ui/inference/cannot-infer-async.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// edition:2018
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::io::Error;
|
||||
|
||||
fn make_unit() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let fut = async {
|
||||
make_unit()?; //~ ERROR type annotations needed
|
||||
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
11
src/test/ui/inference/cannot-infer-async.stderr
Normal file
11
src/test/ui/inference/cannot-infer-async.stderr
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
error[E0282]: type annotations needed
|
||||
--> $DIR/cannot-infer-async.rs:12:9
|
||||
|
|
||||
LL | let fut = async {
|
||||
| --- consider giving `fut` a type
|
||||
LL | make_unit()?;
|
||||
| ^^^^^^^^^^^^ cannot infer type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
6
src/test/ui/inference/cannot-infer-closure.rs
Normal file
6
src/test/ui/inference/cannot-infer-closure.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
let x = |a: (), b: ()| {
|
||||
Err(a)?; //~ ERROR type annotations needed for the closure
|
||||
Ok(b)
|
||||
};
|
||||
}
|
||||
13
src/test/ui/inference/cannot-infer-closure.stderr
Normal file
13
src/test/ui/inference/cannot-infer-closure.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error[E0282]: type annotations needed for the closure `fn((), ()) -> std::result::Result<(), _>`
|
||||
--> $DIR/cannot-infer-closure.rs:3:9
|
||||
|
|
||||
LL | Err(a)?;
|
||||
| ^^^^^^^ cannot infer type
|
||||
help: give this closure an explicit return type without `_` placeholders
|
||||
|
|
||||
LL | let x = |a: (), b: ()| -> std::result::Result<(), _> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
|
@ -2,10 +2,7 @@ error[E0282]: type annotations needed
|
|||
--> $DIR/issue-18159.rs:2:9
|
||||
|
|
||||
LL | let x;
|
||||
| ^
|
||||
| |
|
||||
| cannot infer type
|
||||
| consider giving `x` a type
|
||||
| ^ consider giving `x` a type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@ error[E0282]: type annotations needed
|
|||
--> $DIR/match-unresolved-one-arm.rs:4:9
|
||||
|
|
||||
LL | let x = match () {
|
||||
| ^
|
||||
| |
|
||||
| cannot infer type
|
||||
| consider giving `x` a type
|
||||
| ^ consider giving `x` a type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@ fn main() {
|
|||
//~^ ERROR found a documentation comment that doesn't document anything
|
||||
//~| HELP maybe a comment was intended
|
||||
;
|
||||
//~^ WARNING unnecessary trailing semicolon
|
||||
//~| HELP remove this semicolon
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,14 @@ LL | /// hi
|
|||
|
|
||||
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
|
||||
|
||||
warning: unnecessary trailing semicolon
|
||||
--> $DIR/doc-before-semi.rs:5:5
|
||||
|
|
||||
LL | ;
|
||||
| ^ help: remove this semicolon
|
||||
|
|
||||
= note: `#[warn(redundant_semicolon)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0585`.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ extern crate test_macros;
|
|||
|
||||
#[recollect_attr]
|
||||
fn a() {
|
||||
let x: usize = "hello";;;;; //~ ERROR mismatched types
|
||||
let x: usize = "hello"; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
#[recollect_attr]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ error[E0308]: mismatched types
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/span-preservation.rs:12:20
|
||||
|
|
||||
LL | let x: usize = "hello";;;;;
|
||||
LL | let x: usize = "hello";
|
||||
| ^^^^^^^ expected usize, found reference
|
||||
|
|
||||
= note: expected type `usize`
|
||||
|
|
|
|||
8
src/test/ui/suggestions/suggest-box.fixed
Normal file
8
src/test/ui/suggestions/suggest-box.fixed
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
let _x: Box<dyn Fn() -> Result<(), ()>> = Box::new(|| { //~ ERROR mismatched types
|
||||
Err(())?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
8
src/test/ui/suggestions/suggest-box.rs
Normal file
8
src/test/ui/suggestions/suggest-box.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
let _x: Box<dyn Fn() -> Result<(), ()>> = || { //~ ERROR mismatched types
|
||||
Err(())?;
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
24
src/test/ui/suggestions/suggest-box.stderr
Normal file
24
src/test/ui/suggestions/suggest-box.stderr
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-box.rs:4:47
|
||||
|
|
||||
LL | let _x: Box<dyn Fn() -> Result<(), ()>> = || {
|
||||
| _______________________________________________^
|
||||
LL | | Err(())?;
|
||||
LL | | Ok(())
|
||||
LL | | };
|
||||
| |_____^ expected struct `std::boxed::Box`, found closure
|
||||
|
|
||||
= note: expected type `std::boxed::Box<dyn std::ops::Fn() -> std::result::Result<(), ()>>`
|
||||
found type `[closure@$DIR/suggest-box.rs:4:47: 7:6]`
|
||||
= note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
|
||||
help: store this in the heap by calling `Box::new`
|
||||
|
|
||||
LL | let _x: Box<dyn Fn() -> Result<(), ()>> = Box::new(|| {
|
||||
LL | Err(())?;
|
||||
LL | Ok(())
|
||||
LL | });
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
3
src/test/ui/suggestions/suggest-closure-return-type-1.rs
Normal file
3
src/test/ui/suggestions/suggest-closure-return-type-1.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
let _v = || -> _ { [] }; //~ ERROR type annotations needed for the closure
|
||||
}
|
||||
13
src/test/ui/suggestions/suggest-closure-return-type-1.stderr
Normal file
13
src/test/ui/suggestions/suggest-closure-return-type-1.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
|
||||
--> $DIR/suggest-closure-return-type-1.rs:2:24
|
||||
|
|
||||
LL | let _v = || -> _ { [] };
|
||||
| ^^ cannot infer type
|
||||
help: give this closure an explicit return type without `_` placeholders
|
||||
|
|
||||
LL | let _v = || -> [_; 0] { [] };
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
3
src/test/ui/suggestions/suggest-closure-return-type-2.rs
Normal file
3
src/test/ui/suggestions/suggest-closure-return-type-2.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
let _v = || { [] }; //~ ERROR type annotations needed for the closure
|
||||
}
|
||||
13
src/test/ui/suggestions/suggest-closure-return-type-2.stderr
Normal file
13
src/test/ui/suggestions/suggest-closure-return-type-2.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
|
||||
--> $DIR/suggest-closure-return-type-2.rs:2:19
|
||||
|
|
||||
LL | let _v = || { [] };
|
||||
| ^^ cannot infer type
|
||||
help: give this closure an explicit return type without `_` placeholders
|
||||
|
|
||||
LL | let _v = || -> [_; 0] { [] };
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue