From 0663f253757ab0d360f540e9d7bc7882db1dc8bd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 3 Feb 2020 20:12:42 +0000 Subject: [PATCH 01/25] Always qualify literals by type --- .../transform/check_consts/qualifs.rs | 25 ++++++------------- .../min-global-align/min_global_align.rs | 10 +++++--- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index e509e8267cc1a..215496e4d03cb 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -94,32 +94,23 @@ pub trait Qualif { } Operand::Constant(ref constant) => { - if constant.check_static_ptr(cx.tcx).is_some() { - // `mir_const_qualif` does return the qualifs in the final value of a `static`, - // so we could use value-based qualification here, but we shouldn't do this - // without a good reason. - // - // Note: this uses `constant.literal.ty` which is a reference or pointer to the - // type of the actual `static` item. - Self::in_any_value_of_ty(cx, constant.literal.ty) - } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val - { + // Check the qualifs of the value of `const` items. + if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val { assert!(promoted.is_none()); // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(def_id).is_some() { - Self::in_any_value_of_ty(cx, constant.literal.ty) - } else { + if cx.tcx.trait_of_item(def_id).is_none() { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def_id); - let qualif = Self::in_qualifs(&qualifs); + if !Self::in_qualifs(&qualifs) { + return false; + } // Just in case the type is more specific than // the definition, e.g., impl associated const // with type parameters, take it into account. - qualif && Self::in_any_value_of_ty(cx, constant.literal.ty) } - } else { - false } + // Otherwise use the qualifs of the type. + Self::in_any_value_of_ty(cx, constant.literal.ty) } } } diff --git a/src/test/run-make-fulldeps/min-global-align/min_global_align.rs b/src/test/run-make-fulldeps/min-global-align/min_global_align.rs index ce86d202c62d3..d9851a2f79422 100644 --- a/src/test/run-make-fulldeps/min-global-align/min_global_align.rs +++ b/src/test/run-make-fulldeps/min-global-align/min_global_align.rs @@ -1,5 +1,5 @@ #![feature(no_core, lang_items)] -#![crate_type="rlib"] +#![crate_type = "rlib"] #![no_core] pub static STATIC_BOOL: bool = true; @@ -9,7 +9,6 @@ pub static mut STATIC_MUT_BOOL: bool = true; const CONST_BOOL: bool = true; pub static CONST_BOOL_REF: &'static bool = &CONST_BOOL; - #[lang = "sized"] trait Sized {} @@ -19,10 +18,13 @@ trait Copy {} #[lang = "freeze"] trait Freeze {} +// No `UnsafeCell`, so everything is `Freeze`. +impl Freeze for T {} + #[lang = "sync"] trait Sync {} impl Sync for bool {} impl Sync for &'static bool {} -#[lang="drop_in_place"] -pub unsafe fn drop_in_place(_: *mut T) { } +#[lang = "drop_in_place"] +pub unsafe fn drop_in_place(_: *mut T) {} From f2980e71d936be7a39b9a472664363d93f2c7fd8 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 15 Feb 2020 14:21:50 +0000 Subject: [PATCH 02/25] Add fast path for is_freeze --- src/librustc/ty/util.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index db7b8d8cfd9ed..f27b66314f9e6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -697,7 +697,7 @@ impl<'tcx> ty::TyS<'tcx> { /// strange rules like `>::Bar: Sized` that /// actually carry lifetime requirements. pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - tcx_at.is_sized_raw(param_env.and(self)) + self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self)) } /// Checks whether values of this type `T` implement the `Freeze` @@ -713,7 +713,43 @@ impl<'tcx> ty::TyS<'tcx> { param_env: ty::ParamEnv<'tcx>, span: Span, ) -> bool { - tcx.at(span).is_freeze_raw(param_env.and(self)) + self.is_trivially_freeze() || tcx.at(span).is_freeze_raw(param_env.and(self)) + } + + /// Fast path helper for testing if a type is `Freeze`. + /// + /// Returning true means the type is known to be `Freeze`. Returning + /// `false` means nothing -- could be `Freeze`, might not be. + fn is_trivially_freeze(&self) -> bool { + match self.kind { + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Never + | ty::Ref(..) + | ty::RawPtr(_) + | ty::FnDef(..) + | ty::Error + | ty::FnPtr(_) => true, + ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze), + ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), + ty::Adt(..) + | ty::Bound(..) + | ty::Closure(..) + | ty::Dynamic(..) + | ty::Foreign(_) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::Infer(_) + | ty::Opaque(..) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Projection(_) + | ty::UnnormalizedProjection(_) => false, + } } /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely From 2fd15442f2f1c798718242eaa9817531a53c2134 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 13 Feb 2020 18:03:38 +0100 Subject: [PATCH 03/25] ast: move Generics into AssocItemKinds --- src/librustc_ast_lowering/item.rs | 45 ++--- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_ast_passes/ast_validation.rs | 6 +- src/librustc_ast_passes/feature_gate.rs | 6 +- src/librustc_ast_pretty/pprust.rs | 8 +- .../deriving/generic/mod.rs | 5 +- src/librustc_expand/placeholders.rs | 3 - src/librustc_interface/util.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_parse/parser/item.rs | 16 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/def_collector.rs | 6 +- src/librustc_resolve/late.rs | 180 +++++++++--------- src/librustc_save_analysis/dump_visitor.rs | 14 +- src/libsyntax/ast.rs | 5 +- src/libsyntax/mut_visit.rs | 9 +- src/libsyntax/visit.rs | 7 +- 17 files changed, 155 insertions(+), 163 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 426659fd92452..073f0c6bc4775 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -760,31 +760,25 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match i.kind { AssocItemKind::Const(ref ty, ref default) => { - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - ( - generics, - hir::TraitItemKind::Const( - ty, - default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))), - ), - ) + let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); + (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body)) } - AssocItemKind::Fn(ref sig, None) => { + AssocItemKind::Fn(ref sig, ref generics, None) => { let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = - self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None); + self.lower_method_sig(generics, sig, trait_item_def_id, false, None); (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) } - AssocItemKind::Fn(ref sig, Some(ref body)) => { + AssocItemKind::Fn(ref sig, ref generics, Some(ref body)) => { let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body)); let (generics, sig) = - self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None); + self.lower_method_sig(generics, sig, trait_item_def_id, false, None); (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) } - AssocItemKind::TyAlias(ref bounds, ref default) => { + AssocItemKind::TyAlias(ref generics, ref bounds, ref default) => { let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed())); - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); + let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); let kind = hir::TraitItemKind::Type( self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), ty, @@ -806,10 +800,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { - let (kind, has_default) = match i.kind { - AssocItemKind::Const(_, ref default) => (hir::AssocItemKind::Const, default.is_some()), - AssocItemKind::TyAlias(_, ref default) => (hir::AssocItemKind::Type, default.is_some()), - AssocItemKind::Fn(ref sig, ref default) => { + let (kind, has_default) = match &i.kind { + AssocItemKind::Const(_, default) => (hir::AssocItemKind::Const, default.is_some()), + AssocItemKind::TyAlias(_, _, default) => (hir::AssocItemKind::Type, default.is_some()), + AssocItemKind::Fn(sig, _, default) => { (hir::AssocItemKind::Method { has_self: sig.decl.has_self() }, default.is_some()) } AssocItemKind::Macro(..) => unimplemented!(), @@ -833,21 +827,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match i.kind { AssocItemKind::Const(ref ty, ref expr) => { - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); ( - generics, + hir::Generics::empty(), hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), ) } - AssocItemKind::Fn(ref sig, ref body) => { + AssocItemKind::Fn(ref sig, ref generics, ref body) => { self.current_item = Some(i.span); let asyncness = sig.header.asyncness; let body_id = self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref()); let impl_trait_return_allow = !self.is_in_trait_impl; let (generics, sig) = self.lower_method_sig( - &i.generics, + generics, sig, impl_item_def_id, impl_trait_return_allow, @@ -856,8 +849,8 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, hir::ImplItemKind::Method(sig, body_id)) } - AssocItemKind::TyAlias(_, ref ty) => { - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); + AssocItemKind::TyAlias(ref generics, _, ref ty) => { + let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); let kind = match ty { None => { let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err)); @@ -902,13 +895,13 @@ impl<'hir> LoweringContext<'_, 'hir> { defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::TyAlias(_, ty) => { + AssocItemKind::TyAlias(_, _, ty) => { match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) { None => hir::AssocItemKind::Type, Some(_) => hir::AssocItemKind::OpaqueTy, } } - AssocItemKind::Fn(sig, _) => { + AssocItemKind::Fn(sig, _, _) => { hir::AssocItemKind::Method { has_self: sig.decl.has_self() } } AssocItemKind::Macro(..) => unimplemented!(), diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 99de4b88fd3c4..56d789b7a6a8b 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -490,7 +490,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lctx.allocate_hir_id_counter(item.id); let owner = match (&item.kind, ctxt) { // Ignore patterns in trait methods without bodies. - (AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None, + (AssocItemKind::Fn(_, _, None), AssocCtxt::Trait) => None, _ => Some(item.id), }; self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt)); diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 2f0495b8b5a48..206cdefecc990 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -1154,10 +1154,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { AssocItemKind::Const(_, body) => { self.check_impl_item_provided(item.span, body, "constant", " = ;"); } - AssocItemKind::Fn(_, body) => { + AssocItemKind::Fn(_, _, body) => { self.check_impl_item_provided(item.span, body, "function", " { }"); } - AssocItemKind::TyAlias(bounds, body) => { + AssocItemKind::TyAlias(_, bounds, body) => { self.check_impl_item_provided(item.span, body, "type", " = ;"); self.check_impl_assoc_type_no_bounds(bounds); } @@ -1167,7 +1167,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if ctxt == AssocCtxt::Trait || self.in_trait_impl { self.invalid_visibility(&item.vis, None); - if let AssocItemKind::Fn(sig, _) = &item.kind { + if let AssocItemKind::Fn(sig, _, _) = &item.kind { self.check_trait_fn_not_const(sig.header.constness); self.check_trait_fn_not_async(item.span, sig.header.asyncness); } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 0b21de4d78b41..32c91f4a63486 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -548,12 +548,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } match i.kind { - ast::AssocItemKind::Fn(ref sig, _) => { + ast::AssocItemKind::Fn(ref sig, _, _) => { if let (ast::Const::Yes(_), AssocCtxt::Trait) = (sig.header.constness, ctxt) { gate_feature_post!(&self, const_fn, i.span, "const fn is unstable"); } } - ast::AssocItemKind::TyAlias(_, ref ty) => { + ast::AssocItemKind::TyAlias(ref generics, _, ref ty) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, @@ -565,7 +565,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(&i.generics, i.span); + self.check_gat(generics, i.span); } _ => {} } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 75938470b6fca..0fcda7f763eff 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1473,12 +1473,12 @@ impl<'a> State<'a> { ast::AssocItemKind::Const(ty, expr) => { self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis); } - ast::AssocItemKind::Fn(sig, body) => { + ast::AssocItemKind::Fn(sig, generics, body) => { let body = body.as_deref(); - self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs); + self.print_fn_full(sig, item.ident, generics, &item.vis, body, &item.attrs); } - ast::AssocItemKind::TyAlias(bounds, ty) => { - self.print_associated_type(item.ident, &item.generics, bounds, ty.as_deref()); + ast::AssocItemKind::TyAlias(generics, bounds, ty) => { + self.print_associated_type(item.ident, generics, bounds, ty.as_deref()); } ast::AssocItemKind::Macro(mac) => { self.print_mac(mac); diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index 5cf233e222e7c..2e4cbd708a9f6 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -544,8 +544,8 @@ impl<'a> TraitDef<'a> { vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, attrs: Vec::new(), - generics: Generics::default(), kind: ast::AssocItemKind::TyAlias( + Generics::default(), Vec::new(), Some(type_def.to_ty(cx, self.span, type_ident, generics)), ), @@ -973,12 +973,11 @@ impl<'a> MethodDef<'a> { P(ast::AssocItem { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), - generics: fn_generics, span: trait_.span, vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, ident: method_ident, - kind: ast::AssocItemKind::Fn(sig, Some(body_block)), + kind: ast::AssocItemKind::Fn(sig, fn_generics, Some(body_block)), tokens: None, }) } diff --git a/src/librustc_expand/placeholders.rs b/src/librustc_expand/placeholders.rs index 6bcb8f45f001e..c96b394c7b5e2 100644 --- a/src/librustc_expand/placeholders.rs +++ b/src/librustc_expand/placeholders.rs @@ -25,7 +25,6 @@ pub fn placeholder( let ident = ast::Ident::invalid(); let attrs = Vec::new(); - let generics = ast::Generics::default(); let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited)); let span = DUMMY_SP; let expr_placeholder = || { @@ -57,7 +56,6 @@ pub fn placeholder( ident, vis, attrs, - generics, kind: ast::AssocItemKind::Macro(mac_placeholder()), defaultness: ast::Defaultness::Final, tokens: None, @@ -68,7 +66,6 @@ pub fn placeholder( ident, vis, attrs, - generics, kind: ast::AssocItemKind::Macro(mac_placeholder()), defaultness: ast::Defaultness::Final, tokens: None, diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 659323d1c2555..df50fc5d3ed24 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -686,7 +686,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { fn flat_map_trait_item(&mut self, i: P) -> SmallVec<[P; 1]> { let is_const = match i.kind { ast::AssocItemKind::Const(..) => true, - ast::AssocItemKind::Fn(ref sig, _) => Self::is_sig_const(sig), + ast::AssocItemKind::Fn(ref sig, _, _) => Self::is_sig_const(sig), _ => false, }; self.run(is_const, |s| noop_flat_map_assoc_item(i, s)) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 93fca43d67c1f..207defa96a3e6 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -640,7 +640,7 @@ declare_lint_pass!( impl EarlyLintPass for AnonymousParameters { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { match it.kind { - ast::AssocItemKind::Fn(ref sig, _) => { + ast::AssocItemKind::Fn(ref sig, _, _) => { for arg in sig.decl.inputs.iter() { match arg.pat.kind { ast::PatKind::Ident(_, ident, None) => { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 500aaaf43b92a..96b3cf797208e 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -665,11 +665,11 @@ impl<'a> Parser<'a> { let vis = self.parse_visibility(FollowedByType::No)?; let defaultness = self.parse_defaultness(); - let (ident, kind, generics) = if self.eat_keyword(kw::Type) { + let (ident, kind) = if self.eat_keyword(kw::Type) { self.parse_assoc_ty()? } else if self.check_fn_front_matter() { let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; - (ident, AssocItemKind::Fn(sig, body), generics) + (ident, AssocItemKind::Fn(sig, generics, body)) } else if self.check_keyword(kw::Const) { self.parse_assoc_const()? } else if self.isnt_macro_invocation() { @@ -677,7 +677,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { let mac = self.parse_item_macro(&vis)?; *at_end = true; - (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default()) + (Ident::invalid(), AssocItemKind::Macro(mac)) } else { self.recover_attrs_no_item(&attrs)?; self.unexpected()? @@ -685,26 +685,26 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_span); let id = DUMMY_NODE_ID; - Ok(AssocItem { id, span, ident, attrs, vis, defaultness, generics, kind, tokens: None }) + Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None }) } /// This parses the grammar: /// /// AssocConst = "const" Ident ":" Ty "=" Expr ";" - fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> { + fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind)> { self.expect_keyword(kw::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; self.expect_semi()?; - Ok((ident, AssocItemKind::Const(ty, expr), Generics::default())) + Ok((ident, AssocItemKind::Const(ty, expr))) } /// Parses the following grammar: /// /// AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] - fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> { + fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind)> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -716,7 +716,7 @@ impl<'a> Parser<'a> { let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; self.expect_semi()?; - Ok((ident, AssocItemKind::TyAlias(bounds, default), generics)) + Ok((ident, AssocItemKind::TyAlias(generics, bounds, default))) } /// Parses a `UseTree`. diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d6ea737385cdd..280a7a8fdba4f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1252,7 +1252,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { let item_def_id = self.r.definitions.local_def_id(item.id); let (res, ns) = match item.kind { AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS), - AssocItemKind::Fn(ref sig, _) => { + AssocItemKind::Fn(ref sig, _, _) => { if sig.decl.has_self() { self.r.has_self.insert(item_def_id); } diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index fe80dec513cfe..256b5ff4b9a89 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -215,13 +215,15 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { let def_data = match &i.kind { - AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.is_async() => { + AssocItemKind::Fn(FnSig { header, decl }, generics, body) + if header.asyncness.is_async() => + { return self.visit_async_fn( i.id, i.ident.name, i.span, header, - &i.generics, + generics, decl, body.as_deref(), ); diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index bcf558d1563ed..0e4e9c152867c 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -826,41 +826,33 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds); - for trait_item in trait_items { + let walk_assoc_item = |this: &mut Self, generics, item| { + this.with_generic_param_rib(generics, AssocItemRibKind, |this| { + visit::walk_assoc_item(this, item, AssocCtxt::Trait) + }); + }; + + for item in trait_items { this.with_trait_items(trait_items, |this| { - this.with_generic_param_rib( - &trait_item.generics, - AssocItemRibKind, - |this| { - match trait_item.kind { - AssocItemKind::Const(ref ty, ref default) => { - this.visit_ty(ty); - - // Only impose the restrictions of - // ConstRibKind for an actual constant - // expression in a provided default. - if let Some(ref expr) = *default { - this.with_constant_rib(|this| { - this.visit_expr(expr); - }); - } - } - AssocItemKind::Fn(_, _) => visit::walk_assoc_item( - this, - trait_item, - AssocCtxt::Trait, - ), - AssocItemKind::TyAlias(..) => visit::walk_assoc_item( - this, - trait_item, - AssocCtxt::Trait, - ), - AssocItemKind::Macro(_) => { - panic!("unexpanded macro in resolve!") - } - }; - }, - ); + match &item.kind { + AssocItemKind::Const(ty, default) => { + this.visit_ty(ty); + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = default { + this.with_constant_rib(|this| this.visit_expr(expr)); + } + } + AssocItemKind::Fn(_, generics, _) => { + walk_assoc_item(this, generics, item); + } + AssocItemKind::TyAlias(generics, _, _) => { + walk_assoc_item(this, generics, item); + } + AssocItemKind::Macro(_) => { + panic!("unexpanded macro in resolve!") + } + }; }); } }); @@ -1021,7 +1013,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { trait_items .iter() .filter_map(|item| match &item.kind { - AssocItemKind::TyAlias(bounds, _) if bounds.len() == 0 => Some(item.ident), + AssocItemKind::TyAlias(_, bounds, _) if bounds.len() == 0 => Some(item.ident), _ => None, }) .collect(), @@ -1113,66 +1105,74 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_current_self_type(self_type, |this| { this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); - for impl_item in impl_items { - // We also need a new scope for the impl item type parameters. - this.with_generic_param_rib(&impl_item.generics, - AssocItemRibKind, - |this| { - use crate::ResolutionError::*; - match impl_item.kind { - AssocItemKind::Const(..) => { - debug!( - "resolve_implementation AssocItemKind::Const", - ); - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - impl_item.ident, - ValueNS, - impl_item.span, - |n, s| ConstNotMemberOfTrait(n, s), - ); - - this.with_constant_rib(|this| { + for item in impl_items { + use crate::ResolutionError::*; + match &item.kind { + AssocItemKind::Const(..) => { + debug!("resolve_implementation AssocItemKind::Const",); + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.ident, + ValueNS, + item.span, + |n, s| ConstNotMemberOfTrait(n, s), + ); + + this.with_constant_rib(|this| { + visit::walk_assoc_item(this, item, AssocCtxt::Impl) + }); + } + AssocItemKind::Fn(_, generics, _) => { + // We also need a new scope for the impl item type parameters. + this.with_generic_param_rib( + generics, + AssocItemRibKind, + |this| { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item( + item.ident, + ValueNS, + item.span, + |n, s| MethodNotMemberOfTrait(n, s), + ); + visit::walk_assoc_item( this, - impl_item, + item, AssocCtxt::Impl, ) - }); - } - AssocItemKind::Fn(..) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident, - ValueNS, - impl_item.span, - |n, s| MethodNotMemberOfTrait(n, s)); - - visit::walk_assoc_item( - this, - impl_item, - AssocCtxt::Impl, - ) - } - AssocItemKind::TyAlias(_, _) => { - // If this is a trait impl, ensure the type - // exists in trait - this.check_trait_item(impl_item.ident, - TypeNS, - impl_item.span, - |n, s| TypeNotMemberOfTrait(n, s)); - - visit::walk_assoc_item( - this, - impl_item, - AssocCtxt::Impl, - ) - } - AssocItemKind::Macro(_) => - panic!("unexpanded macro in resolve!"), + }, + ); + } + AssocItemKind::TyAlias(generics, _, _) => { + // We also need a new scope for the impl item type parameters. + this.with_generic_param_rib( + generics, + AssocItemRibKind, + |this| { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item( + item.ident, + TypeNS, + item.span, + |n, s| TypeNotMemberOfTrait(n, s), + ); + + visit::walk_assoc_item( + this, + item, + AssocCtxt::Impl, + ) + }, + ); + } + AssocItemKind::Macro(_) => { + panic!("unexpanded macro in resolve!") } - }); + } } }); }); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 01e3e3f368529..561a4a83d2803 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1015,18 +1015,18 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { &trait_item.attrs, ); } - ast::AssocItemKind::Fn(ref sig, ref body) => { + ast::AssocItemKind::Fn(ref sig, ref generics, ref body) => { self.process_method( sig, body.as_ref().map(|x| &**x), trait_item.id, trait_item.ident, - &trait_item.generics, + generics, respan(vis_span, ast::VisibilityKind::Public), trait_item.span, ); } - ast::AssocItemKind::TyAlias(ref bounds, ref default_ty) => { + ast::AssocItemKind::TyAlias(_, ref bounds, ref default_ty) => { // FIXME do something with _bounds (for type refs) let name = trait_item.ident.name.to_string(); let qualname = format!( @@ -1085,19 +1085,19 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { &impl_item.attrs, ); } - ast::AssocItemKind::Fn(ref sig, ref body) => { + ast::AssocItemKind::Fn(ref sig, ref generics, ref body) => { self.process_method( sig, body.as_deref(), impl_item.id, impl_item.ident, - &impl_item.generics, + generics, impl_item.vis.clone(), impl_item.span, ); } - ast::AssocItemKind::TyAlias(_, None) => {} - ast::AssocItemKind::TyAlias(_, Some(ref ty)) => { + ast::AssocItemKind::TyAlias(_, _, None) => {} + ast::AssocItemKind::TyAlias(_, _, Some(ref ty)) => { // FIXME: uses of the assoc type should ideally point to this // 'def' and the name here should be a ref to the def in the // trait. diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 72430fa9c17e4..7f6e405fec69c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1616,7 +1616,6 @@ pub struct AssocItem { pub ident: Ident, pub defaultness: Defaultness, - pub generics: Generics, pub kind: AssocItemKind, /// See `Item::tokens` for what this is. pub tokens: Option, @@ -1636,10 +1635,10 @@ pub enum AssocItemKind { Const(P, Option>), /// An associated function. - Fn(FnSig, Option>), + Fn(FnSig, Generics, Option>), /// An associated type. - TyAlias(GenericBounds, Option>), + TyAlias(Generics, GenericBounds, Option>), /// A macro expanding to an associated item. Macro(Mac), diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index e0180d451936f..f3857b3a41437 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -951,23 +951,24 @@ pub fn noop_flat_map_assoc_item( mut item: P, visitor: &mut T, ) -> SmallVec<[P; 1]> { - let AssocItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } = + let AssocItem { id, ident, vis, defaultness: _, attrs, kind, span, tokens: _ } = item.deref_mut(); visitor.visit_id(id); visitor.visit_ident(ident); visitor.visit_vis(vis); visit_attrs(attrs, visitor); - visitor.visit_generics(generics); match kind { AssocItemKind::Const(ty, expr) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } - AssocItemKind::Fn(sig, body) => { + AssocItemKind::Fn(sig, generics, body) => { + visitor.visit_generics(generics); visit_fn_sig(sig, visitor); visit_opt(body, |body| visitor.visit_block(body)); } - AssocItemKind::TyAlias(bounds, ty) => { + AssocItemKind::TyAlias(generics, bounds, ty) => { + visitor.visit_generics(generics); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 73e731397c329..edcfd7f4e7870 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -625,17 +625,18 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, visitor.visit_vis(&item.vis); visitor.visit_ident(item.ident); walk_list!(visitor, visit_attribute, &item.attrs); - visitor.visit_generics(&item.generics); match item.kind { AssocItemKind::Const(ref ty, ref expr) => { visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } - AssocItemKind::Fn(ref sig, ref body) => { + AssocItemKind::Fn(ref sig, ref generics, ref body) => { + visitor.visit_generics(generics); let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); visitor.visit_fn(kind, item.span, item.id); } - AssocItemKind::TyAlias(ref bounds, ref ty) => { + AssocItemKind::TyAlias(ref generics, ref bounds, ref ty) => { + visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, ty); } From f06df1629e1144be6a217754303a6585699e0728 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 13 Feb 2020 18:05:40 +0100 Subject: [PATCH 04/25] ast: colocate AssocItem with ForeignItem --- src/libsyntax/ast.rs | 78 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7f6e405fec69c..2eab688fd9d46 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1605,45 +1605,6 @@ pub struct FnSig { pub decl: P, } -/// Represents associated items. -/// These include items in `impl` and `trait` definitions. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct AssocItem { - pub attrs: Vec, - pub id: NodeId, - pub span: Span, - pub vis: Visibility, - pub ident: Ident, - - pub defaultness: Defaultness, - pub kind: AssocItemKind, - /// See `Item::tokens` for what this is. - pub tokens: Option, -} - -/// Represents various kinds of content within an `impl`. -/// -/// The term "provided" in the variants below refers to the item having a default -/// definition / body. Meanwhile, a "required" item lacks a definition / body. -/// In an implementation, all items must be provided. -/// The `Option`s below denote the bodies, where `Some(_)` -/// means "provided" and conversely `None` means "required". -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum AssocItemKind { - /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. - /// If `def` is parsed, then the associated constant is provided, and otherwise required. - Const(P, Option>), - - /// An associated function. - Fn(FnSig, Generics, Option>), - - /// An associated type. - TyAlias(Generics, GenericBounds, Option>), - - /// A macro expanding to an associated item. - Macro(Mac), -} - #[derive( Clone, Copy, @@ -2664,3 +2625,42 @@ impl ForeignItemKind { } } } + +/// Represents associated items. +/// These include items in `impl` and `trait` definitions. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct AssocItem { + pub attrs: Vec, + pub id: NodeId, + pub span: Span, + pub vis: Visibility, + pub ident: Ident, + + pub defaultness: Defaultness, + pub kind: AssocItemKind, + /// See `Item::tokens` for what this is. + pub tokens: Option, +} + +/// Represents various kinds of content within an `impl`. +/// +/// The term "provided" in the variants below refers to the item having a default +/// definition / body. Meanwhile, a "required" item lacks a definition / body. +/// In an implementation, all items must be provided. +/// The `Option`s below denote the bodies, where `Some(_)` +/// means "provided" and conversely `None` means "required". +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AssocItemKind { + /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. + /// If `def` is parsed, then the associated constant is provided, and otherwise required. + Const(P, Option>), + + /// An associated function. + Fn(FnSig, Generics, Option>), + + /// An associated type. + TyAlias(Generics, GenericBounds, Option>), + + /// A macro expanding to an associated item. + Macro(Mac), +} From e2ae717265c4597d605cf5981a6e557516ccb0c8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 13 Feb 2020 18:15:58 +0100 Subject: [PATCH 05/25] ast: tweak comments of Foreign/AssocItemKind --- src/libsyntax/ast.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2eab688fd9d46..af0195ffc6168 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2605,13 +2605,13 @@ pub type ForeignItem = Item; /// An item within an `extern` block. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ForeignItemKind { - /// A foreign function. - Fn(FnSig, Generics, Option>), - /// A foreign static item (`static ext: u8`). + /// A static item (`static FOO: u8`). Static(P, Mutability), - /// A foreign type. + /// A function. + Fn(FnSig, Generics, Option>), + /// A type. Ty, - /// A macro invocation. + /// A macro expanding to an item. Macro(Mac), } @@ -2651,16 +2651,13 @@ pub struct AssocItem { /// means "provided" and conversely `None` means "required". #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum AssocItemKind { - /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. - /// If `def` is parsed, then the associated constant is provided, and otherwise required. + /// A constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. + /// If `def` is parsed, then the constant is provided, and otherwise required. Const(P, Option>), - - /// An associated function. + /// A function. Fn(FnSig, Generics, Option>), - - /// An associated type. + /// A type. TyAlias(Generics, GenericBounds, Option>), - - /// A macro expanding to an associated item. + /// A macro expanding to an item. Macro(Mac), } From 95dc9b9a73353a786e3c934c5074fb793ff7a735 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 14 Feb 2020 12:55:42 +0100 Subject: [PATCH 06/25] ast: normalize `ForeignItemKind::Ty` & `AssocItemKind::TyAlias`. --- src/librustc_ast_lowering/item.rs | 2 +- src/librustc_ast_passes/ast_validation.rs | 63 ++++++++++++++++-- src/librustc_ast_passes/feature_gate.rs | 2 +- src/librustc_ast_pretty/pprust.rs | 18 ++--- src/librustc_parse/parser/item.rs | 12 ++-- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/late.rs | 5 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_save_analysis/sig.rs | 2 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/mut_visit.rs | 6 +- src/libsyntax/visit.rs | 6 +- .../ui/parser/foreign-ty-semantic-fail.rs | 18 +++++ .../ui/parser/foreign-ty-semantic-fail.stderr | 65 +++++++++++++++++++ .../ui/parser/foreign-ty-syntactic-pass.rs | 12 ++++ .../impl-item-type-no-body-semantic-fail.rs | 4 +- ...mpl-item-type-no-body-semantic-fail.stderr | 4 +- 18 files changed, 192 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/parser/foreign-ty-semantic-fail.rs create mode 100644 src/test/ui/parser/foreign-ty-semantic-fail.stderr create mode 100644 src/test/ui/parser/foreign-ty-syntactic-pass.rs diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 073f0c6bc4775..6c4026408ed4a 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -682,7 +682,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty(t, ImplTraitContext::disallowed()); hir::ForeignItemKind::Static(ty, m) } - ForeignItemKind::Ty => hir::ForeignItemKind::Type, + ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"), }, vis: self.lower_visibility(&i.vis, None), diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 206cdefecc990..c539f98aecf44 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -22,6 +22,9 @@ use syntax::expand::is_proc_macro_attr; use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::walk_list; +const MORE_EXTERN: &str = + "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; + /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { Yes, @@ -423,14 +426,59 @@ impl<'a> AstValidator<'a> { } } - fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) { + fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) { let span = match bounds { [] => return, [b0] => b0.span(), [b0, .., bl] => b0.span().to(bl.span()), }; self.err_handler() - .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect") + .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx)) + .emit(); + } + + fn check_foreign_ty_genericless(&self, generics: &Generics) { + let cannot_have = |span, descr, remove_descr| { + self.err_handler() + .struct_span_err( + span, + &format!("`type`s inside `extern` blocks cannot have {}", descr), + ) + .span_suggestion( + span, + &format!("remove the {}", remove_descr), + String::new(), + Applicability::MaybeIncorrect, + ) + .span_label(self.current_extern_span(), "`extern` block begins here") + .note(MORE_EXTERN) + .emit(); + }; + + if !generics.params.is_empty() { + cannot_have(generics.span, "generic parameters", "generic parameters"); + } + + if !generics.where_clause.predicates.is_empty() { + cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause"); + } + } + + fn check_foreign_ty_bodyless(&self, ident: Ident, body: Option<&Ty>) { + let body = match body { + None => return, + Some(body) => body, + }; + self.err_handler() + .struct_span_err(ident.span, "incorrect `type` inside `extern` block") + .span_label(ident.span, "cannot have a body") + .span_label(body.span, "the invalid body") + .span_label( + self.current_extern_span(), + "`extern` blocks define existing foreign types and types \ + inside of them cannot have a body", + ) + .note(MORE_EXTERN) .emit(); } @@ -458,7 +506,7 @@ impl<'a> AstValidator<'a> { "`extern` blocks define existing foreign functions and functions \ inside of them cannot have a body", ) - .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") + .note(MORE_EXTERN) .emit(); } @@ -912,7 +960,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); } - ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} + ForeignItemKind::TyAlias(generics, bounds, body) => { + self.check_foreign_ty_bodyless(fi.ident, body.as_deref()); + self.check_type_no_bounds(bounds, "`extern` blocks"); + self.check_foreign_ty_genericless(generics); + } + ForeignItemKind::Static(..) | ForeignItemKind::Macro(..) => {} } visit::walk_foreign_item(self, fi) @@ -1159,7 +1212,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } AssocItemKind::TyAlias(_, bounds, body) => { self.check_impl_item_provided(item.span, body, "type", " = ;"); - self.check_impl_assoc_type_no_bounds(bounds); + self.check_type_no_bounds(bounds, "`impl`s"); } _ => {} } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 32c91f4a63486..c543f7095b943 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -397,7 +397,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); } ast::ForeignItemKind::Macro(..) => {} diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 0fcda7f763eff..b0e1b5d4f4238 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1019,13 +1019,13 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); - match item.kind { - ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => { + match &item.kind { + ast::ForeignItemKind::Fn(sig, gen, body) => { self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } - ast::ForeignItemKind::Static(ref t, m) => { + ast::ForeignItemKind::Static(t, m) => { self.head(visibility_qualified(&item.vis, "static")); - if m == ast::Mutability::Mut { + if *m == ast::Mutability::Mut { self.word_space("mut"); } self.print_ident(item.ident); @@ -1035,14 +1035,10 @@ impl<'a> State<'a> { self.end(); // end the head-ibox self.end(); // end the outer cbox } - ast::ForeignItemKind::Ty => { - self.head(visibility_qualified(&item.vis, "type")); - self.print_ident(item.ident); - self.s.word(";"); - self.end(); // end the head-ibox - self.end(); // end the outer cbox + ast::ForeignItemKind::TyAlias(generics, bounds, ty) => { + self.print_associated_type(item.ident, generics, bounds, ty.as_deref()); } - ast::ForeignItemKind::Macro(ref m) => { + ast::ForeignItemKind::Macro(m) => { self.print_mac(m); if m.args.need_semicolon() { self.s.word(";"); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 96b3cf797208e..4a5b4ff8e04ac 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -876,7 +876,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; - let (ident, kind) = if self.check_keyword(kw::Type) { + let (ident, kind) = if self.eat_keyword(kw::Type) { // FOREIGN TYPE ITEM self.parse_item_foreign_type()? } else if self.check_fn_front_matter() { @@ -925,10 +925,12 @@ impl<'a> Parser<'a> { /// Parses a type from a foreign module. fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { - self.expect_keyword(kw::Type)?; - let ident = self.parse_ident()?; - self.expect_semi()?; - Ok((ident, ForeignItemKind::Ty)) + let (ident, kind) = self.parse_assoc_ty()?; + let kind = match kind { + AssocItemKind::TyAlias(g, b, d) => ForeignItemKind::TyAlias(g, b, d), + _ => unreachable!(), + }; + Ok((ident, kind)) } fn is_static_global(&mut self) -> bool { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 280a7a8fdba4f..f5e64443dda6a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -829,7 +829,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ForeignItemKind::Static(..) => { (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS) } - ForeignItemKind::Ty => { + ForeignItemKind::TyAlias(..) => { (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS) } ForeignItemKind::Macro(_) => unreachable!(), diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 0e4e9c152867c..1a1a9b1076e98 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -437,7 +437,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { match foreign_item.kind { - ForeignItemKind::Fn(_, ref generics, _) => { + ForeignItemKind::Fn(_, ref generics, _) + | ForeignItemKind::TyAlias(ref generics, ..) => { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { visit::walk_foreign_item(this, foreign_item); }); @@ -447,7 +448,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_foreign_item(this, foreign_item); }); } - ForeignItemKind::Ty | ForeignItemKind::Macro(..) => { + ForeignItemKind::Macro(..) => { visit::walk_foreign_item(self, foreign_item); } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 561a4a83d2803..5668be40eefe0 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1540,7 +1540,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { self.visit_ty(ty); } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(var_data, DefData, item.span); self.dumper.dump_def(&access, var_data); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 401e172275113..e983802ee11ba 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -173,7 +173,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { })) } // FIXME(plietar): needs a new DefKind in rls-data - ast::ForeignItemKind::Ty => None, + ast::ForeignItemKind::TyAlias(..) => None, ast::ForeignItemKind::Macro(..) => None, } } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index d3c4d6d5723b9..bd7bd9bc6169e 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -773,7 +773,7 @@ impl Sig for ast::ForeignItem { Ok(extend_sig(ty_sig, text, defs, vec![])) } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { let mut text = "type ".to_owned(); let name = self.ident.to_string(); let defs = vec![SigElement { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index af0195ffc6168..fe353bc994aff 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2610,7 +2610,7 @@ pub enum ForeignItemKind { /// A function. Fn(FnSig, Generics, Option>), /// A type. - Ty, + TyAlias(Generics, GenericBounds, Option>), /// A macro expanding to an item. Macro(Mac), } @@ -2620,7 +2620,7 @@ impl ForeignItemKind { match *self { ForeignItemKind::Fn(..) => "foreign function", ForeignItemKind::Static(..) => "foreign static item", - ForeignItemKind::Ty => "foreign type", + ForeignItemKind::TyAlias(..) => "foreign type", ForeignItemKind::Macro(..) => "macro in foreign module", } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f3857b3a41437..d36b0a28a8cee 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1051,7 +1051,11 @@ pub fn noop_flat_map_foreign_item( visit_opt(body, |body| visitor.visit_block(body)); } ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), - ForeignItemKind::Ty => {} + ForeignItemKind::TyAlias(generics, bounds, ty) => { + visitor.visit_generics(generics); + visit_bounds(bounds, visitor); + visit_opt(ty, |ty| visitor.visit_ty(ty)); + } ForeignItemKind::Macro(mac) => visitor.visit_mac(mac), } visitor.visit_id(id); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index edcfd7f4e7870..ed57fc8abf3b4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -535,7 +535,11 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI visitor.visit_fn(kind, item.span, item.id); } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), - ForeignItemKind::Ty => (), + ForeignItemKind::TyAlias(ref generics, ref bounds, ref ty) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_ty, ty); + } ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.rs b/src/test/ui/parser/foreign-ty-semantic-fail.rs new file mode 100644 index 0000000000000..96b15232b10d0 --- /dev/null +++ b/src/test/ui/parser/foreign-ty-semantic-fail.rs @@ -0,0 +1,18 @@ +#![feature(extern_types)] + +fn main() {} + +extern "C" { + type A: Ord; + //~^ ERROR bounds on `type`s in `extern` blocks have no effect + type B<'a> where 'a: 'static; + //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + type C where T: 'static; + //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + type D = u8; + //~^ ERROR incorrect `type` inside `extern` block + + type E: where; +} diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.stderr b/src/test/ui/parser/foreign-ty-semantic-fail.stderr new file mode 100644 index 0000000000000..588e4966aaeb5 --- /dev/null +++ b/src/test/ui/parser/foreign-ty-semantic-fail.stderr @@ -0,0 +1,65 @@ +error: bounds on `type`s in `extern` blocks have no effect + --> $DIR/foreign-ty-semantic-fail.rs:6:13 + | +LL | type A: Ord; + | ^^^ + +error: `type`s inside `extern` blocks cannot have generic parameters + --> $DIR/foreign-ty-semantic-fail.rs:8:11 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type B<'a> where 'a: 'static; + | ^^^^ help: remove the generic parameters + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have `where` clauses + --> $DIR/foreign-ty-semantic-fail.rs:8:16 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type B<'a> where 'a: 'static; + | ^^^^^^^^^^^^^^^^^ help: remove the `where` clause + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have generic parameters + --> $DIR/foreign-ty-semantic-fail.rs:11:11 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type C where T: 'static; + | ^^^^^^^^ help: remove the generic parameters + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have `where` clauses + --> $DIR/foreign-ty-semantic-fail.rs:11:20 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type C where T: 'static; + | ^^^^^^^^^^^^^^^^ help: remove the `where` clause + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `type` inside `extern` block + --> $DIR/foreign-ty-semantic-fail.rs:14:10 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign types and types inside of them cannot have a body +... +LL | type D = u8; + | ^ -- the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/foreign-ty-syntactic-pass.rs b/src/test/ui/parser/foreign-ty-syntactic-pass.rs new file mode 100644 index 0000000000000..a746de1f14f4d --- /dev/null +++ b/src/test/ui/parser/foreign-ty-syntactic-pass.rs @@ -0,0 +1,12 @@ +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern "C" { + type A: Ord; + type A<'a> where 'a: 'static; + type A where T: 'static; + type A = u8; + type A<'a: 'static, T: Ord + 'static>: Eq + PartialEq where T: 'static + Copy = Vec; +} diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs index 9c321c4bd0d74..fa9c7ababcf9e 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs @@ -11,11 +11,11 @@ impl X { //~| ERROR associated types are not yet supported in inherent impls type Z: Ord; //~^ ERROR associated type in `impl` without body - //~| ERROR bounds on associated `type`s in `impl`s have no effect + //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR associated types are not yet supported in inherent impls type W: Ord where Self: Eq; //~^ ERROR associated type in `impl` without body - //~| ERROR bounds on associated `type`s in `impl`s have no effect + //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR associated types are not yet supported in inherent impls type W where Self: Eq; //~^ ERROR associated type in `impl` without body diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr index 65e1981e3ac78..541d9317c79d0 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -14,7 +14,7 @@ LL | type Z: Ord; | | | help: provide a definition for the type: `= ;` -error: bounds on associated `type`s in `impl`s have no effect +error: bounds on `type`s in `impl`s have no effect --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13 | LL | type Z: Ord; @@ -28,7 +28,7 @@ LL | type W: Ord where Self: Eq; | | | help: provide a definition for the type: `= ;` -error: bounds on associated `type`s in `impl`s have no effect +error: bounds on `type`s in `impl`s have no effect --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13 | LL | type W: Ord where Self: Eq; From f3e9763543e5828fe9eee7f5e78c88193f5b8ba5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 14 Feb 2020 14:21:02 +0100 Subject: [PATCH 07/25] ast: make `= ;` optional in free statics/consts. --- src/librustc_ast_lowering/item.rs | 37 ++--- src/librustc_ast_passes/ast_validation.rs | 8 + src/librustc_ast_pretty/pprust.rs | 14 +- src/librustc_builtin_macros/test.rs | 148 +++++++++--------- src/librustc_expand/build.rs | 4 +- src/librustc_lint/unused.rs | 2 +- src/librustc_parse/parser/item.rs | 19 +-- src/librustc_resolve/late.rs | 6 +- src/librustc_save_analysis/dump_visitor.rs | 8 +- src/librustc_save_analysis/sig.rs | 18 ++- src/libsyntax/ast.rs | 4 +- src/libsyntax/mut_visit.rs | 8 +- src/libsyntax/visit.rs | 2 +- .../item-free-const-no-body-semantic-fail.rs | 7 + ...em-free-const-no-body-semantic-fail.stderr | 24 +++ .../item-free-const-no-body-syntactic-pass.rs | 8 + .../item-free-static-no-body-semantic-fail.rs | 11 ++ ...m-free-static-no-body-semantic-fail.stderr | 46 ++++++ ...item-free-static-no-body-syntactic-pass.rs | 8 + 19 files changed, 250 insertions(+), 132 deletions(-) create mode 100644 src/test/ui/parser/item-free-const-no-body-semantic-fail.rs create mode 100644 src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr create mode 100644 src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs create mode 100644 src/test/ui/parser/item-free-static-no-body-semantic-fail.rs create mode 100644 src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr create mode 100644 src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 6c4026408ed4a..f19481d890d52 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -269,26 +269,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } ItemKind::Static(ref t, m, ref e) => { - let ty = self.lower_ty( - t, - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) - } else { - ImplTraitContext::Disallowed(ImplTraitPosition::Binding) - }, - ); - hir::ItemKind::Static(ty, m, self.lower_const_body(span, Some(e))) + let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + hir::ItemKind::Static(ty, m, body_id) } ItemKind::Const(ref t, ref e) => { - let ty = self.lower_ty( - t, - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) - } else { - ImplTraitContext::Disallowed(ImplTraitPosition::Binding) - }, - ); - hir::ItemKind::Const(ty, self.lower_const_body(span, Some(e))) + let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + hir::ItemKind::Const(ty, body_id) } ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); @@ -457,6 +443,21 @@ impl<'hir> LoweringContext<'_, 'hir> { // not cause an assertion failure inside the `lower_defaultness` function. } + fn lower_const_item( + &mut self, + ty: &Ty, + span: Span, + body: Option<&Expr>, + ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { + let itctx = if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Binding) + }; + let ty = self.lower_ty(ty, itctx); + (ty, self.lower_const_body(span, body)) + } + fn lower_use_tree( &mut self, tree: &UseTree, diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index c539f98aecf44..fdbf866cd9a95 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -948,6 +948,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.err_handler().span_err(item.span, "unions cannot have zero fields"); } } + ItemKind::Const(.., None) => { + let msg = "free constant item without body"; + self.error_item_without_body(item.span, "constant", msg, " = ;"); + } + ItemKind::Static(.., None) => { + let msg = "free static item without body"; + self.error_item_without_body(item.span, "static", msg, " = ;"); + } _ => {} } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index b0e1b5d4f4238..356fdd1e71c66 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1124,9 +1124,10 @@ impl<'a> State<'a> { self.print_type(ty); self.s.space(); self.end(); // end the head-ibox - - self.word_space("="); - self.print_expr(expr); + if let Some(expr) = expr { + self.word_space("="); + self.print_expr(expr); + } self.s.word(";"); self.end(); // end the outer cbox } @@ -1137,9 +1138,10 @@ impl<'a> State<'a> { self.print_type(ty); self.s.space(); self.end(); // end the head-ibox - - self.word_space("="); - self.print_expr(expr); + if let Some(expr) = expr { + self.word_space("="); + self.print_expr(expr); + } self.s.word(";"); self.end(); // end the outer cbox } diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index 02a0bc00c1169..b6837c0703aed 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -186,81 +186,85 @@ pub fn expand_test_or_bench( ast::ItemKind::Const( cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), // test::TestDescAndFn { - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - vec![ - // desc: test::TestDesc { - field( - "desc", - cx.expr_struct( - sp, - test_path("TestDesc"), - vec![ - // name: "path::to::test" - field( - "name", - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestName")), - vec![cx.expr_str( - sp, - Symbol::intern(&item_path( - // skip the name of the root module - &cx.current_expansion.module.mod_path[1..], - &item.ident, - )), - )], - ), - ), - // ignore: true | false - field("ignore", cx.expr_bool(sp, should_ignore(&item))), - // allow_fail: true | false - field("allow_fail", cx.expr_bool(sp, should_fail(&item))), - // should_panic: ... - field( - "should_panic", - match should_panic(cx, &item) { - // test::ShouldPanic::No - ShouldPanic::No => cx.expr_path(should_panic_path("No")), - // test::ShouldPanic::Yes - ShouldPanic::Yes(None) => { - cx.expr_path(should_panic_path("Yes")) - } - // test::ShouldPanic::YesWithMessage("...") - ShouldPanic::Yes(Some(sym)) => cx.expr_call( + Some( + cx.expr_struct( + sp, + test_path("TestDescAndFn"), + vec![ + // desc: test::TestDesc { + field( + "desc", + cx.expr_struct( + sp, + test_path("TestDesc"), + vec![ + // name: "path::to::test" + field( + "name", + cx.expr_call( sp, - cx.expr_path(should_panic_path("YesWithMessage")), - vec![cx.expr_str(sp, sym)], + cx.expr_path(test_path("StaticTestName")), + vec![cx.expr_str( + sp, + Symbol::intern(&item_path( + // skip the name of the root module + &cx.current_expansion.module.mod_path[1..], + &item.ident, + )), + )], ), - }, - ), - // test_type: ... - field( - "test_type", - match test_type(cx) { - // test::TestType::UnitTest - TestType::UnitTest => { - cx.expr_path(test_type_path("UnitTest")) - } - // test::TestType::IntegrationTest - TestType::IntegrationTest => { - cx.expr_path(test_type_path("IntegrationTest")) - } - // test::TestPath::Unknown - TestType::Unknown => { - cx.expr_path(test_type_path("Unknown")) - } - }, - ), - // }, - ], + ), + // ignore: true | false + field("ignore", cx.expr_bool(sp, should_ignore(&item))), + // allow_fail: true | false + field("allow_fail", cx.expr_bool(sp, should_fail(&item))), + // should_panic: ... + field( + "should_panic", + match should_panic(cx, &item) { + // test::ShouldPanic::No + ShouldPanic::No => { + cx.expr_path(should_panic_path("No")) + } + // test::ShouldPanic::Yes + ShouldPanic::Yes(None) => { + cx.expr_path(should_panic_path("Yes")) + } + // test::ShouldPanic::YesWithMessage("...") + ShouldPanic::Yes(Some(sym)) => cx.expr_call( + sp, + cx.expr_path(should_panic_path("YesWithMessage")), + vec![cx.expr_str(sp, sym)], + ), + }, + ), + // test_type: ... + field( + "test_type", + match test_type(cx) { + // test::TestType::UnitTest + TestType::UnitTest => { + cx.expr_path(test_type_path("UnitTest")) + } + // test::TestType::IntegrationTest + TestType::IntegrationTest => { + cx.expr_path(test_type_path("IntegrationTest")) + } + // test::TestPath::Unknown + TestType::Unknown => { + cx.expr_path(test_type_path("Unknown")) + } + }, + ), + // }, + ], + ), ), - ), - // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) - field("testfn", test_fn), // } - ], - ), // } + // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) + field("testfn", test_fn), // } + ], + ), // } + ), ), ); test_const = test_const.map(|mut tc| { diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index af22e46eb6afa..0882151063098 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -634,7 +634,7 @@ impl<'a> ExtCtxt<'a> { mutbl: ast::Mutability, expr: P, ) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, expr)) + self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr))) } pub fn item_const( @@ -644,7 +644,7 @@ impl<'a> ExtCtxt<'a> { ty: P, expr: P, ) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, expr)) + self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, Some(expr))) } pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 480df99a01eed..7870b9da4cb70 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -603,7 +603,7 @@ impl EarlyLintPass for UnusedParens { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { use ast::ItemKind::*; - if let Const(.., ref expr) | Static(.., ref expr) = item.kind { + if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind { self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None); } } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 4a5b4ff8e04ac..893cbf5adfa62 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -966,7 +966,7 @@ impl<'a> Parser<'a> { } } - /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// /// When `m` is `"const"`, `$ident` may also be `"_"`. @@ -975,25 +975,22 @@ impl<'a> Parser<'a> { // Parse the type of a `const` or `static mut?` item. // That is, the `":" $ty` fragment. - let ty = if self.token == token::Eq { - self.recover_missing_const_type(id, m) - } else { - // Not `=` so expect `":"" $ty` as usual. - self.expect(&token::Colon)?; + let ty = if self.eat(&token::Colon) { self.parse_ty()? + } else { + self.recover_missing_const_type(id, m) }; - self.expect(&token::Eq)?; - let e = self.parse_expr()?; + let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; self.expect_semi()?; let item = match m { - Some(m) => ItemKind::Static(ty, m, e), - None => ItemKind::Const(ty, e), + Some(m) => ItemKind::Static(ty, m, expr), + None => ItemKind::Const(ty, expr), }; Ok((id, item)) } - /// We were supposed to parse `:` but instead, we're already at `=`. + /// We were supposed to parse `:` but the `:` was missing. /// This means that the type is missing. fn recover_missing_const_type(&mut self, id: Ident, m: Option) -> P { // Construct the error and stash it away with the hope diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 1a1a9b1076e98..36667e1d6ff3b 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -881,9 +881,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { debug!("resolve_item ItemKind::Const"); self.with_item_rib(HasGenericParams::No, |this| { this.visit_ty(ty); - this.with_constant_rib(|this| { - this.visit_expr(expr); - }); + if let Some(expr) = expr { + this.with_constant_rib(|this| this.visit_expr(expr)); + } }); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5668be40eefe0..fc5496eb1822f 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -400,7 +400,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { &mut self, item: &'l ast::Item, typ: &'l ast::Ty, - expr: &'l ast::Expr, + expr: Option<&'l ast::Expr>, ) { let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.nest_tables(item.id, |v| { @@ -409,7 +409,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), var_data); } v.visit_ty(&typ); - v.visit_expr(expr); + walk_list!(v, visit_expr, expr); }); } @@ -1293,8 +1293,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { Fn(ref sig, ref ty_params, ref body) => { self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref()) } - Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr), - Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), + Static(ref typ, _, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()), + Const(ref typ, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()), Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => { self.process_struct(item, def, ty_params) } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index bd7bd9bc6169e..d678a8b067e39 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -334,10 +334,13 @@ impl Sig for ast::Item { let ty = ty.make(offset + text.len(), id, scx)?; text.push_str(&ty.text); - text.push_str(" = "); - let expr = pprust::expr_to_string(expr).replace('\n', " "); - text.push_str(&expr); + if let Some(expr) = expr { + text.push_str(" = "); + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + } + text.push(';'); Ok(extend_sig(ty, text, defs, vec![])) @@ -355,10 +358,13 @@ impl Sig for ast::Item { let ty = ty.make(offset + text.len(), id, scx)?; text.push_str(&ty.text); - text.push_str(" = "); - let expr = pprust::expr_to_string(expr).replace('\n', " "); - text.push_str(&expr); + if let Some(expr) = expr { + text.push_str(" = "); + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + } + text.push(';'); Ok(extend_sig(ty, text, defs, vec![])) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fe353bc994aff..61ae14cae028f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2496,11 +2496,11 @@ pub enum ItemKind { /// A static item (`static`). /// /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`. - Static(P, Mutability, P), + Static(P, Mutability, Option>), /// A constant item (`const`). /// /// E.g., `const FOO: i32 = 42;`. - Const(P, P), + Const(P, Option>), /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index d36b0a28a8cee..cd7a3becca765 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -890,13 +890,9 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { match kind { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(ty, _mut, expr) => { + ItemKind::Static(ty, _, expr) | ItemKind::Const(ty, expr) => { vis.visit_ty(ty); - vis.visit_expr(expr); - } - ItemKind::Const(ty, expr) => { - vis.visit_ty(ty); - vis.visit_expr(expr); + visit_opt(expr, |expr| vis.visit_expr(expr)); } ItemKind::Fn(sig, generics, body) => { visit_fn_sig(sig, vis); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ed57fc8abf3b4..4beb94e9f0c19 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -300,7 +300,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::Use(ref use_tree) => visitor.visit_use_tree(use_tree, item.id, false), ItemKind::Static(ref typ, _, ref expr) | ItemKind::Const(ref typ, ref expr) => { visitor.visit_ty(typ); - visitor.visit_expr(expr); + walk_list!(visitor, visit_expr, expr); } ItemKind::Fn(ref sig, ref generics, ref body) => { visitor.visit_generics(generics); diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs new file mode 100644 index 0000000000000..613b3c9856171 --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs @@ -0,0 +1,7 @@ +// Semantically, a free `const` item cannot omit its body. + +fn main() {} + +const A: u8; //~ ERROR free constant item without body +const B; //~ ERROR free constant item without body +//~^ ERROR missing type for `const` item diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr new file mode 100644 index 0000000000000..4e97229fa1a41 --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -0,0 +1,24 @@ +error: free constant item without body + --> $DIR/item-free-const-no-body-semantic-fail.rs:5:1 + | +LL | const A: u8; + | ^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: free constant item without body + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:1 + | +LL | const B; + | ^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: missing type for `const` item + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7 + | +LL | const B; + | ^ help: provide a type for the item: `B: [type error]` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs new file mode 100644 index 0000000000000..acfdd3c363f25 --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs @@ -0,0 +1,8 @@ +// Syntactically, a free `const` item can omit its body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +const X: u8; diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs new file mode 100644 index 0000000000000..780479e3d26ac --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs @@ -0,0 +1,11 @@ +// Semantically, a free `static` item cannot omit its body. + +fn main() {} + +static A: u8; //~ ERROR free static item without body +static B; //~ ERROR free static item without body +//~^ ERROR missing type for `static` item + +static mut C: u8; //~ ERROR free static item without body +static mut D; //~ ERROR free static item without body +//~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr new file mode 100644 index 0000000000000..60b7bb34c698b --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -0,0 +1,46 @@ +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:5:1 + | +LL | static A: u8; + | ^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:1 + | +LL | static B; + | ^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 + | +LL | static mut C: u8; + | ^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:1 + | +LL | static mut D; + | ^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: missing type for `static` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8 + | +LL | static B; + | ^ help: provide a type for the item: `B: [type error]` + +error: missing type for `static mut` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12 + | +LL | static mut D; + | ^ help: provide a type for the item: `D: [type error]` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs new file mode 100644 index 0000000000000..db0039204d870 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs @@ -0,0 +1,8 @@ +// Syntactically, a free `const` item can omit its body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +static X: u8; From 1c2906ead3825c013ac022249f1e1ee3a3b97c75 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 14 Feb 2020 15:56:05 +0100 Subject: [PATCH 08/25] ast/parser: fuse `static` & `const` grammars in all contexts. --- src/librustc_ast_lowering/item.rs | 2 +- src/librustc_ast_passes/ast_validation.rs | 34 +++++++-- src/librustc_ast_pretty/pprust.rs | 71 ++++++------------- src/librustc_parse/parser/item.rs | 37 +++++----- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_save_analysis/sig.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/mut_visit.rs | 5 +- src/libsyntax/visit.rs | 5 +- .../assoc-const-underscore-semantic-fail.rs | 17 +++++ ...ssoc-const-underscore-semantic-fail.stderr | 27 +++++++ .../assoc-const-underscore-syntactic-pass.rs | 18 +++++ .../ui/parser/foreign-static-semantic-fail.rs | 8 +++ .../foreign-static-semantic-fail.stderr | 27 +++++++ .../parser/foreign-static-syntactic-pass.rs | 11 +++ .../ui/parser/underscore_item_not_const.rs | 16 +---- .../parser/underscore_item_not_const.stderr | 44 ++++-------- 18 files changed, 205 insertions(+), 125 deletions(-) create mode 100644 src/test/ui/parser/assoc-const-underscore-semantic-fail.rs create mode 100644 src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr create mode 100644 src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs create mode 100644 src/test/ui/parser/foreign-static-semantic-fail.rs create mode 100644 src/test/ui/parser/foreign-static-semantic-fail.stderr create mode 100644 src/test/ui/parser/foreign-static-syntactic-pass.rs diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index f19481d890d52..813af18c4011f 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -679,7 +679,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } - ForeignItemKind::Static(ref t, m) => { + ForeignItemKind::Static(ref t, m, _) => { let ty = self.lower_ty(t, ImplTraitContext::disallowed()); hir::ForeignItemKind::Static(ty, m) } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index fdbf866cd9a95..fd65750367e59 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -464,19 +464,22 @@ impl<'a> AstValidator<'a> { } } - fn check_foreign_ty_bodyless(&self, ident: Ident, body: Option<&Ty>) { + fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option) { let body = match body { None => return, Some(body) => body, }; self.err_handler() - .struct_span_err(ident.span, "incorrect `type` inside `extern` block") + .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind)) .span_label(ident.span, "cannot have a body") - .span_label(body.span, "the invalid body") + .span_label(body, "the invalid body") .span_label( self.current_extern_span(), - "`extern` blocks define existing foreign types and types \ - inside of them cannot have a body", + format!( + "`extern` blocks define existing foreign {0}s and {0}s \ + inside of them cannot have a body", + kind + ), ) .note(MORE_EXTERN) .emit(); @@ -579,6 +582,16 @@ impl<'a> AstValidator<'a> { } } } + + fn check_item_named(&self, ident: Ident, kind: &str) { + if ident.name != kw::Underscore { + return; + } + self.err_handler() + .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind)) + .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind)) + .emit(); + } } enum GenericPosition { @@ -969,11 +982,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); } ForeignItemKind::TyAlias(generics, bounds, body) => { - self.check_foreign_ty_bodyless(fi.ident, body.as_deref()); + self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span)); self.check_type_no_bounds(bounds, "`extern` blocks"); self.check_foreign_ty_genericless(generics); } - ForeignItemKind::Static(..) | ForeignItemKind::Macro(..) => {} + ForeignItemKind::Static(_, _, body) => { + self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); + } + ForeignItemKind::Macro(..) => {} } visit::walk_foreign_item(self, fi) @@ -1234,6 +1250,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } + if let AssocItemKind::Const(..) = item.kind { + self.check_item_named(item.ident, "const"); + } + self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt)); } } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 356fdd1e71c66..e9dacfec23cc6 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1023,17 +1023,8 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(sig, gen, body) => { self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } - ast::ForeignItemKind::Static(t, m) => { - self.head(visibility_qualified(&item.vis, "static")); - if *m == ast::Mutability::Mut { - self.word_space("mut"); - } - self.print_ident(item.ident); - self.word_space(":"); - self.print_type(t); - self.s.word(";"); - self.end(); // end the head-ibox - self.end(); // end the outer cbox + ast::ForeignItemKind::Static(ty, mutbl, body) => { + self.print_item_const(item.ident, Some(*mutbl), ty, body.as_deref(), &item.vis); } ast::ForeignItemKind::TyAlias(generics, bounds, ty) => { self.print_associated_type(item.ident, generics, bounds, ty.as_deref()); @@ -1047,24 +1038,31 @@ impl<'a> State<'a> { } } - fn print_associated_const( + fn print_item_const( &mut self, ident: ast::Ident, + mutbl: Option, ty: &ast::Ty, - default: Option<&ast::Expr>, + body: Option<&ast::Expr>, vis: &ast::Visibility, ) { - self.s.word(visibility_qualified(vis, "")); - self.word_space("const"); + let leading = match mutbl { + None => "const ", + Some(ast::Mutability::Not) => "static ", + Some(ast::Mutability::Mut) => "static mut ", + }; + self.head(visibility_qualified(vis, leading)); self.print_ident(ident); self.word_space(":"); self.print_type(ty); - if let Some(expr) = default { - self.s.space(); + self.s.space(); + self.end(); // end the head-ibox + if let Some(body) = body { self.word_space("="); - self.print_expr(expr); + self.print_expr(body); } - self.s.word(";") + self.s.word(";"); + self.end(); // end the outer cbox } fn print_associated_type( @@ -1114,36 +1112,11 @@ impl<'a> State<'a> { self.end(); // end inner head-block self.end(); // end outer head-block } - ast::ItemKind::Static(ref ty, m, ref expr) => { - self.head(visibility_qualified(&item.vis, "static")); - if m == ast::Mutability::Mut { - self.word_space("mut"); - } - self.print_ident(item.ident); - self.word_space(":"); - self.print_type(ty); - self.s.space(); - self.end(); // end the head-ibox - if let Some(expr) = expr { - self.word_space("="); - self.print_expr(expr); - } - self.s.word(";"); - self.end(); // end the outer cbox + ast::ItemKind::Static(ref ty, mutbl, ref body) => { + self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis); } - ast::ItemKind::Const(ref ty, ref expr) => { - self.head(visibility_qualified(&item.vis, "const")); - self.print_ident(item.ident); - self.word_space(":"); - self.print_type(ty); - self.s.space(); - self.end(); // end the head-ibox - if let Some(expr) = expr { - self.word_space("="); - self.print_expr(expr); - } - self.s.word(";"); - self.end(); // end the outer cbox + ast::ItemKind::Const(ref ty, ref body) => { + self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis); } ast::ItemKind::Fn(ref sig, ref gen, ref body) => { self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); @@ -1469,7 +1442,7 @@ impl<'a> State<'a> { self.print_defaultness(item.defaultness); match &item.kind { ast::AssocItemKind::Const(ty, expr) => { - self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis); + self.print_item_const(item.ident, None, ty, expr.as_deref(), &item.vis); } ast::AssocItemKind::Fn(sig, generics, body) => { let body = body.as_deref(); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 893cbf5adfa62..ab91580239581 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -670,7 +670,7 @@ impl<'a> Parser<'a> { } else if self.check_fn_front_matter() { let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; (ident, AssocItemKind::Fn(sig, generics, body)) - } else if self.check_keyword(kw::Const) { + } else if self.eat_keyword(kw::Const) { self.parse_assoc_const()? } else if self.isnt_macro_invocation() { return Err(self.missing_assoc_item_kind_err("associated", self.prev_span)); @@ -693,11 +693,7 @@ impl<'a> Parser<'a> { /// AssocConst = "const" Ident ":" Ty "=" Expr ";" fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind)> { self.expect_keyword(kw::Const)?; - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; - self.expect_semi()?; + let (ident, ty, expr) = self.parse_item_const_common(None)?; Ok((ident, AssocItemKind::Const(ty, expr))) } @@ -916,11 +912,8 @@ impl<'a> Parser<'a> { /// Assumes that the `static` keyword is already parsed. fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { let mutbl = self.parse_mutability(); - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - self.expect_semi()?; - Ok((ident, ForeignItemKind::Static(ty, mutbl))) + let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?; + Ok((ident, ForeignItemKind::Static(ty, mutbl, expr))) } /// Parses a type from a foreign module. @@ -971,6 +964,22 @@ impl<'a> Parser<'a> { /// /// When `m` is `"const"`, `$ident` may also be `"_"`. fn parse_item_const(&mut self, m: Option) -> PResult<'a, ItemInfo> { + let (id, ty, expr) = self.parse_item_const_common(m)?; + let item = match m { + Some(m) => ItemKind::Static(ty, m, expr), + None => ItemKind::Const(ty, expr), + }; + Ok((id, item)) + } + + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with + /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. + /// + /// When `m` is `"const"`, `$ident` may also be `"_"`. + fn parse_item_const_common( + &mut self, + m: Option, + ) -> PResult<'a, (Ident, P, Option>)> { let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; // Parse the type of a `const` or `static mut?` item. @@ -983,11 +992,7 @@ impl<'a> Parser<'a> { let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; self.expect_semi()?; - let item = match m { - Some(m) => ItemKind::Static(ty, m, expr), - None => ItemKind::Const(ty, expr), - }; - Ok((id, item)) + Ok((id, ty, expr)) } /// We were supposed to parse `:` but the `:` was missing. diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index fc5496eb1822f..574689be49183 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1532,7 +1532,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { self.visit_ty(&ret_ty); } } - ast::ForeignItemKind::Static(ref ty, _) => { + ast::ForeignItemKind::Static(ref ty, _, _) => { if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(var_data, DefData, item.span); self.dumper.dump_def(&access, var_data); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e983802ee11ba..6bb2bf4c1e995 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -151,7 +151,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { attributes: lower_attributes(item.attrs.clone(), self), })) } - ast::ForeignItemKind::Static(ref ty, _) => { + ast::ForeignItemKind::Static(ref ty, _, _) => { filter!(self.span_utils, item.ident.span); let id = id_from_node_id(item.id, self); diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index d678a8b067e39..8fba3109f2122 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -760,7 +760,7 @@ impl Sig for ast::ForeignItem { Ok(sig) } - ast::ForeignItemKind::Static(ref ty, m) => { + ast::ForeignItemKind::Static(ref ty, m, _) => { let mut text = "static ".to_owned(); if m == ast::Mutability::Mut { text.push_str("mut "); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 61ae14cae028f..bbb629012a951 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2606,7 +2606,7 @@ pub type ForeignItem = Item; #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ForeignItemKind { /// A static item (`static FOO: u8`). - Static(P, Mutability), + Static(P, Mutability, Option>), /// A function. Fn(FnSig, Generics, Option>), /// A type. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index cd7a3becca765..62f640f0bfa24 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1046,7 +1046,10 @@ pub fn noop_flat_map_foreign_item( visitor.visit_generics(generics); visit_opt(body, |body| visitor.visit_block(body)); } - ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), + ForeignItemKind::Static(ty, _, body) => { + visitor.visit_ty(ty); + visit_opt(body, |body| visitor.visit_expr(body)); + } ForeignItemKind::TyAlias(generics, bounds, ty) => { visitor.visit_generics(generics); visit_bounds(bounds, visitor); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4beb94e9f0c19..0dd21cdf12fde 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -534,7 +534,10 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref()); visitor.visit_fn(kind, item.span, item.id); } - ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), + ForeignItemKind::Static(ref typ, _, ref body) => { + visitor.visit_ty(typ); + walk_list!(visitor, visit_expr, body); + } ForeignItemKind::TyAlias(ref generics, ref bounds, ref ty) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); diff --git a/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs new file mode 100644 index 0000000000000..d37ce06c555bf --- /dev/null +++ b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs @@ -0,0 +1,17 @@ +// Semantically, an associated constant cannot use `_` as a name. + +fn main() {} + +const _: () = { + pub trait A { + const _: () = (); //~ ERROR `const` items in this context need a name + } + impl A for () { + const _: () = (); //~ ERROR `const` items in this context need a name + //~^ ERROR const `_` is not a member of trait `A` + } + struct B; + impl B { + const _: () = (); //~ ERROR `const` items in this context need a name + } +}; diff --git a/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr b/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr new file mode 100644 index 0000000000000..538bf0ec100dc --- /dev/null +++ b/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr @@ -0,0 +1,27 @@ +error: `const` items in this context need a name + --> $DIR/assoc-const-underscore-semantic-fail.rs:7:15 + | +LL | const _: () = (); + | ^ `_` is not a valid name for this `const` item + +error: `const` items in this context need a name + --> $DIR/assoc-const-underscore-semantic-fail.rs:10:15 + | +LL | const _: () = (); + | ^ `_` is not a valid name for this `const` item + +error: `const` items in this context need a name + --> $DIR/assoc-const-underscore-semantic-fail.rs:15:15 + | +LL | const _: () = (); + | ^ `_` is not a valid name for this `const` item + +error[E0438]: const `_` is not a member of trait `A` + --> $DIR/assoc-const-underscore-semantic-fail.rs:10:9 + | +LL | const _: () = (); + | ^^^^^^^^^^^^^^^^^ not a member of trait `A` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0438`. diff --git a/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs b/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs new file mode 100644 index 0000000000000..60da408c81153 --- /dev/null +++ b/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs @@ -0,0 +1,18 @@ +// All constant items (associated or otherwise) may syntactically use `_` as a name. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +const _: () = { + pub trait A { + const _: () = (); + } + impl A for () { + const _: () = (); + } + impl dyn A { + const _: () = (); + } +}; diff --git a/src/test/ui/parser/foreign-static-semantic-fail.rs b/src/test/ui/parser/foreign-static-semantic-fail.rs new file mode 100644 index 0000000000000..9abdf33df9c46 --- /dev/null +++ b/src/test/ui/parser/foreign-static-semantic-fail.rs @@ -0,0 +1,8 @@ +// Syntactically, a foreign static may not have a body. + +fn main() {} + +extern { + static X: u8 = 0; //~ ERROR incorrect `static` inside `extern` block + static mut Y: u8 = 0; //~ ERROR incorrect `static` inside `extern` block +} diff --git a/src/test/ui/parser/foreign-static-semantic-fail.stderr b/src/test/ui/parser/foreign-static-semantic-fail.stderr new file mode 100644 index 0000000000000..5942e3a94497b --- /dev/null +++ b/src/test/ui/parser/foreign-static-semantic-fail.stderr @@ -0,0 +1,27 @@ +error: incorrect `static` inside `extern` block + --> $DIR/foreign-static-semantic-fail.rs:6:12 + | +LL | extern { + | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body +LL | static X: u8 = 0; + | ^ - the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `static` inside `extern` block + --> $DIR/foreign-static-semantic-fail.rs:7:16 + | +LL | extern { + | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body +LL | static X: u8 = 0; +LL | static mut Y: u8 = 0; + | ^ - the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/foreign-static-syntactic-pass.rs b/src/test/ui/parser/foreign-static-syntactic-pass.rs new file mode 100644 index 0000000000000..2c805e8a0b700 --- /dev/null +++ b/src/test/ui/parser/foreign-static-syntactic-pass.rs @@ -0,0 +1,11 @@ +// Syntactically, a foreign static may have a body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern { + static X: u8 = 0; + static mut Y: u8 = 0; +} diff --git a/src/test/ui/parser/underscore_item_not_const.rs b/src/test/ui/parser/underscore_item_not_const.rs index 7b0d128f06f8a..c01ac4752e075 100644 --- a/src/test/ui/parser/underscore_item_not_const.rs +++ b/src/test/ui/parser/underscore_item_not_const.rs @@ -1,18 +1,4 @@ -// Test that various non-const items and associated consts do not permit `_` as a name. - -// Associated `const`s: - -pub trait A { - const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` -} -impl A for () { - const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` -} -impl dyn A { - const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` -} - -// Other kinds of items: +// Test that various non-const items do not syntactically permit `_` as a name. static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` struct _(); //~ ERROR expected identifier, found reserved identifier `_` diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr index ebf1ff9ff1ea3..0bc7642dd1964 100644 --- a/src/test/ui/parser/underscore_item_not_const.stderr +++ b/src/test/ui/parser/underscore_item_not_const.stderr @@ -1,92 +1,74 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:6:11 - | -LL | const _: () = (); - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:9:11 - | -LL | const _: () = (); - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:12:11 - | -LL | const _: () = (); - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:17:8 + --> $DIR/underscore_item_not_const.rs:3:8 | LL | static _: () = (); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:18:8 + --> $DIR/underscore_item_not_const.rs:4:8 | LL | struct _(); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:19:6 + --> $DIR/underscore_item_not_const.rs:5:6 | LL | enum _ {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:20:4 + --> $DIR/underscore_item_not_const.rs:6:4 | LL | fn _() {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:21:5 + --> $DIR/underscore_item_not_const.rs:7:5 | LL | mod _ {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:22:6 + --> $DIR/underscore_item_not_const.rs:8:6 | LL | type _ = (); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:23:5 + --> $DIR/underscore_item_not_const.rs:9:5 | LL | use _; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:24:5 + --> $DIR/underscore_item_not_const.rs:10:5 | LL | use _ as g; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:25:7 + --> $DIR/underscore_item_not_const.rs:11:7 | LL | trait _ {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:26:7 + --> $DIR/underscore_item_not_const.rs:12:7 | LL | trait _ = Copy; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:27:14 + --> $DIR/underscore_item_not_const.rs:13:14 | LL | macro_rules! _ { () => {} } | ^ expected identifier, found reserved identifier error: expected one of `!` or `::`, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:28:7 + --> $DIR/underscore_item_not_const.rs:14:7 | LL | union _ { f: u8 } | ^ expected one of `!` or `::` -error: aborting due to 15 previous errors +error: aborting due to 12 previous errors From f8d2264463162291f5cb3391c98d7bc95ec17d87 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 01:50:26 +0100 Subject: [PATCH 09/25] parse associated statics. --- src/librustc_ast_lowering/item.rs | 13 ++- src/librustc_ast_passes/ast_validation.rs | 9 +- src/librustc_ast_pretty/pprust.rs | 3 + src/librustc_parse/parser/item.rs | 18 ++-- src/librustc_resolve/build_reduced_graph.rs | 3 +- src/librustc_resolve/def_collector.rs | 4 +- src/librustc_resolve/late.rs | 5 +- src/librustc_save_analysis/dump_visitor.rs | 6 +- src/libsyntax/ast.rs | 2 + src/libsyntax/mut_visit.rs | 2 +- src/libsyntax/visit.rs | 2 +- src/test/ui/issues/issue-58856-2.stderr | 4 +- src/test/ui/issues/issue-60075.stderr | 2 +- .../ui/parser/assoc-static-semantic-fail.rs | 43 ++++++++ .../parser/assoc-static-semantic-fail.stderr | 99 +++++++++++++++++++ .../ui/parser/assoc-static-syntactic-pass.rs | 29 ++++++ src/test/ui/parser/issue-32446.stderr | 4 +- src/test/ui/parser/issue-41155.stderr | 4 +- .../parser/macro/trait-non-item-macros.stderr | 4 +- .../ui/parser/removed-syntax-static-fn.rs | 4 +- .../ui/parser/removed-syntax-static-fn.stderr | 25 +++-- 21 files changed, 243 insertions(+), 42 deletions(-) create mode 100644 src/test/ui/parser/assoc-static-semantic-fail.rs create mode 100644 src/test/ui/parser/assoc-static-semantic-fail.stderr create mode 100644 src/test/ui/parser/assoc-static-syntactic-pass.rs diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 813af18c4011f..b465fd79c8f20 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -760,7 +760,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = self.resolver.definitions().local_def_id(i.id); let (generics, kind) = match i.kind { - AssocItemKind::Const(ref ty, ref default) => { + AssocItemKind::Static(ref ty, _, ref default) // Let's pretend this is a `const`. + | AssocItemKind::Const(ref ty, ref default) => { let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body)) @@ -802,7 +803,10 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { let (kind, has_default) = match &i.kind { - AssocItemKind::Const(_, default) => (hir::AssocItemKind::Const, default.is_some()), + AssocItemKind::Static(_, _, default) // Let's pretend this is a `const` for recovery. + | AssocItemKind::Const(_, default) => { + (hir::AssocItemKind::Const, default.is_some()) + } AssocItemKind::TyAlias(_, _, default) => (hir::AssocItemKind::Type, default.is_some()), AssocItemKind::Fn(sig, _, default) => { (hir::AssocItemKind::Method { has_self: sig.decl.has_self() }, default.is_some()) @@ -827,7 +831,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let impl_item_def_id = self.resolver.definitions().local_def_id(i.id); let (generics, kind) = match i.kind { - AssocItemKind::Const(ref ty, ref expr) => { + AssocItemKind::Static(ref ty, _, ref expr) | AssocItemKind::Const(ref ty, ref expr) => { let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); ( hir::Generics::empty(), @@ -895,7 +899,8 @@ impl<'hir> LoweringContext<'_, 'hir> { vis: self.lower_visibility(&i.vis, Some(i.id)), defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), kind: match &i.kind { - AssocItemKind::Const(..) => hir::AssocItemKind::Const, + AssocItemKind::Static(..) // Let's pretend this is a `const` for recovery. + | AssocItemKind::Const(..) => hir::AssocItemKind::Const, AssocItemKind::TyAlias(_, _, ty) => { match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) { None => hir::AssocItemKind::Type, diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index fd65750367e59..72cffdd750a32 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -1250,8 +1250,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - if let AssocItemKind::Const(..) = item.kind { - self.check_item_named(item.ident, "const"); + match item.kind { + AssocItemKind::Const(..) => self.check_item_named(item.ident, "const"), + AssocItemKind::Static(..) => self + .err_handler() + .struct_span_err(item.span, "associated `static` items are not allowed") + .emit(), + _ => {} } self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt)); diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index e9dacfec23cc6..ee1a829da1a44 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1441,6 +1441,9 @@ impl<'a> State<'a> { self.print_outer_attributes(&item.attrs); self.print_defaultness(item.defaultness); match &item.kind { + ast::AssocItemKind::Static(ty, mutbl, expr) => { + self.print_item_const(item.ident, Some(*mutbl), ty, expr.as_deref(), &item.vis); + } ast::AssocItemKind::Const(ty, expr) => { self.print_item_const(item.ident, None, ty, expr.as_deref(), &item.vis); } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index ab91580239581..9b7728f27d0f7 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -546,6 +546,7 @@ impl<'a> Parser<'a> { 1, &[ kw::Impl, + kw::Static, kw::Const, kw::Async, kw::Fn, @@ -670,8 +671,14 @@ impl<'a> Parser<'a> { } else if self.check_fn_front_matter() { let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; (ident, AssocItemKind::Fn(sig, generics, body)) + } else if self.is_static_global() { + self.bump(); // `static` + let mutbl = self.parse_mutability(); + let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?; + (ident, AssocItemKind::Static(ty, mutbl, expr)) } else if self.eat_keyword(kw::Const) { - self.parse_assoc_const()? + let (ident, ty, expr) = self.parse_item_const_common(None)?; + (ident, AssocItemKind::Const(ty, expr)) } else if self.isnt_macro_invocation() { return Err(self.missing_assoc_item_kind_err("associated", self.prev_span)); } else if self.token.is_path_start() { @@ -688,15 +695,6 @@ impl<'a> Parser<'a> { Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None }) } - /// This parses the grammar: - /// - /// AssocConst = "const" Ident ":" Ty "=" Expr ";" - fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind)> { - self.expect_keyword(kw::Const)?; - let (ident, ty, expr) = self.parse_item_const_common(None)?; - Ok((ident, AssocItemKind::Const(ty, expr))) - } - /// Parses the following grammar: /// /// AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f5e64443dda6a..7c541928e6fab 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1251,7 +1251,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { // Add the item to the trait info. let item_def_id = self.r.definitions.local_def_id(item.id); let (res, ns) = match item.kind { - AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS), + AssocItemKind::Static(..) // Let's pretend it's a `const` for recovery. + | AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS), AssocItemKind::Fn(ref sig, _, _) => { if sig.decl.has_self() { self.r.has_self.insert(item_def_id); diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index 256b5ff4b9a89..60cba55512193 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -228,7 +228,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { body.as_deref(), ); } - AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name), + AssocItemKind::Fn(..) | AssocItemKind::Const(..) | AssocItemKind::Static(..) => { + DefPathData::ValueNs(i.ident.name) + } AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), AssocItemKind::Macro(..) => return self.visit_macro_invoc(i.id), }; diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 36667e1d6ff3b..7b445fcc03538 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -836,7 +836,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for item in trait_items { this.with_trait_items(trait_items, |this| { match &item.kind { - AssocItemKind::Const(ty, default) => { + AssocItemKind::Static(ty, _, default) + | AssocItemKind::Const(ty, default) => { this.visit_ty(ty); // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. @@ -1109,7 +1110,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for item in impl_items { use crate::ResolutionError::*; match &item.kind { - AssocItemKind::Const(..) => { + AssocItemKind::Static(..) | AssocItemKind::Const(..) => { debug!("resolve_implementation AssocItemKind::Const",); // If this is a trait impl, ensure the const // exists in trait diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 574689be49183..001f2f098549d 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1004,7 +1004,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { self.process_macro_use(trait_item.span); let vis_span = trait_item.span.shrink_to_lo(); match trait_item.kind { - ast::AssocItemKind::Const(ref ty, ref expr) => { + ast::AssocItemKind::Static(ref ty, _, ref expr) + | ast::AssocItemKind::Const(ref ty, ref expr) => { self.process_assoc_const( trait_item.id, trait_item.ident, @@ -1074,7 +1075,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { fn process_impl_item(&mut self, impl_item: &'l ast::AssocItem, impl_id: DefId) { self.process_macro_use(impl_item.span); match impl_item.kind { - ast::AssocItemKind::Const(ref ty, ref expr) => { + ast::AssocItemKind::Static(ref ty, _, ref expr) + | ast::AssocItemKind::Const(ref ty, ref expr) => { self.process_assoc_const( impl_item.id, impl_item.ident, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bbb629012a951..ca39fbd6c5d0f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2654,6 +2654,8 @@ pub enum AssocItemKind { /// A constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. /// If `def` is parsed, then the constant is provided, and otherwise required. Const(P, Option>), + /// A static item (`static FOO: u8`). + Static(P, Mutability, Option>), /// A function. Fn(FnSig, Generics, Option>), /// A type. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 62f640f0bfa24..91db61586896a 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -954,7 +954,7 @@ pub fn noop_flat_map_assoc_item( visitor.visit_vis(vis); visit_attrs(attrs, visitor); match kind { - AssocItemKind::Const(ty, expr) => { + AssocItemKind::Const(ty, expr) | AssocItemKind::Static(ty, _, expr) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 0dd21cdf12fde..f5763ecf573e3 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -633,7 +633,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, visitor.visit_ident(item.ident); walk_list!(visitor, visit_attribute, &item.attrs); match item.kind { - AssocItemKind::Const(ref ty, ref expr) => { + AssocItemKind::Const(ref ty, ref expr) | AssocItemKind::Static(ref ty, _, ref expr) => { visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr index 6221b90b31dd7..f4ca3c46ea28a 100644 --- a/src/test/ui/issues/issue-58856-2.stderr +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -7,11 +7,11 @@ LL | fn how_are_you(&self -> Empty { | | help: `)` may belong here | unclosed delimiter -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `)` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, `}`, or identifier, found `)` --> $DIR/issue-58856-2.rs:11:1 | LL | } - | - expected one of 11 possible tokens + | - expected one of 12 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr index b2beb73503bb0..bab50a53b1ae4 100644 --- a/src/test/ui/issues/issue-60075.stderr +++ b/src/test/ui/issues/issue-60075.stderr @@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` LL | }); | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `;` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, `}`, or identifier, found `;` --> $DIR/issue-60075.rs:6:11 | LL | fn qux() -> Option { diff --git a/src/test/ui/parser/assoc-static-semantic-fail.rs b/src/test/ui/parser/assoc-static-semantic-fail.rs new file mode 100644 index 0000000000000..cf3debd77cbfd --- /dev/null +++ b/src/test/ui/parser/assoc-static-semantic-fail.rs @@ -0,0 +1,43 @@ +// Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item. + +#![feature(specialization)] + +fn main() {} + +struct S; +impl S { + static IA: u8 = 0; + //~^ ERROR associated `static` items are not allowed + static IB: u8; + //~^ ERROR associated `static` items are not allowed + default static IC: u8 = 0; + //~^ ERROR associated `static` items are not allowed + pub(crate) default static ID: u8; + //~^ ERROR associated `static` items are not allowed +} + +trait T { + static TA: u8 = 0; + //~^ ERROR associated `static` items are not allowed + static TB: u8; + //~^ ERROR associated `static` items are not allowed + default static TC: u8 = 0; + //~^ ERROR associated `static` items are not allowed + //~| ERROR `default` is only allowed on items in + pub(crate) default static TD: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR `default` is only allowed on items in + //~| ERROR unnecessary visibility qualifier +} + +impl T for S { + static TA: u8 = 0; + //~^ ERROR associated `static` items are not allowed + static TB: u8; + //~^ ERROR associated `static` items are not allowed + default static TC: u8 = 0; + //~^ ERROR associated `static` items are not allowed + pub default static TD: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR unnecessary visibility qualifier +} diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr new file mode 100644 index 0000000000000..d5a02c9bebcf0 --- /dev/null +++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr @@ -0,0 +1,99 @@ +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:9:5 + | +LL | static IA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:11:5 + | +LL | static IB: u8; + | ^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:13:5 + | +LL | default static IC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:15:5 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:20:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:22:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/assoc-static-semantic-fail.rs:24:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:24:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/assoc-static-semantic-fail.rs:27:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0449]: unnecessary visibility qualifier + --> $DIR/assoc-static-semantic-fail.rs:27:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:27:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:34:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:36:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:38:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0449]: unnecessary visibility qualifier + --> $DIR/assoc-static-semantic-fail.rs:40:5 + | +LL | pub default static TD: u8; + | ^^^ `pub` not permitted here because it's implied + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:40:5 + | +LL | pub default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0449`. diff --git a/src/test/ui/parser/assoc-static-syntactic-pass.rs b/src/test/ui/parser/assoc-static-syntactic-pass.rs new file mode 100644 index 0000000000000..7f5b9f7933563 --- /dev/null +++ b/src/test/ui/parser/assoc-static-syntactic-pass.rs @@ -0,0 +1,29 @@ +// Syntactically, we do allow e.g., `static X: u8 = 0;` as an associated item. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +impl S { + static IA: u8 = 0; + static IB: u8; + default static IC: u8 = 0; + pub(crate) default static ID: u8; +} + +#[cfg(FALSE)] +trait T { + static TA: u8 = 0; + static TB: u8; + default static TC: u8 = 0; + pub(crate) default static TD: u8; +} + +#[cfg(FALSE)] +impl T for S { + static TA: u8 = 0; + static TB: u8; + default static TC: u8 = 0; + pub default static TD: u8; +} diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr index 25c1efe35ae11..d25828da0b979 100644 --- a/src/test/ui/parser/issue-32446.stderr +++ b/src/test/ui/parser/issue-32446.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `...` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, `}`, or identifier, found `...` --> $DIR/issue-32446.rs:4:11 | LL | trait T { ... } - | ^^^ expected one of 11 possible tokens + | ^^^ expected one of 12 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/issue-41155.stderr b/src/test/ui/parser/issue-41155.stderr index 327bc65818fa9..a91ef6c67e89e 100644 --- a/src/test/ui/parser/issue-41155.stderr +++ b/src/test/ui/parser/issue-41155.stderr @@ -1,8 +1,8 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, `unsafe`, or identifier, found `}` +error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `static`, `type`, `unsafe`, or identifier, found `}` --> $DIR/issue-41155.rs:5:1 | LL | pub - | - expected one of 9 possible tokens + | - expected one of 10 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr index 9d05e85bcc00e..c76b096a1ebf4 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.stderr +++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or identifier, found `2` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, or identifier, found `2` --> $DIR/trait-non-item-macros.rs:2:19 | LL | ($a:expr) => ($a) - | ^^ expected one of 10 possible tokens + | ^^ expected one of 11 possible tokens ... LL | bah!(2); | -------- in this macro invocation diff --git a/src/test/ui/parser/removed-syntax-static-fn.rs b/src/test/ui/parser/removed-syntax-static-fn.rs index 9e12222f3fd8b..cd643b874dbda 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.rs +++ b/src/test/ui/parser/removed-syntax-static-fn.rs @@ -1,8 +1,10 @@ struct S; impl S { - //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration static fn f() {} + //~^ ERROR expected identifier, found keyword `fn` + //~| ERROR expected one of `:`, `;`, or `=` + //~| ERROR missing type for `static` item } fn main() {} diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr index 5edf88026fbec..dc5625bdadea3 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.stderr +++ b/src/test/ui/parser/removed-syntax-static-fn.stderr @@ -1,11 +1,20 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/removed-syntax-static-fn.rs:3:9 +error: expected identifier, found keyword `fn` + --> $DIR/removed-syntax-static-fn.rs:4:12 | -LL | impl S { - | _________^ -LL | | -LL | | static fn f() {} - | |____^ missing `fn`, `type`, or `const` +LL | static fn f() {} + | ^^ expected identifier, found keyword -error: aborting due to previous error +error: expected one of `:`, `;`, or `=`, found `f` + --> $DIR/removed-syntax-static-fn.rs:4:15 + | +LL | static fn f() {} + | ^ expected one of `:`, `;`, or `=` + +error: missing type for `static` item + --> $DIR/removed-syntax-static-fn.rs:4:12 + | +LL | static fn f() {} + | ^^ help: provide a type for the item: `r#fn: ` + +error: aborting due to 3 previous errors From 35884fe16889b39d4be43cf8effc3bdf843c6f12 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 02:23:10 +0100 Subject: [PATCH 10/25] parse extern consts --- src/librustc_ast_lowering/item.rs | 5 ++++ src/librustc_ast_passes/ast_validation.rs | 17 ++++++++++++ src/librustc_ast_passes/feature_gate.rs | 2 +- src/librustc_ast_pretty/pprust.rs | 3 +++ src/librustc_parse/parser/item.rs | 27 +++++-------------- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/late.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_save_analysis/sig.rs | 1 + src/libsyntax/ast.rs | 4 +++ src/libsyntax/mut_visit.rs | 2 +- src/libsyntax/visit.rs | 3 ++- src/test/ui/extern/extern-const.stderr | 10 +++++-- .../ui/parser/foreign-const-semantic-fail.rs | 8 ++++++ .../parser/foreign-const-semantic-fail.stderr | 27 +++++++++++++++++++ .../ui/parser/foreign-const-syntactic-pass.rs | 11 ++++++++ .../ui/parser/removed-syntax-extern-const.rs | 6 ----- .../parser/removed-syntax-extern-const.stderr | 8 ------ 19 files changed, 98 insertions(+), 44 deletions(-) create mode 100644 src/test/ui/parser/foreign-const-semantic-fail.rs create mode 100644 src/test/ui/parser/foreign-const-semantic-fail.stderr create mode 100644 src/test/ui/parser/foreign-const-syntactic-pass.rs delete mode 100644 src/test/ui/parser/removed-syntax-extern-const.rs delete mode 100644 src/test/ui/parser/removed-syntax-extern-const.stderr diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index b465fd79c8f20..e0db8606bc203 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -683,6 +683,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty(t, ImplTraitContext::disallowed()); hir::ForeignItemKind::Static(ty, m) } + ForeignItemKind::Const(ref t, _) => { + // For recovery purposes. + let ty = self.lower_ty(t, ImplTraitContext::disallowed()); + hir::ForeignItemKind::Static(ty, Mutability::Not) + } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"), }, diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 72cffdd750a32..8efd50ad0987e 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -533,6 +533,20 @@ impl<'a> AstValidator<'a> { } } + fn error_foreign_const(&self, ident: Ident, span: Span) { + self.err_handler() + .struct_span_err(ident.span, "extern items cannot be `const`") + .span_suggestion( + span.with_hi(ident.span.lo()), + "try using a static value", + "static ".to_string(), + Applicability::MachineApplicable, + ) + .span_label(self.current_extern_span(), "in this `extern` block") + .note(MORE_EXTERN) + .emit(); + } + /// Reject C-varadic type unless the function is foreign, /// or free and `unsafe extern "C"` semantically. fn check_c_varadic_type(&self, fk: FnKind<'a>) { @@ -989,6 +1003,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ForeignItemKind::Static(_, _, body) => { self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); } + ForeignItemKind::Const(..) => { + self.error_foreign_const(fi.ident, fi.span); + } ForeignItemKind::Macro(..) => {} } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index c543f7095b943..d4de2c937583d 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -400,7 +400,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ForeignItemKind::TyAlias(..) => { gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); } - ast::ForeignItemKind::Macro(..) => {} + ast::ForeignItemKind::Macro(..) | ast::ForeignItemKind::Const(..) => {} } visit::walk_foreign_item(self, i) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index ee1a829da1a44..410600e495778 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1023,6 +1023,9 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(sig, gen, body) => { self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } + ast::ForeignItemKind::Const(ty, body) => { + self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis); + } ast::ForeignItemKind::Static(ty, mutbl, body) => { self.print_item_const(item.ident, Some(*mutbl), ty, body.as_deref(), &item.vis); } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 9b7728f27d0f7..5fcd72090ec87 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -880,19 +880,12 @@ impl<'a> Parser<'a> { } else if self.is_static_global() { // FOREIGN STATIC ITEM self.bump(); // `static` - self.parse_item_foreign_static()? - } else if self.token.is_keyword(kw::Const) { - // Treat `const` as `static` for error recovery, but don't add it to expected tokens. - self.bump(); // `const` - self.struct_span_err(self.prev_span, "extern items cannot be `const`") - .span_suggestion( - self.prev_span, - "try using a static value", - "static".to_owned(), - Applicability::MachineApplicable, - ) - .emit(); - self.parse_item_foreign_static()? + let mutbl = self.parse_mutability(); + let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?; + (ident, ForeignItemKind::Static(ty, mutbl, expr)) + } else if self.eat_keyword(kw::Const) { + let (ident, ty, expr) = self.parse_item_const_common(None)?; + (ident, ForeignItemKind::Const(ty, expr)) } else if self.isnt_macro_invocation() { return Err(self.missing_assoc_item_kind_err("extern", self.prev_span)); } else if self.token.is_path_start() { @@ -906,14 +899,6 @@ impl<'a> Parser<'a> { Ok(P(self.mk_item(lo, ident, kind, vis, attrs))) } - /// Parses a static item from a foreign module. - /// Assumes that the `static` keyword is already parsed. - fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { - let mutbl = self.parse_mutability(); - let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?; - Ok((ident, ForeignItemKind::Static(ty, mutbl, expr))) - } - /// Parses a type from a foreign module. fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { let (ident, kind) = self.parse_assoc_ty()?; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 7c541928e6fab..1f622b80e8e2e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -826,7 +826,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ForeignItemKind::Fn(..) => { (Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS) } - ForeignItemKind::Static(..) => { + ForeignItemKind::Static(..) | ForeignItemKind::Const(..) => { (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::TyAlias(..) => { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 7b445fcc03538..68559c0446aed 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -443,7 +443,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_foreign_item(this, foreign_item); }); } - ForeignItemKind::Static(..) => { + ForeignItemKind::Const(..) | ForeignItemKind::Static(..) => { self.with_item_rib(HasGenericParams::No, |this| { visit::walk_foreign_item(this, foreign_item); }); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 001f2f098549d..6a3abf4fbf5f3 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1534,7 +1534,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { self.visit_ty(&ret_ty); } } - ast::ForeignItemKind::Static(ref ty, _, _) => { + ast::ForeignItemKind::Const(ref ty, _) | ast::ForeignItemKind::Static(ref ty, _, _) => { if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(var_data, DefData, item.span); self.dumper.dump_def(&access, var_data); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 6bb2bf4c1e995..d244370ae2c11 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -151,7 +151,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { attributes: lower_attributes(item.attrs.clone(), self), })) } - ast::ForeignItemKind::Static(ref ty, _, _) => { + ast::ForeignItemKind::Const(ref ty, _) | ast::ForeignItemKind::Static(ref ty, _, _) => { filter!(self.span_utils, item.ident.span); let id = id_from_node_id(item.id, self); diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 8fba3109f2122..3c68124ad40f7 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -792,6 +792,7 @@ impl Sig for ast::ForeignItem { Ok(Signature { text: text, defs: defs, refs: vec![] }) } + ast::ForeignItemKind::Const(..) => Err("foreign const"), ast::ForeignItemKind::Macro(..) => Err("macro"), } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ca39fbd6c5d0f..5041d43b16c08 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2605,6 +2605,9 @@ pub type ForeignItem = Item; /// An item within an `extern` block. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ForeignItemKind { + /// A constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. + /// If `def` is parsed, then the constant is provided, and otherwise required. + Const(P, Option>), /// A static item (`static FOO: u8`). Static(P, Mutability, Option>), /// A function. @@ -2619,6 +2622,7 @@ impl ForeignItemKind { pub fn descriptive_variant(&self) -> &str { match *self { ForeignItemKind::Fn(..) => "foreign function", + ForeignItemKind::Const(..) => "foreign const item", ForeignItemKind::Static(..) => "foreign static item", ForeignItemKind::TyAlias(..) => "foreign type", ForeignItemKind::Macro(..) => "macro in foreign module", diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 91db61586896a..ffc42340dba64 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1046,7 +1046,7 @@ pub fn noop_flat_map_foreign_item( visitor.visit_generics(generics); visit_opt(body, |body| visitor.visit_block(body)); } - ForeignItemKind::Static(ty, _, body) => { + ForeignItemKind::Const(ty, body) | ForeignItemKind::Static(ty, _, body) => { visitor.visit_ty(ty); visit_opt(body, |body| visitor.visit_expr(body)); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f5763ecf573e3..5a21eb55528d0 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -534,7 +534,8 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref()); visitor.visit_fn(kind, item.span, item.id); } - ForeignItemKind::Static(ref typ, _, ref body) => { + ForeignItemKind::Const(ref typ, ref body) + | ForeignItemKind::Static(ref typ, _, ref body) => { visitor.visit_ty(typ); walk_list!(visitor, visit_expr, body); } diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr index 258202b6903d3..97e11381c6f78 100644 --- a/src/test/ui/extern/extern-const.stderr +++ b/src/test/ui/extern/extern-const.stderr @@ -1,8 +1,14 @@ error: extern items cannot be `const` - --> $DIR/extern-const.rs:16:5 + --> $DIR/extern-const.rs:16:11 | +LL | extern "C" { + | ---------- in this `extern` block LL | const rust_dbg_static_mut: libc::c_int; - | ^^^^^ help: try using a static value: `static` + | ------^^^^^^^^^^^^^^^^^^^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html error: aborting due to previous error diff --git a/src/test/ui/parser/foreign-const-semantic-fail.rs b/src/test/ui/parser/foreign-const-semantic-fail.rs new file mode 100644 index 0000000000000..d28b64142826c --- /dev/null +++ b/src/test/ui/parser/foreign-const-semantic-fail.rs @@ -0,0 +1,8 @@ +fn main() {} + +extern { + const A: isize; + //~^ ERROR extern items cannot be `const` + const B: isize = 42; + //~^ ERROR extern items cannot be `const` +} diff --git a/src/test/ui/parser/foreign-const-semantic-fail.stderr b/src/test/ui/parser/foreign-const-semantic-fail.stderr new file mode 100644 index 0000000000000..799a795c5939a --- /dev/null +++ b/src/test/ui/parser/foreign-const-semantic-fail.stderr @@ -0,0 +1,27 @@ +error: extern items cannot be `const` + --> $DIR/foreign-const-semantic-fail.rs:4:11 + | +LL | extern { + | ------ in this `extern` block +LL | const A: isize; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: extern items cannot be `const` + --> $DIR/foreign-const-semantic-fail.rs:6:11 + | +LL | extern { + | ------ in this `extern` block +... +LL | const B: isize = 42; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/foreign-const-syntactic-pass.rs b/src/test/ui/parser/foreign-const-syntactic-pass.rs new file mode 100644 index 0000000000000..bacef8e71d62e --- /dev/null +++ b/src/test/ui/parser/foreign-const-syntactic-pass.rs @@ -0,0 +1,11 @@ +// Syntactically, a `const` item inside an `extern { ... }` block is allowed. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern { + const A: isize; + const B: isize = 42; +} diff --git a/src/test/ui/parser/removed-syntax-extern-const.rs b/src/test/ui/parser/removed-syntax-extern-const.rs deleted file mode 100644 index 71c22e62f8e4b..0000000000000 --- a/src/test/ui/parser/removed-syntax-extern-const.rs +++ /dev/null @@ -1,6 +0,0 @@ -extern { - const i: isize; - //~^ ERROR extern items cannot be `const` -} - -fn main() {} diff --git a/src/test/ui/parser/removed-syntax-extern-const.stderr b/src/test/ui/parser/removed-syntax-extern-const.stderr deleted file mode 100644 index 2bccbd91452f6..0000000000000 --- a/src/test/ui/parser/removed-syntax-extern-const.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: extern items cannot be `const` - --> $DIR/removed-syntax-extern-const.rs:2:5 - | -LL | const i: isize; - | ^^^^^ help: try using a static value: `static` - -error: aborting due to previous error - From 91110fda27b2d227a5c5b20e3be01a47f7e39910 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 02:34:19 +0100 Subject: [PATCH 11/25] ast: make ForeignItemKind an alias of AssocItemKind --- src/libsyntax/ast.rs | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5041d43b16c08..a931d8c27ba83 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2600,35 +2600,8 @@ impl ItemKind { } } -pub type ForeignItem = Item; - -/// An item within an `extern` block. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum ForeignItemKind { - /// A constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. - /// If `def` is parsed, then the constant is provided, and otherwise required. - Const(P, Option>), - /// A static item (`static FOO: u8`). - Static(P, Mutability, Option>), - /// A function. - Fn(FnSig, Generics, Option>), - /// A type. - TyAlias(Generics, GenericBounds, Option>), - /// A macro expanding to an item. - Macro(Mac), -} - -impl ForeignItemKind { - pub fn descriptive_variant(&self) -> &str { - match *self { - ForeignItemKind::Fn(..) => "foreign function", - ForeignItemKind::Const(..) => "foreign const item", - ForeignItemKind::Static(..) => "foreign static item", - ForeignItemKind::TyAlias(..) => "foreign type", - ForeignItemKind::Macro(..) => "macro in foreign module", - } - } -} +pub type ForeignItem = Item; +pub type ForeignItemKind = AssocItemKind; /// Represents associated items. /// These include items in `impl` and `trait` definitions. @@ -2646,7 +2619,7 @@ pub struct AssocItem { pub tokens: Option, } -/// Represents various kinds of content within an `impl`. +/// Represents non-free item kinds. /// /// The term "provided" in the variants below refers to the item having a default /// definition / body. Meanwhile, a "required" item lacks a definition / body. From 0e0c0286a2dfe62ca3093e68a77931bff8896b01 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 17:35:29 +0100 Subject: [PATCH 12/25] fuse extern & associated item parsing up to defaultness --- src/librustc_parse/parser/item.rs | 116 ++++++------------ src/test/ui/did_you_mean/issue-40006.rs | 4 +- src/test/ui/did_you_mean/issue-40006.stderr | 24 ++-- src/test/ui/macros/issue-54441.rs | 2 +- src/test/ui/macros/issue-54441.stderr | 4 +- src/test/ui/parser/default.rs | 2 +- src/test/ui/parser/default.stderr | 4 +- src/test/ui/parser/duplicate-visibility.rs | 2 +- .../ui/parser/duplicate-visibility.stderr | 4 +- src/test/ui/parser/extern-no-fn.rs | 3 +- src/test/ui/parser/extern-no-fn.stderr | 5 +- src/test/ui/parser/issue-19398.rs | 2 +- src/test/ui/parser/issue-19398.stderr | 4 +- src/test/ui/parser/issue-21153.rs | 3 +- src/test/ui/parser/issue-21153.stderr | 5 +- .../missing-close-brace-in-impl-trait.rs | 2 +- .../missing-close-brace-in-impl-trait.stderr | 4 +- .../missing-close-brace-in-trait.rs | 2 +- .../missing-close-brace-in-trait.stderr | 4 +- 19 files changed, 81 insertions(+), 115 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 5fcd72090ec87..20d6182ddc19b 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -13,7 +13,7 @@ use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, Unsafe}; use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind}; use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; -use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind}; +use syntax::ast::{FnHeader, ForeignItem, Mutability, Visibility, VisibilityKind}; use syntax::ptr::P; use syntax::token; use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; @@ -333,29 +333,19 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn]) } - fn missing_assoc_item_kind_err( - &self, - item_type: &str, - prev_span: Span, - ) -> DiagnosticBuilder<'a> { - let expected_kinds = if item_type == "extern" { - "missing `fn`, `type`, or `static`" - } else { - "missing `fn`, `type`, or `const`" - }; - - // Given this code `path(`, it seems like this is not - // setting the visibility of a macro invocation, but rather - // a mistyped method declaration. - // Create a diagnostic pointing out that `fn` is missing. - // - // x | pub path(&self) { - // | ^ missing `fn`, `type`, or `const` - // pub path( - // ^^ `sp` below will point to this + /// Given this code `path(`, it seems like this is not + /// setting the visibility of a macro invocation, + /// but rather a mistyped method declaration. + /// Create a diagnostic pointing out that `fn` is missing. + /// + /// ``` + /// x | pub path(&self) { + /// | ^ missing `fn`, `type`, `const`, or `static` + /// ``` + fn missing_nested_item_kind_err(&self, prev_span: Span) -> DiagnosticBuilder<'a> { let sp = prev_span.between(self.token.span); - let mut err = self - .struct_span_err(sp, &format!("{} for {}-item declaration", expected_kinds, item_type)); + let expected_kinds = "missing `fn`, `type`, `const`, or `static`"; + let mut err = self.struct_span_err(sp, &format!("{} for item declaration", expected_kinds)); err.span_label(sp, expected_kinds); err } @@ -639,7 +629,7 @@ impl<'a> Parser<'a> { fn parse_assoc_item( &mut self, at_end: &mut bool, - req_name: fn(&token::Token) -> bool, + req_name: ReqName, ) -> PResult<'a, P> { let attrs = self.parse_outer_attributes()?; let mut unclosed_delims = vec![]; @@ -660,39 +650,47 @@ impl<'a> Parser<'a> { &mut self, at_end: &mut bool, mut attrs: Vec, - req_name: fn(&token::Token) -> bool, + req_name: ReqName, ) -> PResult<'a, AssocItem> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; let defaultness = self.parse_defaultness(); + let (ident, kind) = self.parse_assoc_item_kind(at_end, &mut attrs, req_name, &vis)?; + let span = lo.to(self.prev_span); + let id = DUMMY_NODE_ID; + Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None }) + } - let (ident, kind) = if self.eat_keyword(kw::Type) { - self.parse_assoc_ty()? + fn parse_assoc_item_kind( + &mut self, + at_end: &mut bool, + attrs: &mut Vec, + req_name: ReqName, + vis: &Visibility, + ) -> PResult<'a, (Ident, AssocItemKind)> { + if self.eat_keyword(kw::Type) { + self.parse_assoc_ty() } else if self.check_fn_front_matter() { - let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; - (ident, AssocItemKind::Fn(sig, generics, body)) + let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, req_name)?; + Ok((ident, AssocItemKind::Fn(sig, generics, body))) } else if self.is_static_global() { self.bump(); // `static` let mutbl = self.parse_mutability(); let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?; - (ident, AssocItemKind::Static(ty, mutbl, expr)) + Ok((ident, AssocItemKind::Static(ty, mutbl, expr))) } else if self.eat_keyword(kw::Const) { let (ident, ty, expr) = self.parse_item_const_common(None)?; - (ident, AssocItemKind::Const(ty, expr)) + Ok((ident, AssocItemKind::Const(ty, expr))) } else if self.isnt_macro_invocation() { - return Err(self.missing_assoc_item_kind_err("associated", self.prev_span)); + Err(self.missing_nested_item_kind_err(self.prev_span)) } else if self.token.is_path_start() { let mac = self.parse_item_macro(&vis)?; *at_end = true; - (Ident::invalid(), AssocItemKind::Macro(mac)) + Ok((Ident::invalid(), AssocItemKind::Macro(mac))) } else { - self.recover_attrs_no_item(&attrs)?; - self.unexpected()? - }; - - let span = lo.to(self.prev_span); - let id = DUMMY_NODE_ID; - Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None }) + self.recover_attrs_no_item(attrs)?; + self.unexpected() + } } /// Parses the following grammar: @@ -869,46 +867,10 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; - - let (ident, kind) = if self.eat_keyword(kw::Type) { - // FOREIGN TYPE ITEM - self.parse_item_foreign_type()? - } else if self.check_fn_front_matter() { - // FOREIGN FUNCTION ITEM - let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, |_| true)?; - (ident, ForeignItemKind::Fn(sig, generics, body)) - } else if self.is_static_global() { - // FOREIGN STATIC ITEM - self.bump(); // `static` - let mutbl = self.parse_mutability(); - let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?; - (ident, ForeignItemKind::Static(ty, mutbl, expr)) - } else if self.eat_keyword(kw::Const) { - let (ident, ty, expr) = self.parse_item_const_common(None)?; - (ident, ForeignItemKind::Const(ty, expr)) - } else if self.isnt_macro_invocation() { - return Err(self.missing_assoc_item_kind_err("extern", self.prev_span)); - } else if self.token.is_path_start() { - let mac = self.parse_item_macro(&vis)?; - *at_end = true; - (Ident::invalid(), ForeignItemKind::Macro(mac)) - } else { - self.recover_attrs_no_item(&attrs)?; - self.unexpected()? - }; + let (ident, kind) = self.parse_assoc_item_kind(at_end, &mut attrs, |_| true, &vis)?; Ok(P(self.mk_item(lo, ident, kind, vis, attrs))) } - /// Parses a type from a foreign module. - fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { - let (ident, kind) = self.parse_assoc_ty()?; - let kind = match kind { - AssocItemKind::TyAlias(g, b, d) => ForeignItemKind::TyAlias(g, b, d), - _ => unreachable!(), - }; - Ok((ident, kind)) - } - fn is_static_global(&mut self) -> bool { if self.check_keyword(kw::Static) { // Check if this could be a closure. diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs index 60633c6930cdf..2ed682cea9503 100644 --- a/src/test/ui/did_you_mean/issue-40006.rs +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -18,10 +18,10 @@ trait A { //~ ERROR missing trait B { fn xxx() { ### } //~ ERROR expected } -trait C { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration +trait C { //~ ERROR missing `fn`, `type`, `const`, or `static` for item declaration L = M; } -trait D { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration +trait D { //~ ERROR missing `fn`, `type`, `const`, or `static` for item declaration Z = { 2 + 3 }; } trait E { diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 072e61f6a3cd1..119e30a3e0f57 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,26 +1,26 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-40006.rs:1:13 | LL | impl dyn A { | _____________^ LL | | Y - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-40006.rs:7:10 | LL | trait X { | __________^ LL | | X() {} - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-40006.rs:15:10 | LL | trait A { | __________^ LL | | X() {} - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` error: expected `[`, found `#` --> $DIR/issue-40006.rs:19:17 @@ -28,21 +28,21 @@ error: expected `[`, found `#` LL | fn xxx() { ### } | ^ expected `[` -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-40006.rs:21:10 | LL | trait C { | __________^ LL | | L = M; - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-40006.rs:24:10 | LL | trait D { | __________^ LL | | Z = { 2 + 3 }; - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` error: expected one of `!` or `::`, found `(` --> $DIR/issue-40006.rs:28:9 @@ -50,11 +50,11 @@ error: expected one of `!` or `::`, found `(` LL | ::Y (); | ^ expected one of `!` or `::` -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-40006.rs:32:8 | LL | pub hello_method(&self) { - | ^ missing `fn`, `type`, or `const` + | ^ missing `fn`, `type`, `const`, or `static` error[E0599]: no method named `hello_method` found for struct `S` in the current scope --> $DIR/issue-40006.rs:38:7 diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs index a70163df1cb93..5570f081b157d 100644 --- a/src/test/ui/macros/issue-54441.rs +++ b/src/test/ui/macros/issue-54441.rs @@ -1,5 +1,5 @@ macro_rules! m { - //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration + //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration () => { let }; diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index 761e7aec7235a..5857aacb43176 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,11 +1,11 @@ -error: missing `fn`, `type`, or `static` for extern-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-54441.rs:1:1 | LL | / macro_rules! m { LL | | LL | | () => { LL | | let - | |________^ missing `fn`, `type`, or `static` + | |________^ missing `fn`, `type`, `const`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/default.rs b/src/test/ui/parser/default.rs index 65ecb1ebbe919..50952eef22f5c 100644 --- a/src/test/ui/parser/default.rs +++ b/src/test/ui/parser/default.rs @@ -20,7 +20,7 @@ impl Foo for u16 { impl Foo for u32 { //~ ERROR not all trait items implemented, missing: `foo` default pub fn foo() -> T { T::default() } - //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration + //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration } fn main() {} diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index ede9e47151863..07b051ece2b5d 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -1,8 +1,8 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/default.rs:22:12 | LL | default pub fn foo() -> T { T::default() } - | ^ missing `fn`, `type`, or `const` + | ^ missing `fn`, `type`, `const`, or `static` error[E0449]: unnecessary visibility qualifier --> $DIR/default.rs:16:5 diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs index 1d271fa64b0ec..f6e7f7e6abe8f 100644 --- a/src/test/ui/parser/duplicate-visibility.rs +++ b/src/test/ui/parser/duplicate-visibility.rs @@ -2,5 +2,5 @@ fn main() {} extern { pub pub fn foo(); - //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration + //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index 36a3a1ed5a0cc..398ba65c9e1d8 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,8 +1,8 @@ -error: missing `fn`, `type`, or `static` for extern-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/duplicate-visibility.rs:4:8 | LL | pub pub fn foo(); - | ^ missing `fn`, `type`, or `static` + | ^ missing `fn`, `type`, `const`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/extern-no-fn.rs b/src/test/ui/parser/extern-no-fn.rs index c37ddd69ce53c..dc47f7410730c 100644 --- a/src/test/ui/parser/extern-no-fn.rs +++ b/src/test/ui/parser/extern-no-fn.rs @@ -1,4 +1,5 @@ -extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration +extern { +//~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration f(); } diff --git a/src/test/ui/parser/extern-no-fn.stderr b/src/test/ui/parser/extern-no-fn.stderr index d2d5e3c46874a..8d55eefc8d0ec 100644 --- a/src/test/ui/parser/extern-no-fn.stderr +++ b/src/test/ui/parser/extern-no-fn.stderr @@ -1,10 +1,11 @@ -error: missing `fn`, `type`, or `static` for extern-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/extern-no-fn.rs:1:9 | LL | extern { | _________^ +LL | | LL | | f(); - | |____^ missing `fn`, `type`, or `static` + | |____^ missing `fn`, `type`, `const`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs index 982a6be23ac5f..014c930ef8205 100644 --- a/src/test/ui/parser/issue-19398.rs +++ b/src/test/ui/parser/issue-19398.rs @@ -1,5 +1,5 @@ trait T { - //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration + //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration extern "Rust" unsafe fn foo(); } diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr index 2bd6ac3a4b3a4..b38b39f9bd99f 100644 --- a/src/test/ui/parser/issue-19398.stderr +++ b/src/test/ui/parser/issue-19398.stderr @@ -1,11 +1,11 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-19398.rs:1:10 | LL | trait T { | __________^ LL | | LL | | extern "Rust" unsafe fn foo(); - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-21153.rs b/src/test/ui/parser/issue-21153.rs index 46cd45f28b43d..4fe05e6f04155 100644 --- a/src/test/ui/parser/issue-21153.rs +++ b/src/test/ui/parser/issue-21153.rs @@ -1,4 +1,5 @@ -trait MyTrait: Iterator { //~ ERROR missing `fn`, `type`, or `const` +trait MyTrait: Iterator { + //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration Item = T; } diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr index 6e20a9ce3c432..e9824bd729081 100644 --- a/src/test/ui/parser/issue-21153.stderr +++ b/src/test/ui/parser/issue-21153.stderr @@ -1,10 +1,11 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/issue-21153.rs:1:29 | LL | trait MyTrait: Iterator { | _____________________________^ +LL | | LL | | Item = T; - | |____^ missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, `const`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs index 592215030f552..748db8983b595 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs @@ -3,7 +3,7 @@ fn main() {} impl T for () { //~ ERROR cannot find trait `T` in this scope fn foo(&self) {} -//~^ ERROR missing `fn`, `type`, or `const` +//~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration trait T { fn foo(&self); diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr index 1ec54525105f6..240be39eacef4 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr @@ -7,7 +7,7 @@ LL | impl T for () { LL | | ^ -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/missing-close-brace-in-impl-trait.rs:5:17 | LL | fn foo(&self) {} @@ -15,7 +15,7 @@ LL | fn foo(&self) {} LL | | LL | | LL | | trait T { - | |_ missing `fn`, `type`, or `const` + | |_ missing `fn`, `type`, `const`, or `static` error[E0405]: cannot find trait `T` in this scope --> $DIR/missing-close-brace-in-impl-trait.rs:3:6 diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs index 077e334719427..4e8cc6489bc64 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs @@ -3,7 +3,7 @@ trait T { fn foo(&self); pub(crate) struct Bar(); -//~^ ERROR missing `fn`, `type`, or `const` +//~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration impl T for Bar { fn foo(&self) {} diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr index 1bb153c461d90..54afad5755b15 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -7,11 +7,11 @@ LL | trait T { LL | fn main() {} | ^ -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn`, `type`, `const`, or `static` for item declaration --> $DIR/missing-close-brace-in-trait.rs:5:11 | LL | pub(crate) struct Bar(); - | ^ missing `fn`, `type`, or `const` + | ^ missing `fn`, `type`, `const`, or `static` error[E0601]: `main` function not found in crate `missing_close_brace_in_trait` --> $DIR/missing-close-brace-in-trait.rs:1:1 From cf87edfdc5f2b44c7e379270a2b8b92464cb7cdb Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 18:28:47 +0100 Subject: [PATCH 13/25] pprust: unify extern & associated item printing --- src/librustc_ast_pretty/pprust.rs | 62 ++++++++++++++----------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 410600e495778..0eea64dfe734d 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -912,7 +912,7 @@ impl<'a> State<'a> { } } - crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) { + crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[Attribute]) { self.print_inner_attributes(attrs); for item in &nmod.items { self.print_foreign_item(item); @@ -1016,21 +1016,37 @@ impl<'a> State<'a> { } crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + let ast::ForeignItem { id, span, ident, attrs, kind, vis, tokens: _ } = item; + self.print_nested_item_kind(*id, *span, *ident, attrs, ast::Defaultness::Final, kind, vis); + } + + fn print_nested_item_kind( + &mut self, + id: ast::NodeId, + span: Span, + ident: ast::Ident, + attrs: &[Attribute], + defaultness: ast::Defaultness, + kind: &ast::AssocItemKind, + vis: &ast::Visibility, + ) { + self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); - self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(&item.attrs); - match &item.kind { + self.maybe_print_comment(span.lo()); + self.print_outer_attributes(attrs); + self.print_defaultness(defaultness); + match kind { ast::ForeignItemKind::Fn(sig, gen, body) => { - self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); + self.print_fn_full(sig, ident, gen, vis, body.as_deref(), attrs); } ast::ForeignItemKind::Const(ty, body) => { - self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis); + self.print_item_const(ident, None, ty, body.as_deref(), vis); } ast::ForeignItemKind::Static(ty, mutbl, body) => { - self.print_item_const(item.ident, Some(*mutbl), ty, body.as_deref(), &item.vis); + self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis); } ast::ForeignItemKind::TyAlias(generics, bounds, ty) => { - self.print_associated_type(item.ident, generics, bounds, ty.as_deref()); + self.print_associated_type(ident, generics, bounds, ty.as_deref()); } ast::ForeignItemKind::Macro(m) => { self.print_mac(m); @@ -1039,6 +1055,7 @@ impl<'a> State<'a> { } } } + self.ann.post(self, AnnNode::SubItem(id)) } fn print_item_const( @@ -1438,33 +1455,8 @@ impl<'a> State<'a> { } crate fn print_assoc_item(&mut self, item: &ast::AssocItem) { - self.ann.pre(self, AnnNode::SubItem(item.id)); - self.hardbreak_if_not_bol(); - self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(&item.attrs); - self.print_defaultness(item.defaultness); - match &item.kind { - ast::AssocItemKind::Static(ty, mutbl, expr) => { - self.print_item_const(item.ident, Some(*mutbl), ty, expr.as_deref(), &item.vis); - } - ast::AssocItemKind::Const(ty, expr) => { - self.print_item_const(item.ident, None, ty, expr.as_deref(), &item.vis); - } - ast::AssocItemKind::Fn(sig, generics, body) => { - let body = body.as_deref(); - self.print_fn_full(sig, item.ident, generics, &item.vis, body, &item.attrs); - } - ast::AssocItemKind::TyAlias(generics, bounds, ty) => { - self.print_associated_type(item.ident, generics, bounds, ty.as_deref()); - } - ast::AssocItemKind::Macro(mac) => { - self.print_mac(mac); - if mac.args.need_semicolon() { - self.s.word(";"); - } - } - } - self.ann.post(self, AnnNode::SubItem(item.id)) + let ast::AssocItem { id, span, ident, attrs, defaultness, kind, vis, tokens: _ } = item; + self.print_nested_item_kind(*id, *span, *ident, attrs, *defaultness, kind, vis); } crate fn print_stmt(&mut self, st: &ast::Stmt) { From 5abedd81e04dc1b76db423ca351ef5d3056a6f97 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 18:42:43 +0100 Subject: [PATCH 14/25] visit: unify extern & assoc item visiting --- src/libsyntax/mut_visit.rs | 39 +++++++++---------------- src/libsyntax/visit.rs | 59 +++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 58 deletions(-) diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index ffc42340dba64..1fa6cce2c6284 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -949,6 +949,19 @@ pub fn noop_flat_map_assoc_item( ) -> SmallVec<[P; 1]> { let AssocItem { id, ident, vis, defaultness: _, attrs, kind, span, tokens: _ } = item.deref_mut(); + walk_nested_item(visitor, id, span, ident, vis, attrs, kind); + smallvec![item] +} + +pub fn walk_nested_item( + visitor: &mut impl MutVisitor, + id: &mut NodeId, + span: &mut Span, + ident: &mut Ident, + vis: &mut Visibility, + attrs: &mut Vec, + kind: &mut AssocItemKind, +) { visitor.visit_id(id); visitor.visit_ident(ident); visitor.visit_vis(vis); @@ -971,8 +984,6 @@ pub fn noop_flat_map_assoc_item( AssocItemKind::Macro(mac) => visitor.visit_mac(mac), } visitor.visit_span(span); - - smallvec![item] } pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { @@ -1038,29 +1049,7 @@ pub fn noop_flat_map_foreign_item( visitor: &mut T, ) -> SmallVec<[P; 1]> { let ForeignItem { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut(); - visitor.visit_ident(ident); - visit_attrs(attrs, visitor); - match kind { - ForeignItemKind::Fn(sig, generics, body) => { - visit_fn_sig(sig, visitor); - visitor.visit_generics(generics); - visit_opt(body, |body| visitor.visit_block(body)); - } - ForeignItemKind::Const(ty, body) | ForeignItemKind::Static(ty, _, body) => { - visitor.visit_ty(ty); - visit_opt(body, |body| visitor.visit_expr(body)); - } - ForeignItemKind::TyAlias(generics, bounds, ty) => { - visitor.visit_generics(generics); - visit_bounds(bounds, visitor); - visit_opt(ty, |ty| visitor.visit_ty(ty)); - } - ForeignItemKind::Macro(mac) => visitor.visit_mac(mac), - } - visitor.visit_id(id); - visitor.visit_span(span); - visitor.visit_vis(vis); - + walk_nested_item(visitor, id, span, ident, vis, attrs, kind); smallvec![item] } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5a21eb55528d0..448ed0ba3de57 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -525,29 +525,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) { - visitor.visit_vis(&item.vis); - visitor.visit_ident(item.ident); - - match item.kind { - ForeignItemKind::Fn(ref sig, ref generics, ref body) => { - visitor.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref()); - visitor.visit_fn(kind, item.span, item.id); - } - ForeignItemKind::Const(ref typ, ref body) - | ForeignItemKind::Static(ref typ, _, ref body) => { - visitor.visit_ty(typ); - walk_list!(visitor, visit_expr, body); - } - ForeignItemKind::TyAlias(ref generics, ref bounds, ref ty) => { - visitor.visit_generics(generics); - walk_list!(visitor, visit_param_bound, bounds); - walk_list!(visitor, visit_ty, ty); - } - ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), - } - - walk_list!(visitor, visit_attribute, &item.attrs); + let ForeignItem { id, span, ident, vis, attrs, kind, tokens: _ } = item; + walk_nested_item(visitor, *id, *span, *ident, vis, attrs, kind, FnCtxt::Foreign); } pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { @@ -630,25 +609,39 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa } pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) { - visitor.visit_vis(&item.vis); - visitor.visit_ident(item.ident); - walk_list!(visitor, visit_attribute, &item.attrs); - match item.kind { - AssocItemKind::Const(ref ty, ref expr) | AssocItemKind::Static(ref ty, _, ref expr) => { + let AssocItem { id, span, ident, vis, attrs, kind, tokens: _, defaultness: _ } = item; + walk_nested_item(visitor, *id, *span, *ident, vis, attrs, kind, FnCtxt::Assoc(ctxt)); +} + +fn walk_nested_item<'a, V: Visitor<'a>>( + visitor: &mut V, + id: NodeId, + span: Span, + ident: Ident, + vis: &'a Visibility, + attrs: &'a [Attribute], + kind: &'a AssocItemKind, + ctxt: FnCtxt, +) { + visitor.visit_vis(vis); + visitor.visit_ident(ident); + walk_list!(visitor, visit_attribute, attrs); + match kind { + AssocItemKind::Const(ty, expr) | AssocItemKind::Static(ty, _, expr) => { visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } - AssocItemKind::Fn(ref sig, ref generics, ref body) => { + AssocItemKind::Fn(sig, generics, body) => { visitor.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); - visitor.visit_fn(kind, item.span, item.id); + let kind = FnKind::Fn(ctxt, ident, sig, vis, body.as_deref()); + visitor.visit_fn(kind, span, id); } - AssocItemKind::TyAlias(ref generics, ref bounds, ref ty) => { + AssocItemKind::TyAlias(generics, bounds, ty) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, ty); } - AssocItemKind::Macro(ref mac) => { + AssocItemKind::Macro(mac) => { visitor.visit_mac(mac); } } From d6238bd8d4fe283968abbf46357c8e56f283b65b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 22:21:00 +0100 Subject: [PATCH 15/25] reject assoc statics & extern consts during parsing --- src/librustc_ast_passes/ast_validation.rs | 28 +------ src/librustc_parse/parser/item.rs | 27 ++++++- src/test/ui/extern/extern-const.stderr | 2 - .../parser/assoc-static-semantic-fail.stderr | 44 +++++------ .../ui/parser/assoc-static-syntactic-fail.rs | 27 +++++++ .../parser/assoc-static-syntactic-fail.stderr | 74 +++++++++++++++++++ .../ui/parser/assoc-static-syntactic-pass.rs | 29 -------- .../parser/foreign-const-semantic-fail.stderr | 5 -- .../ui/parser/foreign-const-syntactic-fail.rs | 9 +++ .../foreign-const-syntactic-fail.stderr | 22 ++++++ .../ui/parser/foreign-const-syntactic-pass.rs | 11 --- 11 files changed, 183 insertions(+), 95 deletions(-) create mode 100644 src/test/ui/parser/assoc-static-syntactic-fail.rs create mode 100644 src/test/ui/parser/assoc-static-syntactic-fail.stderr delete mode 100644 src/test/ui/parser/assoc-static-syntactic-pass.rs create mode 100644 src/test/ui/parser/foreign-const-syntactic-fail.rs create mode 100644 src/test/ui/parser/foreign-const-syntactic-fail.stderr delete mode 100644 src/test/ui/parser/foreign-const-syntactic-pass.rs diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 8efd50ad0987e..d3fcb589fd0ff 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -533,20 +533,6 @@ impl<'a> AstValidator<'a> { } } - fn error_foreign_const(&self, ident: Ident, span: Span) { - self.err_handler() - .struct_span_err(ident.span, "extern items cannot be `const`") - .span_suggestion( - span.with_hi(ident.span.lo()), - "try using a static value", - "static ".to_string(), - Applicability::MachineApplicable, - ) - .span_label(self.current_extern_span(), "in this `extern` block") - .note(MORE_EXTERN) - .emit(); - } - /// Reject C-varadic type unless the function is foreign, /// or free and `unsafe extern "C"` semantically. fn check_c_varadic_type(&self, fk: FnKind<'a>) { @@ -1003,10 +989,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ForeignItemKind::Static(_, _, body) => { self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); } - ForeignItemKind::Const(..) => { - self.error_foreign_const(fi.ident, fi.span); - } - ForeignItemKind::Macro(..) => {} + ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {} } visit::walk_foreign_item(self, fi) @@ -1267,13 +1250,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - match item.kind { - AssocItemKind::Const(..) => self.check_item_named(item.ident, "const"), - AssocItemKind::Static(..) => self - .err_handler() - .struct_span_err(item.span, "associated `static` items are not allowed") - .emit(), - _ => {} + if let AssocItemKind::Const(..) = item.kind { + self.check_item_named(item.ident, "const"); } self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt)); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 20d6182ddc19b..da72da043650c 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -643,9 +643,16 @@ impl<'a> Parser<'a> { if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { item.tokens = Some(tokens); } + self.error_on_assoc_static(&item); Ok(P(item)) } + fn error_on_assoc_static(&self, item: &AssocItem) { + if let AssocItemKind::Static(..) = item.kind { + self.struct_span_err(item.span, "associated `static` items are not allowed").emit(); + } + } + fn parse_assoc_item_( &mut self, at_end: &mut bool, @@ -868,7 +875,25 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; let (ident, kind) = self.parse_assoc_item_kind(at_end, &mut attrs, |_| true, &vis)?; - Ok(P(self.mk_item(lo, ident, kind, vis, attrs))) + let item = self.mk_item(lo, ident, kind, vis, attrs); + self.error_on_foreign_const(&item); + Ok(P(item)) + } + + fn error_on_foreign_const(&self, item: &ForeignItem) { + if let AssocItemKind::Const(..) = item.kind { + self.struct_span_err(item.ident.span, "extern items cannot be `const`") + .span_suggestion( + item.span.with_hi(item.ident.span.lo()), + "try using a static value", + "static ".to_string(), + Applicability::MachineApplicable, + ) + .note( + "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html", + ) + .emit(); + } } fn is_static_global(&mut self) -> bool { diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr index 97e11381c6f78..7f67adbdb19c7 100644 --- a/src/test/ui/extern/extern-const.stderr +++ b/src/test/ui/extern/extern-const.stderr @@ -1,8 +1,6 @@ error: extern items cannot be `const` --> $DIR/extern-const.rs:16:11 | -LL | extern "C" { - | ---------- in this `extern` block LL | const rust_dbg_static_mut: libc::c_int; | ------^^^^^^^^^^^^^^^^^^^ | | diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr index d5a02c9bebcf0..d02e2855c7e62 100644 --- a/src/test/ui/parser/assoc-static-semantic-fail.stderr +++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr @@ -34,30 +34,12 @@ error: associated `static` items are not allowed LL | static TB: u8; | ^^^^^^^^^^^^^^ -error: `default` is only allowed on items in `impl` definitions - --> $DIR/assoc-static-semantic-fail.rs:24:5 - | -LL | default static TC: u8 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: associated `static` items are not allowed --> $DIR/assoc-static-semantic-fail.rs:24:5 | LL | default static TC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `default` is only allowed on items in `impl` definitions - --> $DIR/assoc-static-semantic-fail.rs:27:5 - | -LL | pub(crate) default static TD: u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0449]: unnecessary visibility qualifier - --> $DIR/assoc-static-semantic-fail.rs:27:5 - | -LL | pub(crate) default static TD: u8; - | ^^^^^^^^^^ - error: associated `static` items are not allowed --> $DIR/assoc-static-semantic-fail.rs:27:5 | @@ -82,17 +64,35 @@ error: associated `static` items are not allowed LL | default static TC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0449]: unnecessary visibility qualifier +error: associated `static` items are not allowed --> $DIR/assoc-static-semantic-fail.rs:40:5 | LL | pub default static TD: u8; - | ^^^ `pub` not permitted here because it's implied + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: associated `static` items are not allowed +error: `default` is only allowed on items in `impl` definitions + --> $DIR/assoc-static-semantic-fail.rs:24:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/assoc-static-semantic-fail.rs:27:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0449]: unnecessary visibility qualifier + --> $DIR/assoc-static-semantic-fail.rs:27:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^ + +error[E0449]: unnecessary visibility qualifier --> $DIR/assoc-static-semantic-fail.rs:40:5 | LL | pub default static TD: u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ `pub` not permitted here because it's implied error: aborting due to 16 previous errors diff --git a/src/test/ui/parser/assoc-static-syntactic-fail.rs b/src/test/ui/parser/assoc-static-syntactic-fail.rs new file mode 100644 index 0000000000000..8f042767e5503 --- /dev/null +++ b/src/test/ui/parser/assoc-static-syntactic-fail.rs @@ -0,0 +1,27 @@ +// Syntactically, we do allow e.g., `static X: u8 = 0;` as an associated item. + +fn main() {} + +#[cfg(FALSE)] +impl S { + static IA: u8 = 0; //~ ERROR associated `static` items are not allowed + static IB: u8; //~ ERROR associated `static` items are not allowed + default static IC: u8 = 0; //~ ERROR associated `static` items are not allowed + pub(crate) default static ID: u8; //~ ERROR associated `static` items are not allowed +} + +#[cfg(FALSE)] +trait T { + static TA: u8 = 0; //~ ERROR associated `static` items are not allowed + static TB: u8; //~ ERROR associated `static` items are not allowed + default static TC: u8 = 0; //~ ERROR associated `static` items are not allowed + pub(crate) default static TD: u8; //~ ERROR associated `static` items are not allowed +} + +#[cfg(FALSE)] +impl T for S { + static TA: u8 = 0; //~ ERROR associated `static` items are not allowed + static TB: u8; //~ ERROR associated `static` items are not allowed + default static TC: u8 = 0; //~ ERROR associated `static` items are not allowed + pub default static TD: u8; //~ ERROR associated `static` items are not allowed +} diff --git a/src/test/ui/parser/assoc-static-syntactic-fail.stderr b/src/test/ui/parser/assoc-static-syntactic-fail.stderr new file mode 100644 index 0000000000000..bb1e5c4be2e9c --- /dev/null +++ b/src/test/ui/parser/assoc-static-syntactic-fail.stderr @@ -0,0 +1,74 @@ +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:7:5 + | +LL | static IA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:8:5 + | +LL | static IB: u8; + | ^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:9:5 + | +LL | default static IC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:10:5 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:15:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:16:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:17:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:18:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:23:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:24:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:25:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:26:5 + | +LL | pub default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/parser/assoc-static-syntactic-pass.rs b/src/test/ui/parser/assoc-static-syntactic-pass.rs deleted file mode 100644 index 7f5b9f7933563..0000000000000 --- a/src/test/ui/parser/assoc-static-syntactic-pass.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Syntactically, we do allow e.g., `static X: u8 = 0;` as an associated item. - -// check-pass - -fn main() {} - -#[cfg(FALSE)] -impl S { - static IA: u8 = 0; - static IB: u8; - default static IC: u8 = 0; - pub(crate) default static ID: u8; -} - -#[cfg(FALSE)] -trait T { - static TA: u8 = 0; - static TB: u8; - default static TC: u8 = 0; - pub(crate) default static TD: u8; -} - -#[cfg(FALSE)] -impl T for S { - static TA: u8 = 0; - static TB: u8; - default static TC: u8 = 0; - pub default static TD: u8; -} diff --git a/src/test/ui/parser/foreign-const-semantic-fail.stderr b/src/test/ui/parser/foreign-const-semantic-fail.stderr index 799a795c5939a..f364f11bb038d 100644 --- a/src/test/ui/parser/foreign-const-semantic-fail.stderr +++ b/src/test/ui/parser/foreign-const-semantic-fail.stderr @@ -1,8 +1,6 @@ error: extern items cannot be `const` --> $DIR/foreign-const-semantic-fail.rs:4:11 | -LL | extern { - | ------ in this `extern` block LL | const A: isize; | ------^ | | @@ -13,9 +11,6 @@ LL | const A: isize; error: extern items cannot be `const` --> $DIR/foreign-const-semantic-fail.rs:6:11 | -LL | extern { - | ------ in this `extern` block -... LL | const B: isize = 42; | ------^ | | diff --git a/src/test/ui/parser/foreign-const-syntactic-fail.rs b/src/test/ui/parser/foreign-const-syntactic-fail.rs new file mode 100644 index 0000000000000..a78f8b1623a80 --- /dev/null +++ b/src/test/ui/parser/foreign-const-syntactic-fail.rs @@ -0,0 +1,9 @@ +// Syntactically, a `const` item inside an `extern { ... }` block is not allowed. + +fn main() {} + +#[cfg(FALSE)] +extern { + const A: isize; //~ ERROR extern items cannot be `const` + const B: isize = 42; //~ ERROR extern items cannot be `const` +} diff --git a/src/test/ui/parser/foreign-const-syntactic-fail.stderr b/src/test/ui/parser/foreign-const-syntactic-fail.stderr new file mode 100644 index 0000000000000..9cf58fa95fb2d --- /dev/null +++ b/src/test/ui/parser/foreign-const-syntactic-fail.stderr @@ -0,0 +1,22 @@ +error: extern items cannot be `const` + --> $DIR/foreign-const-syntactic-fail.rs:7:11 + | +LL | const A: isize; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: extern items cannot be `const` + --> $DIR/foreign-const-syntactic-fail.rs:8:11 + | +LL | const B: isize = 42; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/foreign-const-syntactic-pass.rs b/src/test/ui/parser/foreign-const-syntactic-pass.rs deleted file mode 100644 index bacef8e71d62e..0000000000000 --- a/src/test/ui/parser/foreign-const-syntactic-pass.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Syntactically, a `const` item inside an `extern { ... }` block is allowed. - -// check-pass - -fn main() {} - -#[cfg(FALSE)] -extern { - const A: isize; - const B: isize = 42; -} From fe62bed73b0ef9fe63faa2a56653f3c7fa17f7c2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 22:33:21 +0100 Subject: [PATCH 16/25] print_item_const: remove extraneous space --- src/librustc_ast_pretty/pprust.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 0eea64dfe734d..2f712964a84cb 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1067,9 +1067,9 @@ impl<'a> State<'a> { vis: &ast::Visibility, ) { let leading = match mutbl { - None => "const ", - Some(ast::Mutability::Not) => "static ", - Some(ast::Mutability::Mut) => "static mut ", + None => "const", + Some(ast::Mutability::Not) => "static", + Some(ast::Mutability::Mut) => "static mut", }; self.head(visibility_qualified(vis, leading)); self.print_ident(ident); From f12ae4ac608362264470eda9b1d67236bae62040 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 15 Feb 2020 22:36:03 +0100 Subject: [PATCH 17/25] ast: tweak AssocItemKind::Macro comment --- src/libsyntax/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a931d8c27ba83..8154ae2f307bc 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2637,6 +2637,6 @@ pub enum AssocItemKind { Fn(FnSig, Generics, Option>), /// A type. TyAlias(Generics, GenericBounds, Option>), - /// A macro expanding to an item. + /// A macro expanding to items. Macro(Mac), } From 8bafe883b6bb273b7a256d7720e638b267c2e574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 13 Feb 2020 22:45:48 -0800 Subject: [PATCH 18/25] Select an appropriate unused lifetime name in suggestion --- src/librustc_typeck/collect.rs | 50 ++++++++++++++++--- ...iated-types-project-from-hrtb-in-struct.rs | 11 +++- ...d-types-project-from-hrtb-in-struct.stderr | 23 +++++++-- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 80d914d8d0ae5..ca3bcac1206be 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -33,7 +33,7 @@ use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -369,10 +369,12 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { hir::ItemKind::Enum(_, generics) | hir::ItemKind::Struct(_, generics) | hir::ItemKind::Union(_, generics) => { - // FIXME: look for an appropriate lt name if `'a` is already used + let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics); let (lt_sp, sugg) = match &generics.params[..] { - [] => (generics.span, "<'a>".to_string()), - [bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()), + [] => (generics.span, format!("<{}>", lt_name)), + [bound, ..] => { + (bound.span.shrink_to_lo(), format!("{}, ", lt_name)) + } }; let suggestions = vec![ (lt_sp, sugg), @@ -387,7 +389,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { ty::EarlyBoundRegion { def_id: item_def_id, index: 0, - name: Symbol::intern("'a"), + name: Symbol::intern(<_name), }, )) }) @@ -445,6 +447,43 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } +/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. +fn get_new_lifetime_name<'tcx>( + tcx: TyCtxt<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + generics: &hir::Generics<'tcx>, +) -> String { + let existing_lifetimes = tcx + .collect_referenced_late_bound_regions(&poly_trait_ref) + .into_iter() + .filter_map(|lt| { + if let ty::BoundRegion::BrNamed(_, name) = lt { + Some(name.as_str().to_string()) + } else { + None + } + }) + .chain(generics.params.iter().filter_map(|param| { + if let hir::GenericParamKind::Lifetime { .. } = ¶m.kind { + Some(param.name.ident().as_str().to_string()) + } else { + None + } + })) + .collect::>(); + + let a_to_z_repeat_n = |n| { + (b'a'..=b'z').map(move |c| { + let mut s = format!("'"); + s.extend(std::iter::repeat(char::from(c)).take(n)); + s + }) + }; + + // If all single char lifetime names are present, we wrap around and double the chars. + (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap() +} + /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( @@ -1588,7 +1627,6 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - use rustc_data_structures::fx::FxHashSet; use rustc_hir::*; debug!("explicit_predicates_of(def_id={:?})", def_id); diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs index 8a5777d4d7cb5..58f186d7775ea 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs @@ -12,11 +12,12 @@ struct SomeStruct Foo<&'x isize>> { //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } -enum SomeEnum Foo<&'x isize>> { +enum SomeEnum<'b, I: for<'a> Foo<&'a isize>> { TupleVariant(I::A), //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context StructVariant { field: I::A }, //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + OkVariant(&'b usize), } // FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. @@ -26,7 +27,13 @@ enum SomeEnum Foo<&'x isize>> { // } struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> { - field: >::A + field: >::A, +} + +struct Why<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, + 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { + field: I::A, + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index c71bc70ea6c4e..e3fd2860ebcf3 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -18,8 +18,8 @@ LL | TupleVariant(I::A), | help: use a fully qualified path with explicit lifetimes | -LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { -LL | TupleVariant(>::A), +LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { +LL | TupleVariant(>::A), | error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context @@ -30,11 +30,24 @@ LL | StructVariant { field: I::A }, | help: use a fully qualified path with explicit lifetimes | -LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { LL | TupleVariant(I::A), LL | -LL | StructVariant { field: >::A }, +LL | StructVariant { field: >::A }, | -error: aborting due to 3 previous errors +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:35:12 + | +LL | field: I::A, + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | struct Why<'bb, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, +LL | 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { +LL | field: >::A, + | + +error: aborting due to 4 previous errors From 045b7d53a3fe94d2f6cb32d029a3f5d74e174ed9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 17 Feb 2020 11:16:28 +0100 Subject: [PATCH 19/25] ast: add a FIXME --- src/libsyntax/ast.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8154ae2f307bc..a73142406153a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2600,6 +2600,8 @@ impl ItemKind { } } +// FIXME(Centril): These definitions should be unmerged; +// see https://github.com/rust-lang/rust/pull/69194#discussion_r379899975 pub type ForeignItem = Item; pub type ForeignItemKind = AssocItemKind; From 2e07892c7dd71f2025b68dcf8c144d53b3560511 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 16 Feb 2020 21:42:37 +0100 Subject: [PATCH 20/25] Do not emit note suggesting to implement trait to foreign type Update tests Extend to other operations Refractor check in a separate function Fix more tests --- src/librustc_typeck/check/op.rs | 33 ++++++++++--------- src/test/ui/autoderef-full-lval.stderr | 4 --- src/test/ui/binop/binop-bitxor-str.stderr | 2 -- src/test/ui/binop/binop-mul-bool.stderr | 2 -- src/test/ui/binop/binop-typeck.stderr | 2 -- .../core-traits-no-impls-length-33.stderr | 4 --- .../note-unsupported.stderr | 4 --- src/test/ui/error-codes/E0067.stderr | 2 -- src/test/ui/error-festival.stderr | 2 -- src/test/ui/for/for-loop-type-error.stderr | 2 -- src/test/ui/issues/issue-14915.stderr | 2 -- src/test/ui/issues/issue-24363.stderr | 2 -- src/test/ui/issues/issue-31076.stderr | 4 --- src/test/ui/issues/issue-35668.stderr | 2 -- src/test/ui/issues/issue-40610.stderr | 2 -- src/test/ui/issues/issue-41394.stderr | 2 -- src/test/ui/issues/issue-59488.stderr | 3 -- src/test/ui/minus-string.stderr | 2 -- src/test/ui/pattern/pattern-tyvar-2.stderr | 2 -- .../disallowed-positions.stderr | 6 ---- src/test/ui/span/issue-39018.stderr | 4 --- .../trait-resolution-in-overloaded-op.stderr | 2 -- src/test/ui/unop-neg-bool.stderr | 2 -- src/test/ui/vec/vec-res-add.stderr | 2 -- 24 files changed, 17 insertions(+), 77 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 86b00c2f0d3f0..bb31e979b733f 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -5,7 +5,7 @@ use super::{FnCtxt, Needs}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint}; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc_errors::{self, struct_span_err, Applicability}; +use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::Span; @@ -321,11 +321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, missing_trait )); } else if !suggested_deref { - err.note(&format!( - "an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty - )); + suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } } err.emit(); @@ -467,11 +463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, missing_trait )); } else if !suggested_deref && !involves_fn { - err.note(&format!( - "an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty - )); + suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } } err.emit(); @@ -707,11 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::UnNot => "std::ops::Not", hir::UnOp::UnDeref => "std::ops::UnDerf", }; - err.note(&format!( - "an implementation of `{}` might \ - be missing for `{}`", - missing_trait, operand_ty - )); + suggest_impl_missing(&mut err, operand_ty, &missing_trait); } } err.emit(); @@ -929,3 +917,16 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool } } } + +/// If applicable, note that an implementation of `trait` for `ty` may fix the error. +fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) { + if let Adt(def, _) = ty.peel_refs().kind { + if def.did.is_local() { + err.note(&format!( + "an implementation of `{}` might \ + be missing for `{}`", + missing_trait, ty + )); + } + } +} diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr index e2870ef8062d3..f094388794eda 100644 --- a/src/test/ui/autoderef-full-lval.stderr +++ b/src/test/ui/autoderef-full-lval.stderr @@ -5,8 +5,6 @@ LL | let z: isize = a.x + b.y; | --- ^ --- std::boxed::Box | | | std::boxed::Box - | - = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error[E0369]: cannot add `std::boxed::Box` to `std::boxed::Box` --> $DIR/autoderef-full-lval.rs:21:33 @@ -15,8 +13,6 @@ LL | let answer: isize = forty.a + two.a; | ------- ^ ----- std::boxed::Box | | | std::boxed::Box - | - = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr index 9a0d301d86356..18c1ce0ff02e1 100644 --- a/src/test/ui/binop/binop-bitxor-str.stderr +++ b/src/test/ui/binop/binop-bitxor-str.stderr @@ -5,8 +5,6 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } | --------------- ^ --------------- std::string::String | | | std::string::String - | - = note: an implementation of `std::ops::BitXor` might be missing for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/binop/binop-mul-bool.stderr b/src/test/ui/binop/binop-mul-bool.stderr index ade2202558934..859c44a859e85 100644 --- a/src/test/ui/binop/binop-mul-bool.stderr +++ b/src/test/ui/binop/binop-mul-bool.stderr @@ -5,8 +5,6 @@ LL | fn main() { let x = true * false; } | ---- ^ ----- bool | | | bool - | - = note: an implementation of `std::ops::Mul` might be missing for `bool` error: aborting due to previous error diff --git a/src/test/ui/binop/binop-typeck.stderr b/src/test/ui/binop/binop-typeck.stderr index ebf82079ef2e8..42d910819995a 100644 --- a/src/test/ui/binop/binop-typeck.stderr +++ b/src/test/ui/binop/binop-typeck.stderr @@ -5,8 +5,6 @@ LL | let z = x + y; | - ^ - {integer} | | | bool - | - = note: an implementation of `std::ops::Add` might be missing for `bool` error: aborting due to previous error diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr index 781a179624e77..c03377d74e9b7 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr @@ -23,8 +23,6 @@ LL | [0_usize; 33] == [1_usize; 33] | ------------- ^^ ------------- [usize; 33] | | | [usize; 33] - | - = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]` error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]` --> $DIR/core-traits-no-impls-length-33.rs:19:19 @@ -33,8 +31,6 @@ LL | [0_usize; 33] < [1_usize; 33] | ------------- ^ ------------- [usize; 33] | | | [usize; 33] - | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]` error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied --> $DIR/core-traits-no-impls-length-33.rs:24:14 diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr index a6805c32a6e52..d4e25930d22d7 100644 --- a/src/test/ui/destructuring-assignment/note-unsupported.stderr +++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr @@ -16,8 +16,6 @@ LL | (a, b) += (3, 4); | ------^^^^^^^^^^ | | | cannot use `+=` on type `({integer}, {integer})` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `({integer}, {integer})` error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:7:12 @@ -48,8 +46,6 @@ LL | [a, b] += [3, 4]; | ------^^^^^^^^^^ | | | cannot use `+=` on type `[{integer}; 2]` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `[{integer}; 2]` error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:11:12 diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index 526503798b3d4..fad8270fd5ad2 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -5,8 +5,6 @@ LL | LinkedList::new() += 1; | -----------------^^^^^ | | | cannot use `+=` on type `std::collections::LinkedList<_>` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>` error[E0067]: invalid left-hand side of assignment --> $DIR/E0067.rs:4:23 diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 9b69b3733642b..fb5290bf64eb4 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -23,8 +23,6 @@ LL | x += 2; | -^^^^^ | | | cannot use `+=` on type `&str` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `&str` error[E0599]: no method named `z` found for reference `&str` in the current scope --> $DIR/error-festival.rs:16:7 diff --git a/src/test/ui/for/for-loop-type-error.stderr b/src/test/ui/for/for-loop-type-error.stderr index 0ed26384f4064..c93a3b9b25c15 100644 --- a/src/test/ui/for/for-loop-type-error.stderr +++ b/src/test/ui/for/for-loop-type-error.stderr @@ -5,8 +5,6 @@ LL | let x = () + (); | -- ^ -- () | | | () - | - = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr index 00b9909af5979..3c34a8a34673e 100644 --- a/src/test/ui/issues/issue-14915.stderr +++ b/src/test/ui/issues/issue-14915.stderr @@ -5,8 +5,6 @@ LL | println!("{}", x + 1); | - ^ - {integer} | | | std::boxed::Box - | - = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24363.stderr b/src/test/ui/issues/issue-24363.stderr index a60fb24ec1209..16537e21ae08c 100644 --- a/src/test/ui/issues/issue-24363.stderr +++ b/src/test/ui/issues/issue-24363.stderr @@ -11,8 +11,6 @@ LL | ()+() | --^-- () | | | () - | - = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index 5d65734cd230a..4c0e1cf7ebb0b 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -5,8 +5,6 @@ LL | let x = 5 + 6; | - ^ - {integer} | | | {integer} - | - = note: an implementation of `std::ops::Add` might be missing for `{integer}` error[E0369]: cannot add `i32` to `i32` --> $DIR/issue-31076.rs:15:18 @@ -15,8 +13,6 @@ LL | let y = 5i32 + 6i32; | ---- ^ ---- i32 | | | i32 - | - = note: an implementation of `std::ops::Add` might be missing for `i32` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr index 9d5796a5eefed..98e8e6366b99b 100644 --- a/src/test/ui/issues/issue-35668.stderr +++ b/src/test/ui/issues/issue-35668.stderr @@ -5,8 +5,6 @@ LL | a.iter().map(|a| a*a) | -^- &T | | | &T - | - = note: an implementation of `std::ops::Mul` might be missing for `&T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40610.stderr b/src/test/ui/issues/issue-40610.stderr index 95f45c168e122..b4e302dfffc7a 100644 --- a/src/test/ui/issues/issue-40610.stderr +++ b/src/test/ui/issues/issue-40610.stderr @@ -5,8 +5,6 @@ LL | () + f(&[1.0]); | -- ^ --------- () | | | () - | - = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41394.stderr b/src/test/ui/issues/issue-41394.stderr index 3f60ea4bbf73a..47a24547d4533 100644 --- a/src/test/ui/issues/issue-41394.stderr +++ b/src/test/ui/issues/issue-41394.stderr @@ -5,8 +5,6 @@ LL | A = "" + 1 | -- ^ - {integer} | | | &str - | - = note: an implementation of `std::ops::Add` might be missing for `&str` error[E0080]: evaluation of constant value failed --> $DIR/issue-41394.rs:7:9 diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr index 2ac5577e0a0ec..58f1376b19ddf 100644 --- a/src/test/ui/issues/issue-59488.stderr +++ b/src/test/ui/issues/issue-59488.stderr @@ -58,8 +58,6 @@ LL | foo > bar; | --- ^ --- fn(i64) -> i64 {bar} | | | fn() -> i32 {foo} - | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}` error[E0308]: mismatched types --> $DIR/issue-59488.rs:25:11 @@ -79,7 +77,6 @@ LL | assert_eq!(Foo::Bar, i); | fn(usize) -> Foo {Foo::Bar} | fn(usize) -> Foo {Foo::Bar} | - = note: an implementation of `std::cmp::PartialEq` might be missing for `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` diff --git a/src/test/ui/minus-string.stderr b/src/test/ui/minus-string.stderr index 9177082cf0b7d..3fbec7c89c9a2 100644 --- a/src/test/ui/minus-string.stderr +++ b/src/test/ui/minus-string.stderr @@ -3,8 +3,6 @@ error[E0600]: cannot apply unary operator `-` to type `std::string::String` | LL | fn main() { -"foo".to_string(); } | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr index bb3e61017d487..9566244464081 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.stderr +++ b/src/test/ui/pattern/pattern-tyvar-2.stderr @@ -5,8 +5,6 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; | - ^ - {integer} | | | std::vec::Vec - | - = note: an implementation of `std::ops::Mul` might be missing for `std::vec::Vec` error: aborting due to previous error diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 084f070989b6c..39874a6c680cd 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -560,8 +560,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/disallowed-positions.rs:46:8 @@ -748,8 +746,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/disallowed-positions.rs:110:11 @@ -927,8 +923,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/disallowed-positions.rs:183:5 diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 8a32561bd01db..8caa5bea4ac1e 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -136,8 +136,6 @@ LL | let _ = &c + &d; | -- ^ -- &&str | | | &&str - | - = note: an implementation of `std::ops::Add` might be missing for `&&str` error[E0369]: cannot add `&str` to `&&str` --> $DIR/issue-39018.rs:35:16 @@ -146,8 +144,6 @@ LL | let _ = &c + d; | -- ^ - &str | | | &&str - | - = note: an implementation of `std::ops::Add` might be missing for `&&str` error[E0369]: cannot add `&&str` to `&str` --> $DIR/issue-39018.rs:36:15 diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr index 8d7ba36c665b3..29216f36f5f31 100644 --- a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr +++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr @@ -5,8 +5,6 @@ LL | a * b | - ^ - f64 | | | &T - | - = note: an implementation of `std::ops::Mul` might be missing for `&T` error: aborting due to previous error diff --git a/src/test/ui/unop-neg-bool.stderr b/src/test/ui/unop-neg-bool.stderr index 182730137492b..9913747b88ee9 100644 --- a/src/test/ui/unop-neg-bool.stderr +++ b/src/test/ui/unop-neg-bool.stderr @@ -3,8 +3,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | -true; | ^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error: aborting due to previous error diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr index 1cc12a222e50b..2d41583268c4e 100644 --- a/src/test/ui/vec/vec-res-add.stderr +++ b/src/test/ui/vec/vec-res-add.stderr @@ -5,8 +5,6 @@ LL | let k = i + j; | - ^ - std::vec::Vec | | | std::vec::Vec - | - = note: an implementation of `std::ops::Add` might be missing for `std::vec::Vec` error: aborting due to previous error From 0b1e08cb557768f168266c7bbcdcb93fcf372a66 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 17 Feb 2020 16:03:07 +0100 Subject: [PATCH 21/25] parse: recover `mut (x @ y)` as `(mut x @ mut y)`. --- src/librustc_parse/parser/pat.rs | 29 +++++++++++-------------- src/test/ui/parser/mut-patterns.rs | 2 ++ src/test/ui/parser/mut-patterns.stderr | 30 ++++++++++++++++---------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index ec6d4db610285..520d325f16b61 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -503,17 +503,18 @@ impl<'a> Parser<'a> { // Parse the pattern we hope to be an identifier. let mut pat = self.parse_pat(Some("identifier"))?; - // Add `mut` to any binding in the parsed pattern. - let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); - - // Unwrap; If we don't have `mut $ident`, error. - let pat = pat.into_inner(); - match &pat.kind { - PatKind::Ident(..) => {} - _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding), + // If we don't have `mut $ident (@ pat)?`, error. + if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind { + // Don't recurse into the subpattern. + // `mut` on the outer binding doesn't affect the inner bindings. + *m = Mutability::Mut; + } else { + // Add `mut` to any binding in the parsed pattern. + let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); + self.ban_mut_general_pat(mut_span, &pat, changed_any_binding); } - Ok(pat.kind) + Ok(pat.into_inner().kind) } /// Recover on `mut ref? ident @ pat` and suggest @@ -542,14 +543,10 @@ impl<'a> Parser<'a> { } fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(ref mut bm, ..) = pat.kind { - if let BindingMode::ByValue(ref mut m @ Mutability::Not) = bm { - *m = Mutability::Mut; - } + if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind + { self.0 = true; - // Don't recurse into the subpattern, mut on the outer - // binding doesn't affect the inner bindings. - return; + *m = Mutability::Mut; } noop_visit_pat(pat, self); } diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index 66fd5893af5ee..8b83d6ab2f8c8 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -9,6 +9,8 @@ pub fn main() { let mut _ = 0; //~ ERROR `mut` must be followed by a named binding let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding + let mut (x @ y) = 0; //~ ERROR `mut` must be attached to each individual binding + let mut mut x = 0; //~^ ERROR `mut` on a binding may not be repeated //~| remove the additional `mut`s diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index 5f4c349d7d659..9a6af7394bf4a 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -14,14 +14,22 @@ LL | let mut (_, _) = (0, 0); | = note: `mut` may be followed by `variable` and `variable @ pattern` +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:12:9 + | +LL | let mut (x @ y) = 0; + | ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:12:13 + --> $DIR/mut-patterns.rs:14:13 | LL | let mut mut x = 0; | ^^^ help: remove the additional `mut`s error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:17:9 + --> $DIR/mut-patterns.rs:19:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` @@ -29,7 +37,7 @@ LL | let mut Foo { x: x } = Foo { x: 3 }; = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:21:9 + --> $DIR/mut-patterns.rs:23:9 | LL | let mut Foo { x } = Foo { x: 3 }; | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` @@ -37,13 +45,13 @@ LL | let mut Foo { x } = Foo { x: 3 }; = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:26:13 + --> $DIR/mut-patterns.rs:28:13 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^ help: remove the additional `mut`s error: expected identifier, found reserved keyword `yield` - --> $DIR/mut-patterns.rs:26:17 + --> $DIR/mut-patterns.rs:28:17 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -54,7 +62,7 @@ LL | let mut mut r#yield(become, await) = r#yield(0, 0); | ^^^^^^^ error: expected identifier, found reserved keyword `become` - --> $DIR/mut-patterns.rs:26:23 + --> $DIR/mut-patterns.rs:28:23 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^ expected identifier, found reserved keyword @@ -65,7 +73,7 @@ LL | let mut mut yield(r#become, await) = r#yield(0, 0); | ^^^^^^^^ error: expected identifier, found keyword `await` - --> $DIR/mut-patterns.rs:26:31 + --> $DIR/mut-patterns.rs:28:31 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found keyword @@ -76,7 +84,7 @@ LL | let mut mut yield(become, r#await) = r#yield(0, 0); | ^^^^^^^ error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:26:9 + --> $DIR/mut-patterns.rs:28:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` @@ -84,7 +92,7 @@ LL | let mut mut yield(become, await) = r#yield(0, 0); = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:35:9 + --> $DIR/mut-patterns.rs:37:9 | LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` @@ -92,7 +100,7 @@ LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found `x` - --> $DIR/mut-patterns.rs:42:21 + --> $DIR/mut-patterns.rs:44:21 | LL | let mut $p = 0; | ^^ expected identifier @@ -102,5 +110,5 @@ LL | foo!(x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors From d33b3562e5e888eaffd2f8f1af08ca2afdbe542c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 16 Feb 2020 16:47:24 +0300 Subject: [PATCH 22/25] parser: Do not call `bump` recursively Token normalization is merged directly into `bump`. Special "unknown macro variable" diagnostic for unexpected `$`s is removed as preventing legal code from compiling. --- src/librustc_expand/mbe/macro_parser.rs | 2 - src/librustc_expand/mbe/macro_rules.rs | 1 - src/librustc_parse/parser/mod.rs | 75 +++++++++++-------------- src/test/ui/issues/issue-6596-1.rs | 2 +- src/test/ui/issues/issue-6596-1.stderr | 4 +- src/test/ui/issues/issue-6596-2.rs | 2 +- src/test/ui/issues/issue-6596-2.stderr | 4 +- 7 files changed, 38 insertions(+), 52 deletions(-) diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 5bf7602ea6e8f..6599e92222c75 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -856,8 +856,6 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal { if name == sym::tt { return token::NtTT(p.parse_token_tree()); } - // check at the beginning and the parser checks after each bump - p.process_potential_macro_variable(); match parse_nt_inner(p, sp, name) { Ok(nt) => nt, Err(mut err) => { diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index f3c827b1816a8..52e581e30f537 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -267,7 +267,6 @@ fn generic_extension<'cx>( cx.current_expansion.module.mod_path.last().map(|id| id.to_string()); p.last_type_ascription = cx.current_expansion.prior_type_ascription; - p.process_potential_macro_variable(); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return Box::new(ParserAnyMacro { diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 79944dc35e523..4f96d33b83f2f 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -404,7 +404,8 @@ impl<'a> Parser<'a> { subparser_name, }; - parser.token = parser.next_tok(); + // Make parser point to the first token. + parser.bump(); if let Some(directory) = directory { parser.directory = directory; @@ -418,7 +419,6 @@ impl<'a> Parser<'a> { } } - parser.process_potential_macro_variable(); parser } @@ -430,7 +430,7 @@ impl<'a> Parser<'a> { self.unnormalized_prev_token.as_ref().unwrap_or(&self.prev_token) } - fn next_tok(&mut self) -> Token { + fn next_tok(&mut self, fallback_span: Span) -> Token { let mut next = if self.desugar_doc_comments { self.token_cursor.next_desugared() } else { @@ -438,7 +438,7 @@ impl<'a> Parser<'a> { }; if next.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. - next.span = self.unnormalized_token().span.with_ctxt(next.span.ctxt()); + next.span = fallback_span.with_ctxt(next.span.ctxt()); } next } @@ -896,6 +896,24 @@ impl<'a> Parser<'a> { self.parse_delim_comma_seq(token::Paren, f) } + // Interpolated identifier (`$i: ident`) and lifetime (`$l: lifetime`) + // tokens are replaced with usual identifier and lifetime tokens, + // so the former are never encountered during normal parsing. + fn normalize_token(token: &Token) -> Option { + match &token.kind { + token::Interpolated(nt) => match **nt { + token::NtIdent(ident, is_raw) => { + Some(Token::new(token::Ident(ident.name, is_raw), ident.span)) + } + token::NtLifetime(ident) => { + Some(Token::new(token::Lifetime(ident.name), ident.span)) + } + _ => None, + }, + _ => None, + } + } + /// Advance the parser by one token. pub fn bump(&mut self) { if self.prev_token.kind == TokenKind::Eof { @@ -905,16 +923,17 @@ impl<'a> Parser<'a> { } // Update the current and previous tokens. - let next_token = self.next_tok(); - self.prev_token = mem::replace(&mut self.token, next_token); + self.prev_token = self.token.take(); self.unnormalized_prev_token = self.unnormalized_token.take(); + self.token = self.next_tok(self.unnormalized_prev_token().span); + if let Some(normalized_token) = Self::normalize_token(&self.token) { + self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token)); + } // Update fields derived from the previous token. self.prev_span = self.unnormalized_prev_token().span; self.expected_tokens.clear(); - // Check after each token. - self.process_potential_macro_variable(); } /// Advances the parser using provided token as a next one. Use this when @@ -924,9 +943,12 @@ impl<'a> Parser<'a> { /// Correct token kinds and spans need to be calculated instead. fn bump_with(&mut self, next: TokenKind, span: Span) { // Update the current and previous tokens. - let next_token = Token::new(next, span); - self.prev_token = mem::replace(&mut self.token, next_token); + self.prev_token = self.token.take(); self.unnormalized_prev_token = self.unnormalized_token.take(); + self.token = Token::new(next, span); + if let Some(normalized_token) = Self::normalize_token(&self.token) { + self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token)); + } // Update fields derived from the previous token. self.prev_span = self.unnormalized_prev_token().span.with_hi(span.lo()); @@ -1066,39 +1088,6 @@ impl<'a> Parser<'a> { } } - pub fn process_potential_macro_variable(&mut self) { - let normalized_token = match self.token.kind { - token::Dollar - if self.token.span.from_expansion() && self.look_ahead(1, |t| t.is_ident()) => - { - self.bump(); - let name = match self.token.kind { - token::Ident(name, _) => name, - _ => unreachable!(), - }; - let span = self.prev_span.to(self.token.span); - self.struct_span_err(span, &format!("unknown macro variable `{}`", name)) - .span_label(span, "unknown macro variable") - .emit(); - self.bump(); - return; - } - token::Interpolated(ref nt) => { - // Interpolated identifier and lifetime tokens are replaced with usual identifier - // and lifetime tokens, so the former are never encountered during normal parsing. - match **nt { - token::NtIdent(ident, is_raw) => { - Token::new(token::Ident(ident.name, is_raw), ident.span) - } - token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span), - _ => return, - } - } - _ => return, - }; - self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token)); - } - /// Parses a single token tree from the input. pub fn parse_token_tree(&mut self) -> TokenTree { match self.token.kind { diff --git a/src/test/ui/issues/issue-6596-1.rs b/src/test/ui/issues/issue-6596-1.rs index 5da54451346a5..25f1d6500726e 100644 --- a/src/test/ui/issues/issue-6596-1.rs +++ b/src/test/ui/issues/issue-6596-1.rs @@ -1,7 +1,7 @@ macro_rules! e { ($inp:ident) => ( $nonexistent - //~^ ERROR unknown macro variable `nonexistent` + //~^ ERROR expected expression, found `$` ); } diff --git a/src/test/ui/issues/issue-6596-1.stderr b/src/test/ui/issues/issue-6596-1.stderr index 4f29d8a927456..216fe6472a503 100644 --- a/src/test/ui/issues/issue-6596-1.stderr +++ b/src/test/ui/issues/issue-6596-1.stderr @@ -1,8 +1,8 @@ -error: unknown macro variable `nonexistent` +error: expected expression, found `$` --> $DIR/issue-6596-1.rs:3:9 | LL | $nonexistent - | ^^^^^^^^^^^^ unknown macro variable + | ^^^^^^^^^^^^ expected expression ... LL | e!(foo); | -------- in this macro invocation diff --git a/src/test/ui/issues/issue-6596-2.rs b/src/test/ui/issues/issue-6596-2.rs index b19700efe5ad3..8f7c98d9a67a7 100644 --- a/src/test/ui/issues/issue-6596-2.rs +++ b/src/test/ui/issues/issue-6596-2.rs @@ -3,7 +3,7 @@ macro_rules! g { ($inp:ident) => ( { $inp $nonexistent } - //~^ ERROR unknown macro variable `nonexistent` + //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$` ); } diff --git a/src/test/ui/issues/issue-6596-2.stderr b/src/test/ui/issues/issue-6596-2.stderr index 4fcb0176faafd..3d13c64f762ea 100644 --- a/src/test/ui/issues/issue-6596-2.stderr +++ b/src/test/ui/issues/issue-6596-2.stderr @@ -1,8 +1,8 @@ -error: unknown macro variable `nonexistent` +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$` --> $DIR/issue-6596-2.rs:5:16 | LL | { $inp $nonexistent } - | ^^^^^^^^^^^^ unknown macro variable + | ^^^^^^^^^^^^ expected one of 8 possible tokens ... LL | g!(foo); | -------- in this macro invocation From ed2fd28d385c1cc9b2ab3e91513b4d2ffc612671 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 16 Feb 2020 21:36:50 +0300 Subject: [PATCH 23/25] parser: Set previous and unnormalized tokens in couple more places --- src/librustc_parse/lib.rs | 1 + src/librustc_parse/parser/item.rs | 7 ++++--- src/librustc_parse/parser/mod.rs | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 4aad2c0f68a29..40d7a34a8b0d2 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -172,6 +172,7 @@ fn maybe_source_file_to_parser( parser.unclosed_delims = unclosed_delims; if parser.token == token::Eof && parser.token.span.is_dummy() { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); + assert!(parser.unnormalized_token.is_none()); } Ok(parser) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d7b8d9778f0d2..5dc50a0cf2fde 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1400,8 +1400,9 @@ impl<'a> Parser<'a> { } fn report_invalid_macro_expansion_item(&self, args: &MacArgs) { + let span = args.span().expect("undelimited macro call"); let mut err = self.struct_span_err( - self.prev_span, + span, "macros that expand to items must be delimited with braces or followed by a semicolon", ); if self.unclosed_delims.is_empty() { @@ -1416,14 +1417,14 @@ impl<'a> Parser<'a> { ); } else { err.span_suggestion( - self.prev_span, + span, "change the delimiters to curly braces", " { /* items */ }".to_string(), Applicability::HasPlaceholders, ); } err.span_suggestion( - self.prev_span.shrink_to_hi(), + span.shrink_to_hi(), "add a semicolon", ';'.to_string(), Applicability::MaybeIncorrect, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 4f96d33b83f2f..e04cfa374682b 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -95,7 +95,7 @@ pub struct Parser<'a> { /// The current non-normalized token if it's different from `token`. /// Preferable use is through the `unnormalized_token()` getter. /// Use span from this token if you need to concatenate it with some neighbouring spans. - unnormalized_token: Option, + pub unnormalized_token: Option, /// The previous normalized token. /// Use span from this token if you need an isolated span. prev_token: Token, @@ -1096,15 +1096,15 @@ impl<'a> Parser<'a> { &mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap(), ); - self.token.span = frame.span.entire(); + self.token = Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close); + self.unnormalized_token = None; self.bump(); TokenTree::Delimited(frame.span, frame.delim, frame.tree_cursor.stream.into()) } token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = self.token.clone(); self.bump(); - TokenTree::Token(token) + TokenTree::Token(self.prev_token.clone()) } } } From 06fbb0b4faefeaf70f4616d6af9bc0c1ebc69bc2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 16 Feb 2020 23:19:51 +0300 Subject: [PATCH 24/25] parser: Remove `Option`s from unnormalized tokens They are always set synchronously with normalized tokens now --- src/librustc_parse/lib.rs | 8 ++--- src/librustc_parse/parser/expr.rs | 4 +-- src/librustc_parse/parser/mod.rs | 55 +++++++++++-------------------- src/librustc_parse/parser/path.rs | 2 +- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 40d7a34a8b0d2..a0b8415b3e17e 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -9,7 +9,7 @@ use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; use syntax::ast; -use syntax::token::{self, Nonterminal}; +use syntax::token::{self, Nonterminal, Token}; use syntax::tokenstream::{self, TokenStream, TokenTree}; use std::path::{Path, PathBuf}; @@ -170,9 +170,9 @@ fn maybe_source_file_to_parser( let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?; let mut parser = stream_to_parser(sess, stream, None); parser.unclosed_delims = unclosed_delims; - if parser.token == token::Eof && parser.token.span.is_dummy() { - parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); - assert!(parser.unnormalized_token.is_none()); + if parser.token == token::Eof { + let span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); + parser.set_token(Token::new(token::Eof, span)); } Ok(parser) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 51822ab2ea5a1..97daa91eed196 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -166,7 +166,7 @@ impl<'a> Parser<'a> { while let Some(op) = self.check_assoc_op() { // Adjust the span for interpolated LHS to point to the `$lhs` token // and not to what it refers to. - let lhs_span = match self.unnormalized_prev_token().kind { + let lhs_span = match self.unnormalized_prev_token.kind { TokenKind::Interpolated(..) => self.prev_span, _ => lhs.span, }; @@ -527,7 +527,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, (Span, P)> { expr.map(|e| { ( - match self.unnormalized_prev_token().kind { + match self.unnormalized_prev_token.kind { TokenKind::Interpolated(..) => self.prev_span, _ => e.span, }, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index e04cfa374682b..937e5e3cd695b 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -93,18 +93,16 @@ pub struct Parser<'a> { /// Use span from this token if you need an isolated span. pub token: Token, /// The current non-normalized token if it's different from `token`. - /// Preferable use is through the `unnormalized_token()` getter. /// Use span from this token if you need to concatenate it with some neighbouring spans. - pub unnormalized_token: Option, + unnormalized_token: Token, /// The previous normalized token. /// Use span from this token if you need an isolated span. prev_token: Token, /// The previous non-normalized token if it's different from `prev_token`. - /// Preferable use is through the `unnormalized_prev_token()` getter. /// Use span from this token if you need to concatenate it with some neighbouring spans. - unnormalized_prev_token: Option, - /// Equivalent to `unnormalized_prev_token().span`. - /// FIXME: Remove in favor of `(unnormalized_)prev_token().span`. + unnormalized_prev_token: Token, + /// Equivalent to `unnormalized_prev_token.span`. + /// FIXME: Remove in favor of `(unnormalized_)prev_token.span`. pub prev_span: Span, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. @@ -378,9 +376,9 @@ impl<'a> Parser<'a> { let mut parser = Parser { sess, token: Token::dummy(), - unnormalized_token: None, + unnormalized_token: Token::dummy(), prev_token: Token::dummy(), - unnormalized_prev_token: None, + unnormalized_prev_token: Token::dummy(), prev_span: DUMMY_SP, restrictions: Restrictions::empty(), recurse_into_file_modules, @@ -422,14 +420,6 @@ impl<'a> Parser<'a> { parser } - fn unnormalized_token(&self) -> &Token { - self.unnormalized_token.as_ref().unwrap_or(&self.token) - } - - fn unnormalized_prev_token(&self) -> &Token { - self.unnormalized_prev_token.as_ref().unwrap_or(&self.prev_token) - } - fn next_tok(&mut self, fallback_span: Span) -> Token { let mut next = if self.desugar_doc_comments { self.token_cursor.next_desugared() @@ -899,18 +889,17 @@ impl<'a> Parser<'a> { // Interpolated identifier (`$i: ident`) and lifetime (`$l: lifetime`) // tokens are replaced with usual identifier and lifetime tokens, // so the former are never encountered during normal parsing. - fn normalize_token(token: &Token) -> Option { - match &token.kind { + crate fn set_token(&mut self, token: Token) { + self.unnormalized_token = token; + self.token = match &self.unnormalized_token.kind { token::Interpolated(nt) => match **nt { token::NtIdent(ident, is_raw) => { - Some(Token::new(token::Ident(ident.name, is_raw), ident.span)) + Token::new(token::Ident(ident.name, is_raw), ident.span) } - token::NtLifetime(ident) => { - Some(Token::new(token::Lifetime(ident.name), ident.span)) - } - _ => None, + token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span), + _ => self.unnormalized_token.clone(), }, - _ => None, + _ => self.unnormalized_token.clone(), } } @@ -925,13 +914,11 @@ impl<'a> Parser<'a> { // Update the current and previous tokens. self.prev_token = self.token.take(); self.unnormalized_prev_token = self.unnormalized_token.take(); - self.token = self.next_tok(self.unnormalized_prev_token().span); - if let Some(normalized_token) = Self::normalize_token(&self.token) { - self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token)); - } + let next_token = self.next_tok(self.unnormalized_prev_token.span); + self.set_token(next_token); // Update fields derived from the previous token. - self.prev_span = self.unnormalized_prev_token().span; + self.prev_span = self.unnormalized_prev_token.span; self.expected_tokens.clear(); } @@ -945,13 +932,10 @@ impl<'a> Parser<'a> { // Update the current and previous tokens. self.prev_token = self.token.take(); self.unnormalized_prev_token = self.unnormalized_token.take(); - self.token = Token::new(next, span); - if let Some(normalized_token) = Self::normalize_token(&self.token) { - self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token)); - } + self.set_token(Token::new(next, span)); // Update fields derived from the previous token. - self.prev_span = self.unnormalized_prev_token().span.with_hi(span.lo()); + self.prev_span = self.unnormalized_prev_token.span.with_hi(span.lo()); self.expected_tokens.clear(); } @@ -1096,8 +1080,7 @@ impl<'a> Parser<'a> { &mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap(), ); - self.token = Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close); - self.unnormalized_token = None; + self.set_token(Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close)); self.bump(); TokenTree::Delimited(frame.span, frame.delim, frame.tree_cursor.stream.into()) } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 761c06b70ee8b..18e57c6a5d49f 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -134,7 +134,7 @@ impl<'a> Parser<'a> { path }); - let lo = self.unnormalized_token().span; + let lo = self.unnormalized_token.span; let mut segments = Vec::new(); let mod_sep_ctxt = self.token.span.ctxt(); if self.eat(&token::ModSep) { From 950845c5b1079c83e56db0ca2b4bb8fe050ee2f5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 17 Feb 2020 22:47:40 +0300 Subject: [PATCH 25/25] Add a test for proc macro generating `$ IDENT` --- .../auxiliary/generate-dollar-ident.rs | 17 +++++++++++++++++ .../ui/proc-macro/generate-dollar-ident.rs | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs create mode 100644 src/test/ui/proc-macro/generate-dollar-ident.rs diff --git a/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs new file mode 100644 index 0000000000000..c9f0664c3a3ac --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs @@ -0,0 +1,17 @@ +// force-host +// no-prefer-dynamic + +#![feature(proc_macro_hygiene)] +#![feature(proc_macro_quote)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn dollar_ident(input: TokenStream) -> TokenStream { + let black_hole = input.into_iter().next().unwrap(); + quote! { + $black_hole!($$var); + } +} diff --git a/src/test/ui/proc-macro/generate-dollar-ident.rs b/src/test/ui/proc-macro/generate-dollar-ident.rs new file mode 100644 index 0000000000000..b838be9fb9f2c --- /dev/null +++ b/src/test/ui/proc-macro/generate-dollar-ident.rs @@ -0,0 +1,18 @@ +// Proc macros can generate token sequence `$ IDENT` +// without it being recognized as an unknown macro variable. + +// check-pass +// aux-build:generate-dollar-ident.rs + +extern crate generate_dollar_ident; +use generate_dollar_ident::*; + +macro_rules! black_hole { + ($($tt:tt)*) => {}; +} + +black_hole!($var); + +dollar_ident!(black_hole); + +fn main() {}