From e839b2ec849246ec5efe5069c8d874dbef289462 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Thu, 30 Jan 2020 02:42:33 +0100 Subject: [PATCH 01/13] Constness -> enum Const { Yes(Span), No } Same idea for `Unsafety` & use new span for better diagnostics. --- src/librustc/traits/auto_trait.rs | 3 +- src/librustc/traits/error_reporting/mod.rs | 2 +- src/librustc/traits/select.rs | 8 +- src/librustc/ty/fold.rs | 3 +- src/librustc/ty/mod.rs | 4 +- src/librustc/ty/print/pretty.rs | 2 +- src/librustc/ty/structural_impls.rs | 4 +- src/librustc_ast_lowering/item.rs | 30 ++++++-- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_ast_passes/ast_validation.rs | 30 ++++---- src/librustc_ast_passes/feature_gate.rs | 3 +- src/librustc_ast_pretty/pprust.rs | 20 ++--- .../deriving/generic/mod.rs | 6 +- src/librustc_builtin_macros/deriving/mod.rs | 4 +- .../global_allocator.rs | 4 +- src/librustc_builtin_macros/test.rs | 6 +- src/librustc_hir/hir.rs | 48 ++++++++---- src/librustc_hir/print.rs | 2 +- src/librustc_interface/util.rs | 2 +- src/librustc_lint/builtin.rs | 6 +- .../borrow_check/type_check/mod.rs | 5 +- .../transform/qualify_min_const_fn.rs | 3 +- src/librustc_parse/parser/item.rs | 77 ++++++++----------- src/librustc_parse/parser/mod.rs | 12 ++- src/librustc_save_analysis/sig.rs | 16 ++-- src/librustc_typeck/astconv.rs | 6 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/collect.rs | 10 +-- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/doctree.rs | 2 +- src/libsyntax/ast.rs | 68 +++++----------- .../coherence-negative-impls-safe.stderr | 4 +- .../const-fn-with-const-param.stderr | 6 +- src/test/ui/error-codes/E0197.stderr | 4 +- src/test/ui/error-codes/E0198.stderr | 4 +- .../feature-gate.gated.stderr | 4 +- .../feature-gate.stock.stderr | 4 +- .../inherent-impl.stderr | 16 +++- src/test/ui/syntax-trait-polarity.stderr | 8 +- .../traits/trait-safety-inherent-impl.stderr | 6 +- 40 files changed, 238 insertions(+), 212 deletions(-) diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 1255728de37b1..3ab87ce8eb4a3 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -9,7 +9,6 @@ use crate::ty::fold::TypeFolder; use crate::ty::{Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use syntax::ast; use std::collections::hash_map::Entry; use std::collections::VecDeque; @@ -350,7 +349,7 @@ impl AutoTraitFinder<'tcx> { already_visited.remove(&pred); self.add_user_pred( &mut user_computed_preds, - ty::Predicate::Trait(pred, ast::Constness::NotConst), + ty::Predicate::Trait(pred, hir::Constness::NotConst), ); predicates.push_back(pred); } else { diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index a7a2b578b82da..c25b392ec239a 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -695,7 +695,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let unit_obligation = Obligation { predicate: ty::Predicate::Trait( predicate, - ast::Constness::NotConst, + hir::Constness::NotConst, ), ..obligation.clone() }; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index bf82d743c2b04..1fe8ab58d152c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -40,19 +40,19 @@ use crate::ty::fast_reject; use crate::ty::relate::TypeRelation; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_hir::def_id::DefId; - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_index::bit_set::GrowableBitSet; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; +use syntax::attr; + use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; use std::iter; use std::rc::Rc; -use syntax::{ast, attr}; pub use rustc::traits::types::select::*; @@ -677,7 +677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // if the regions match exactly. let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); let cycle = cycle.map(|stack| { - ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst) + ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst) }); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 0dddca98c6257..1f007b970b0ca 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -32,6 +32,7 @@ //! looking for, and does not need to visit anything else. use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; +use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; @@ -150,7 +151,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } } -impl TypeFoldable<'tcx> for syntax::ast::Constness { +impl TypeFoldable<'tcx> for hir::Constness { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { *self } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 393d49a4e4b05..2bda99e6d20fc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -35,7 +35,7 @@ use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::{GlobMap, Node, TraitMap}; +use rustc_hir::{Constness, GlobMap, Node, TraitMap}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_serialize::{self, Encodable, Encoder}; @@ -43,7 +43,7 @@ use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use rustc_target::abi::Align; -use syntax::ast::{self, Constness, Ident, Name}; +use syntax::ast::{self, Ident, Name}; use syntax::node_id::{NodeId, NodeMap, NodeSet}; use std::cell::RefCell; diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 274482cba64cc..384422956367a 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1818,7 +1818,7 @@ define_print_and_forward_display! { ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref data, constness) => { - if let ast::Constness::Const = constness { + if let hir::Constness::Const = constness { p!(write("const ")); } p!(print(data)) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index acd6c9597518d..59dd41e9d56c9 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -7,6 +7,7 @@ use crate::mir::ProjectionKind; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Ty, TyCtxt}; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::CRATE_DEF_INDEX; use rustc_index::vec::{Idx, IndexVec}; @@ -15,7 +16,6 @@ use smallvec::SmallVec; use std::fmt; use std::rc::Rc; use std::sync::Arc; -use syntax::ast; impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -236,7 +236,7 @@ impl fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::Predicate::Trait(ref a, constness) => { - if let ast::Constness::Const = constness { + if let hir::Constness::Const = constness { write!(f, "const ")?; } a.fmt(f) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index dab950e23f618..8cc3479dd1ba3 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -67,10 +67,12 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind { - if constness == Constness::Const { + if let Const::Yes(span) = constness { this.lctx .diagnostic() - .span_err(item.span, "const trait impls are not yet implemented"); + .struct_span_err(item.span, "const trait impls are not yet implemented") + .span_label(span, "const because of this") + .emit(); } this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); @@ -413,10 +415,10 @@ impl<'hir> LoweringContext<'_, 'hir> { }); hir::ItemKind::Impl { - unsafety, + unsafety: self.lower_unsafety(unsafety), polarity, defaultness: self.lower_defaultness(defaultness, true /* [1] */), - constness, + constness: self.lower_constness(constness), generics, of_trait: trait_ref, self_ty: lowered_ty, @@ -430,7 +432,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item))); hir::ItemKind::Trait( is_auto, - unsafety, + self.lower_unsafety(unsafety), self.lower_generics(generics, ImplTraitContext::disallowed()), bounds, items, @@ -1245,9 +1247,9 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { hir::FnHeader { - unsafety: h.unsafety, + unsafety: self.lower_unsafety(h.unsafety), asyncness: self.lower_asyncness(h.asyncness.node), - constness: h.constness.node, + constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), } } @@ -1281,6 +1283,20 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn lower_constness(&mut self, c: Const) -> hir::Constness { + match c { + Const::Yes(_) => hir::Constness::Const, + Const::No => hir::Constness::NotConst, + } + } + + pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety { + match u { + Unsafe::Yes(_) => hir::Unsafety::Unsafe, + Unsafe::No => hir::Unsafety::Normal, + } + } + pub(super) fn lower_generics_mut( &mut self, generics: &Generics, diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 5816a64fca52c..618b1e7964b95 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1196,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &NodeMap::default(), ImplTraitContext::disallowed(), ), - unsafety: f.unsafety, + unsafety: this.lower_unsafety(f.unsafety), abi: this.lower_extern(f.ext), decl: this.lower_fn_decl(&f.decl, None, false, None), param_names: this.lower_fn_params_to_names(&f.decl), diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 057acec959801..de4f092dbf011 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -13,7 +13,6 @@ use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; use rustc_session::Session; -use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use std::mem; @@ -234,16 +233,11 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) { - if constness.node == Constness::Const { - struct_span_err!( - self.session, - constness.span, - E0379, - "trait fns cannot be declared const" - ) - .span_label(constness.span, "trait fns cannot be const") - .emit(); + fn check_trait_fn_not_const(&self, constness: Const) { + if let Const::Yes(span) = constness { + struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const") + .span_label(span, "trait fns cannot be const") + .emit(); } } @@ -487,7 +481,7 @@ impl<'a> AstValidator<'a> { (Some(FnCtxt::Foreign), _) => return, (Some(FnCtxt::Free), Some(header)) => match header.ext { Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit - if header.unsafety == Unsafety::Unsafe => + if matches!(header.unsafety, Unsafe::Yes(_)) => { return; } @@ -514,12 +508,13 @@ impl<'a> AstValidator<'a> { /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor. /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck. fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) { - if sig.header.constness.node == Constness::Const { + if let Const::Yes(const_span) = sig.header.constness { // Look for const generics and error if we find any. for param in &generics.params { if let GenericParamKind::Const { .. } = param.kind { self.err_handler() .struct_span_err(span, "const parameters are not permitted in `const fn`") + .span_label(const_span, "`const fn` because of this") .emit(); } } @@ -754,13 +749,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .help("use `auto trait Trait {}` instead") .emit(); } - if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative { + if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) { struct_span_err!( this.session, item.span, E0198, "negative impls cannot be unsafe" ) + .span_label(span, "unsafe because of this") .emit(); } @@ -782,13 +778,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &item.vis, Some("place qualifiers on individual impl items instead"), ); - if unsafety == Unsafety::Unsafe { + if let Unsafe::Yes(span) = unsafety { struct_span_err!( self.session, item.span, E0197, "inherent impls cannot be unsafe" ) + .span_label(span, "unsafe because of this") .emit(); } if polarity == ImplPolarity::Negative { @@ -800,9 +797,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .note("only trait implementations may be annotated with default") .emit(); } - if constness == Constness::Const { + if let Const::Yes(span) = constness { self.err_handler() .struct_span_err(item.span, "inherent impls cannot be `const`") + .span_label(span, "`const` because of this") .note("only trait implementations may be annotated with `const`") .emit(); } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index a10ac94d8942b..cfab54925b161 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -538,8 +538,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match i.kind { ast::AssocItemKind::Fn(ref sig, _) => { - let constness = sig.header.constness.node; - if let (ast::Constness::Const, AssocCtxt::Trait) = (constness, ctxt) { + if let (ast::Const::Yes(_), AssocCtxt::Trait) = (sig.header.constness, ctxt) { gate_feature_post!(&self, const_fn, i.span, "const fn is unstable"); } } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 78bf149f0e01a..633964683dcc6 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -2686,7 +2686,7 @@ impl<'a> State<'a> { crate fn print_ty_fn( &mut self, ext: ast::Extern, - unsafety: ast::Unsafety, + unsafety: ast::Unsafe, decl: &ast::FnDecl, name: Option<ast::Ident>, generic_params: &[ast::GenericParam], @@ -2733,11 +2733,7 @@ impl<'a> State<'a> { crate fn print_fn_header_info(&mut self, header: ast::FnHeader, vis: &ast::Visibility) { self.s.word(visibility_qualified(vis, "")); - match header.constness.node { - ast::Constness::NotConst => {} - ast::Constness::Const => self.word_nbsp("const"), - } - + self.print_constness(header.constness); self.print_asyncness(header.asyncness.node); self.print_unsafety(header.unsafety); @@ -2756,17 +2752,17 @@ impl<'a> State<'a> { self.s.word("fn") } - crate fn print_unsafety(&mut self, s: ast::Unsafety) { + crate fn print_unsafety(&mut self, s: ast::Unsafe) { match s { - ast::Unsafety::Normal => {} - ast::Unsafety::Unsafe => self.word_nbsp("unsafe"), + ast::Unsafe::No => {} + ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"), } } - crate fn print_constness(&mut self, s: ast::Constness) { + crate fn print_constness(&mut self, s: ast::Const) { match s { - ast::Constness::Const => self.word_nbsp("const"), - ast::Constness::NotConst => {} + ast::Const::No => {} + ast::Const::Yes(_) => self.word_nbsp("const"), } } diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index f99008a6d5c14..5cf233e222e7c 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -700,7 +700,7 @@ impl<'a> TraitDef<'a> { let mut a = vec![attr, unused_qual]; a.extend(self.attributes.iter().cloned()); - let unsafety = if self.is_unsafe { ast::Unsafety::Unsafe } else { ast::Unsafety::Normal }; + let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No }; cx.item( self.span, @@ -710,7 +710,7 @@ impl<'a> TraitDef<'a> { unsafety, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, - constness: ast::Constness::NotConst, + constness: ast::Const::No, generics: trait_generics, of_trait: opt_trait_ref, self_ty: self_type, @@ -960,7 +960,7 @@ impl<'a> MethodDef<'a> { let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type)); let body_block = cx.block_expr(body); - let unsafety = if self.is_unsafe { ast::Unsafety::Unsafe } else { ast::Unsafety::Normal }; + let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No }; let trait_lo_sp = trait_.span.shrink_to_lo(); diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index 914dcdf196921..63cd03527e15c 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -157,10 +157,10 @@ fn inject_impl_of_structural_trait( ast::Ident::invalid(), attrs, ItemKind::Impl { - unsafety: ast::Unsafety::Normal, + unsafety: ast::Unsafe::No, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, - constness: ast::Constness::NotConst, + constness: ast::Const::No, generics, of_trait: Some(trait_ref), self_ty: self_type, diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index ec0d55b38a73d..52f033e8b1404 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -4,7 +4,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use syntax::ast::{self, Attribute, Expr, FnHeader, FnSig, Generics, Ident, Param}; -use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; +use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; use syntax::expand::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ptr::P; @@ -64,7 +64,7 @@ impl AllocFnFactory<'_, '_> { let result = self.call_allocator(method.name, args); let (output_ty, output_expr) = self.ret_ty(&method.output, result); let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)); - let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() }; + let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; let sig = FnSig { decl, header }; let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr))); let item = self.cx.item( diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index 2d6ff81aea8b8..dd93596b3cfce 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -375,8 +375,10 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let ref sd = cx.parse_sess.span_diagnostic; if let ast::ItemKind::Fn(ref sig, ref generics, _) = i.kind { - if sig.header.unsafety == ast::Unsafety::Unsafe { - sd.span_err(i.span, "unsafe functions cannot be used for tests"); + if let ast::Unsafe::Yes(span) = sig.header.unsafety { + sd.struct_span_err(i.span, "unsafe functions cannot be used for tests") + .span_label(span, "unsafe because of this") + .emit(); return false; } if sig.header.asyncness.node.is_async() { diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 27bca1625c1c1..c2ddaf7df316a 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -19,7 +19,7 @@ use rustc_target::spec::abi::Abi; use syntax::ast::{self, AsmDialect, CrateSugar, Ident, Name, NodeId}; use syntax::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto}; -pub use syntax::ast::{CaptureBy, Constness, Movability, Mutability, Unsafety}; +pub use syntax::ast::{CaptureBy, Movability, Mutability}; use syntax::node_id::NodeMap; use syntax::tokenstream::TokenStream; use syntax::util::parser::ExprPrecedence; @@ -2109,18 +2109,8 @@ impl ImplicitSelfKind { } } -#[derive( - Copy, - Clone, - PartialEq, - Eq, - PartialOrd, - HashStable_Generic, - Ord, - RustcEncodable, - RustcDecodable, - Debug -)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Debug)] +#[derive(HashStable_Generic)] pub enum IsAsync { Async, NotAsync, @@ -2389,6 +2379,38 @@ pub struct Item<'hir> { pub span: Span, } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)] +pub enum Unsafety { + Unsafe, + Normal, +} + +impl Unsafety { + pub fn prefix_str(&self) -> &'static str { + match self { + Self::Unsafe => "unsafe ", + Self::Normal => "", + } + } +} + +impl fmt::Display for Unsafety { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + Self::Unsafe => "unsafe", + Self::Normal => "normal", + }) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)] +pub enum Constness { + Const, + NotConst, +} + #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct FnHeader { pub unsafety: Unsafety, diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index 071c3de4b1c2c..b31b814d67be6 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -648,7 +648,7 @@ impl<'a> State<'a> { self.s.space(); } - if constness == ast::Constness::Const { + if let hir::Constness::Const = constness { self.word_nbsp("const"); } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 3052c9fc26f08..659323d1c2555 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -668,7 +668,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { } fn is_sig_const(sig: &ast::FnSig) -> bool { - sig.header.constness.node == ast::Constness::Const + matches!(sig.header.constness, ast::Const::Yes(_)) || ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c827a7f3d5283..93fca43d67c1f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -258,13 +258,13 @@ impl EarlyLintPass for UnsafeCode { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { match it.kind { - ast::ItemKind::Trait(_, ast::Unsafety::Unsafe, ..) => { + ast::ItemKind::Trait(_, ast::Unsafe::Yes(_), ..) => { self.report_unsafe(cx, it.span, |lint| { lint.build("declaration of an `unsafe` trait").emit() }) } - ast::ItemKind::Impl { unsafety: ast::Unsafety::Unsafe, .. } => { + ast::ItemKind::Impl { unsafety: ast::Unsafe::Yes(_), .. } => { self.report_unsafe(cx, it.span, |lint| { lint.build("implementation of an `unsafe` trait").emit() }) @@ -278,7 +278,7 @@ impl EarlyLintPass for UnsafeCode { if let FnKind::Fn( ctxt, _, - ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. }, + ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. }, _, body, ) = fk diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 100fd7dc48d0e..4cbe41455894b 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -32,7 +32,6 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast; use crate::dataflow::generic::ResultsCursor; use crate::dataflow::move_paths::MoveData; @@ -1938,7 +1937,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx.mk_substs_trait(ty, &[]), ), }), - ast::Constness::NotConst, + hir::Constness::NotConst, ), ), &traits::SelectionError::Unimplemented, @@ -2579,7 +2578,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.prove_predicates( Some(ty::Predicate::Trait( trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), - ast::Constness::NotConst, + hir::Constness::NotConst, )), locations, category, diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 6a68ccdddffdc..b12f4ce32698f 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -6,7 +6,6 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::borrow::Cow; -use syntax::ast; type McfResult = Result<(), (Span, Cow<'static, str>)>; @@ -35,7 +34,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - match pred.skip_binder().self_ty().kind { ty::Param(ref p) => { // Allow `T: ?const Trait` - if *constness == ast::Constness::NotConst + if *constness == hir::Constness::NotConst && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) { continue; diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 07d8bae4725bd..a66a85b2b830f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -12,7 +12,7 @@ use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind}; -use syntax::ast::{Constness, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafety}; +use syntax::ast::{Const, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafe}; use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind}; use syntax::ptr::P; @@ -107,9 +107,9 @@ impl<'a> Parser<'a> { // EXTERN FUNCTION ITEM let fn_span = self.prev_span; let header = FnHeader { - unsafety: Unsafety::Normal, + unsafety: Unsafe::No, asyncness: respan(fn_span, IsAsync::NotAsync), - constness: respan(fn_span, Constness::NotConst), + constness: Const::No, ext: Extern::from_abi(abi), }; return self.parse_item_fn(lo, vis, attrs, header); @@ -128,8 +128,8 @@ impl<'a> Parser<'a> { return self.mk_item_with_info(attrs, lo, vis, info); } - if self.eat_keyword(kw::Const) { - let const_span = self.prev_span; + let constness = self.parse_constness(); + if let Const::Yes(const_span) = constness { if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) { // CONST FUNCTION ITEM let unsafety = self.parse_unsafety(); @@ -143,7 +143,7 @@ impl<'a> Parser<'a> { let header = FnHeader { unsafety, asyncness: respan(const_span, IsAsync::NotAsync), - constness: respan(const_span, Constness::Const), + constness, ext, }; return self.parse_item_fn(lo, vis, attrs, header); @@ -175,7 +175,6 @@ impl<'a> Parser<'a> { self.bump(); // `async` let unsafety = self.parse_unsafety(); // `unsafe`? self.expect_keyword(kw::Fn)?; // `fn` - let fn_span = self.prev_span; let asyncness = respan( async_span, IsAsync::Async { @@ -184,20 +183,16 @@ impl<'a> Parser<'a> { }, ); self.ban_async_in_2015(async_span); - let header = FnHeader { - unsafety, - asyncness, - constness: respan(fn_span, Constness::NotConst), - ext: Extern::None, - }; + let header = + FnHeader { unsafety, asyncness, constness: Const::No, ext: Extern::None }; return self.parse_item_fn(lo, vis, attrs, header); } } if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) { // UNSAFE TRAIT ITEM - self.bump(); // `unsafe` - let info = self.parse_item_trait(lo, Unsafety::Unsafe)?; + let unsafety = self.parse_unsafety(); + let info = self.parse_item_trait(lo, unsafety)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -218,9 +213,9 @@ impl<'a> Parser<'a> { self.bump(); let fn_span = self.prev_span; let header = FnHeader { - unsafety: Unsafety::Normal, + unsafety: Unsafe::No, asyncness: respan(fn_span, IsAsync::NotAsync), - constness: respan(fn_span, Constness::NotConst), + constness: Const::No, ext: Extern::None, }; return self.parse_item_fn(lo, vis, attrs, header); @@ -230,16 +225,16 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { // UNSAFE FUNCTION ITEM - self.bump(); // `unsafe` + let unsafety = self.parse_unsafety(); // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic. self.check(&token::OpenDelim(token::Brace)); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; let fn_span = self.prev_span; let header = FnHeader { - unsafety: Unsafety::Unsafe, + unsafety, asyncness: respan(fn_span, IsAsync::NotAsync), - constness: respan(fn_span, Constness::NotConst), + constness: Const::No, ext, }; return self.parse_item_fn(lo, vis, attrs, header); @@ -268,7 +263,7 @@ impl<'a> Parser<'a> { || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])) { // TRAIT ITEM - let info = self.parse_item_trait(lo, Unsafety::Normal)?; + let info = self.parse_item_trait(lo, Unsafe::No)?; return self.mk_item_with_info(attrs, lo, vis, info); } @@ -547,7 +542,7 @@ impl<'a> Parser<'a> { /// `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}` fn parse_item_impl( &mut self, - unsafety: Unsafety, + unsafety: Unsafe, defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { // First, parse generic parameters if necessary. @@ -561,13 +556,10 @@ impl<'a> Parser<'a> { generics }; - let constness = if self.eat_keyword(kw::Const) { - let span = self.prev_span; + let constness = self.parse_constness(); + if let Const::Yes(span) = constness { self.sess.gated_spans.gate(sym::const_trait_impl, span); - Constness::Const - } else { - Constness::NotConst - }; + } // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { @@ -707,7 +699,7 @@ impl<'a> Parser<'a> { } /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafe) -> PResult<'a, ItemInfo> { // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; @@ -734,11 +726,11 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_span); - if is_auto == IsAuto::Yes { + if let IsAuto::Yes = is_auto { let msg = "trait aliases cannot be `auto`"; self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); } - if unsafety != Unsafety::Normal { + if let Unsafe::Yes(_) = unsafety { let msg = "trait aliases cannot be `unsafe`"; self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); } @@ -1785,28 +1777,27 @@ impl<'a> Parser<'a> { Ok(body) } - /// Parses all the "front matter" for a `fn` declaration, up to - /// and including the `fn` keyword: + /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, + /// up to and including the `fn` keyword. The formal grammar is: /// - /// - `const fn` - /// - `unsafe fn` - /// - `const unsafe fn` - /// - `extern fn` - /// - etc. + /// ``` + /// Extern = "extern" StringLit ; + /// FnQual = "const"? "async"? "unsafe"? Extern? ; + /// FnFrontMatter = FnQual? "fn" ; + /// ``` fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { - let is_const_fn = self.eat_keyword(kw::Const); - let const_span = self.prev_span; + let constness = self.parse_constness(); let asyncness = self.parse_asyncness(); if let IsAsync::Async { .. } = asyncness { self.ban_async_in_2015(self.prev_span); } let asyncness = respan(self.prev_span, asyncness); let unsafety = self.parse_unsafety(); - let (constness, unsafety, ext) = if is_const_fn { - (respan(const_span, Constness::Const), unsafety, Extern::None) + let (constness, unsafety, ext) = if let Const::Yes(_) = constness { + (constness, unsafety, Extern::None) } else { let ext = self.parse_extern()?; - (respan(self.prev_span, Constness::NotConst), unsafety, ext) + (Const::No, unsafety, ext) }; if !self.eat_keyword(kw::Fn) { // It is possible for `expect_one_of` to recover given the contents of diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index e1461dbb8e763..bccf5968118b4 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -22,7 +22,8 @@ use rustc_session::parse::ParseSess; use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{FileName, Span, DUMMY_SP}; -use syntax::ast::{self, AttrStyle, AttrVec, CrateSugar, Extern, Ident, Unsafety, DUMMY_NODE_ID}; +use syntax::ast::DUMMY_NODE_ID; +use syntax::ast::{self, AttrStyle, AttrVec, Const, CrateSugar, Extern, Ident, Unsafe}; use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; use syntax::ptr::P; use syntax::token::{self, DelimToken, Token, TokenKind}; @@ -962,8 +963,13 @@ impl<'a> Parser<'a> { } /// Parses unsafety: `unsafe` or nothing. - fn parse_unsafety(&mut self) -> Unsafety { - if self.eat_keyword(kw::Unsafe) { Unsafety::Unsafe } else { Unsafety::Normal } + fn parse_unsafety(&mut self) -> Unsafe { + if self.eat_keyword(kw::Unsafe) { Unsafe::Yes(self.prev_span) } else { Unsafe::No } + } + + /// Parses constness: `const` or nothing. + fn parse_constness(&mut self) -> Const { + if self.eat_keyword(kw::Const) { Const::Yes(self.prev_span) } else { Const::No } } /// Parses mutability (`mut` or nothing). diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 6401cabdcd5c1..820202c85ab87 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -225,7 +225,7 @@ impl Sig for ast::Ty { text.push('>'); } - if f.unsafety == ast::Unsafety::Unsafe { + if let ast::Unsafe::Yes(_) = f.unsafety { text.push_str("unsafe "); } push_extern(&mut text, f.ext); @@ -365,13 +365,13 @@ impl Sig for ast::Item { } ast::ItemKind::Fn(ast::FnSig { ref decl, header }, ref generics, _) => { let mut text = String::new(); - if header.constness.node == ast::Constness::Const { + if let ast::Const::Yes(_) = header.constness { text.push_str("const "); } if header.asyncness.node.is_async() { text.push_str("async "); } - if header.unsafety == ast::Unsafety::Unsafe { + if let ast::Unsafe::Yes(_) = header.unsafety { text.push_str("unsafe "); } push_extern(&mut text, header.ext); @@ -453,7 +453,7 @@ impl Sig for ast::Item { text.push_str("auto "); } - if unsafety == ast::Unsafety::Unsafe { + if let ast::Unsafe::Yes(_) = unsafety { text.push_str("unsafe "); } text.push_str("trait "); @@ -496,11 +496,11 @@ impl Sig for ast::Item { if let ast::Defaultness::Default = defaultness { text.push_str("default "); } - if unsafety == ast::Unsafety::Unsafe { + if let ast::Unsafe::Yes(_) = unsafety { text.push_str("unsafe "); } text.push_str("impl"); - if constness == ast::Constness::Const { + if let ast::Const::Yes(_) = constness { text.push_str(" const"); } @@ -884,13 +884,13 @@ fn make_method_signature( ) -> Result { // FIXME code dup with function signature let mut text = String::new(); - if m.header.constness.node == ast::Constness::Const { + if let ast::Const::Yes(_) = m.header.constness { text.push_str("const "); } if m.header.asyncness.node.is_async() { text.push_str("async "); } - if m.header.unsafety == ast::Unsafety::Unsafe { + if let ast::Unsafe::Yes(_) = m.header.unsafety { text.push_str("unsafe "); } push_extern(&mut text, m.header.ext); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c26b47c313023..0e7c10541cad7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -28,12 +28,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::print; -use rustc_hir::{ExprKind, GenericArg, GenericArgs}; +use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs}; use rustc_span::symbol::sym; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use smallvec::SmallVec; -use syntax::ast::{self, Constness}; +use syntax::ast; use syntax::util::lev_distance::find_best_match_for_name; use std::collections::BTreeSet; @@ -1502,7 +1502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); for (base_trait_ref, span, constness) in regular_traits_refs_spans { - assert_eq!(constness, ast::Constness::NotConst); + assert_eq!(constness, Constness::NotConst); for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) { debug!( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fd0c994a6eadf..a825856e38aa0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2693,13 +2693,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { None } - fn default_constness_for_trait_bounds(&self) -> ast::Constness { + fn default_constness_for_trait_bounds(&self) -> hir::Constness { // FIXME: refactor this into a method let node = self.tcx.hir().get(self.body_id); if let Some(fn_like) = FnLikeNode::from_node(node) { fn_like.constness() } else { - ast::Constness::NotConst + hir::Constness::NotConst } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f3a1f412d0d59..5349c324ad8a7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -300,11 +300,11 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { Some(self.item_def_id) } - fn default_constness_for_trait_bounds(&self) -> ast::Constness { + fn default_constness_for_trait_bounds(&self) -> hir::Constness { if let Some(fn_like) = FnLikeNode::from_node(self.node()) { fn_like.constness() } else { - ast::Constness::NotConst + hir::Constness::NotConst } } @@ -2429,7 +2429,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat match bound { &hir::GenericBound::Trait(ref poly_trait_ref, modifier) => { let constness = match modifier { - hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst, + hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst, hir::TraitBoundModifier::None => constness, hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"), }; @@ -2617,13 +2617,13 @@ fn predicates_from_bound<'tcx>( astconv: &dyn AstConv<'tcx>, param_ty: Ty<'tcx>, bound: &'tcx hir::GenericBound<'tcx>, - constness: ast::Constness, + constness: hir::Constness, ) -> Vec<(ty::Predicate<'tcx>, Span)> { match *bound { hir::GenericBound::Trait(ref tr, modifier) => { let constness = match modifier { hir::TraitBoundModifier::Maybe => return vec![], - hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst, + hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst, hir::TraitBoundModifier::None => constness, }; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 474868f0dd6c4..067b33c144742 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -377,7 +377,7 @@ pub fn hir_trait_to_predicates<'tcx>( &item_cx, hir_trait, DUMMY_SP, - syntax::ast::Constness::NotConst, + hir::Constness::NotConst, tcx.types.err, &mut bounds, true, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 218674b757f39..744201a00500b 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -203,7 +203,7 @@ pub struct Impl<'hir> { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, pub defaultness: hir::Defaultness, - pub constness: ast::Constness, + pub constness: hir::Constness, pub generics: &'hir hir::Generics<'hir>, pub trait_: &'hir Option<hir::TraitRef<'hir>>, pub for_: &'hir hir::Ty<'hir>, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b22406124e098..a7142dfda8593 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1863,7 +1863,7 @@ pub struct Ty { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct BareFnTy { - pub unsafety: Unsafety, + pub unsafety: Unsafe, pub ext: Extern, pub generic_params: Vec<GenericParam>, pub decl: P<FnDecl>, @@ -2101,43 +2101,11 @@ pub enum IsAuto { No, } -#[derive( - Copy, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - Debug, - HashStable_Generic -)] -pub enum Unsafety { - Unsafe, - Normal, -} - -impl Unsafety { - pub fn prefix_str(&self) -> &'static str { - match self { - Unsafety::Unsafe => "unsafe ", - Unsafety::Normal => "", - } - } -} - -impl fmt::Display for Unsafety { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt( - match *self { - Unsafety::Normal => "normal", - Unsafety::Unsafe => "unsafe", - }, - f, - ) - } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] +#[derive(HashStable_Generic)] +pub enum Unsafe { + Yes(Span), + No, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2162,9 +2130,9 @@ impl IsAsync { #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] #[derive(HashStable_Generic)] -pub enum Constness { - Const, - NotConst, +pub enum Const { + Yes(Span), + No, } /// Item defaultness. @@ -2527,9 +2495,9 @@ impl Extern { /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub struct FnHeader { - pub unsafety: Unsafety, + pub unsafety: Unsafe, pub asyncness: Spanned<IsAsync>, - pub constness: Spanned<Constness>, + pub constness: Const, pub ext: Extern, } @@ -2537,9 +2505,9 @@ impl FnHeader { /// Does this function header have any qualifiers or is it empty? pub fn has_qualifiers(&self) -> bool { let Self { unsafety, asyncness, constness, ext } = self; - matches!(unsafety, Unsafety::Unsafe) + matches!(unsafety, Unsafe::Yes(_)) || asyncness.node.is_async() - || matches!(constness.node, Constness::Const) + || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } } @@ -2547,9 +2515,9 @@ impl FnHeader { impl Default for FnHeader { fn default() -> FnHeader { FnHeader { - unsafety: Unsafety::Normal, + unsafety: Unsafe::No, asyncness: dummy_spanned(IsAsync::NotAsync), - constness: dummy_spanned(Constness::NotConst), + constness: Const::No, ext: Extern::None, } } @@ -2606,7 +2574,7 @@ pub enum ItemKind { /// A trait declaration (`trait`). /// /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`. - Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<P<AssocItem>>), + Trait(IsAuto, Unsafe, Generics, GenericBounds, Vec<P<AssocItem>>), /// Trait alias /// /// E.g., `trait Foo = Bar + Quux;`. @@ -2615,10 +2583,10 @@ pub enum ItemKind { /// /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`. Impl { - unsafety: Unsafety, + unsafety: Unsafe, polarity: ImplPolarity, defaultness: Defaultness, - constness: Constness, + constness: Const, generics: Generics, /// The trait being implemented, if any. diff --git a/src/test/ui/coherence/coherence-negative-impls-safe.stderr b/src/test/ui/coherence/coherence-negative-impls-safe.stderr index c47c9d25e3614..4db66af6783ca 100644 --- a/src/test/ui/coherence/coherence-negative-impls-safe.stderr +++ b/src/test/ui/coherence/coherence-negative-impls-safe.stderr @@ -2,7 +2,9 @@ error[E0198]: negative impls cannot be unsafe --> $DIR/coherence-negative-impls-safe.rs:7:1 | LL | unsafe impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsafe because of this error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr index 3437ed33d0c6f..68670963f8e5e 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.stderr +++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr @@ -1,7 +1,11 @@ error: const parameters are not permitted in `const fn` --> $DIR/const-fn-with-const-param.rs:4:1 | -LL | / const fn const_u32_identity<const X: u32>() -> u32 { +LL | const fn const_u32_identity<const X: u32>() -> u32 { + | ^---- + | | + | _`const fn` because of this + | | LL | | LL | | X LL | | } diff --git a/src/test/ui/error-codes/E0197.stderr b/src/test/ui/error-codes/E0197.stderr index bb7b6474d3e38..51ed9c83bc999 100644 --- a/src/test/ui/error-codes/E0197.stderr +++ b/src/test/ui/error-codes/E0197.stderr @@ -2,7 +2,9 @@ error[E0197]: inherent impls cannot be unsafe --> $DIR/E0197.rs:3:1 | LL | unsafe impl Foo { } - | ^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^ + | | + | unsafe because of this error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0198.stderr b/src/test/ui/error-codes/E0198.stderr index 0d3706336a9ca..90e8b4abd1296 100644 --- a/src/test/ui/error-codes/E0198.stderr +++ b/src/test/ui/error-codes/E0198.stderr @@ -2,7 +2,9 @@ error[E0198]: negative impls cannot be unsafe --> $DIR/E0198.rs:5:1 | LL | unsafe impl !Send for Foo { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsafe because of this error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr index b196f9ef57380..061af3c94b44d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr @@ -2,7 +2,9 @@ error: const trait impls are not yet implemented --> $DIR/feature-gate.rs:9:1 | LL | impl const T for S {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^^^^^^^ + | | + | const because of this error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr index 6e1cdde084396..cfe226ea7a7ce 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr @@ -11,7 +11,9 @@ error: const trait impls are not yet implemented --> $DIR/feature-gate.rs:9:1 | LL | impl const T for S {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^^^^^^^ + | | + | const because of this error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr index 508c6f4c747e1..bdc95ff2a57b5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -2,7 +2,9 @@ error: inherent impls cannot be `const` --> $DIR/inherent-impl.rs:9:1 | LL | impl const S {} - | ^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^ + | | + | `const` because of this | = note: only trait implementations may be annotated with `const` @@ -10,7 +12,9 @@ error: inherent impls cannot be `const` --> $DIR/inherent-impl.rs:13:1 | LL | impl const T {} - | ^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^ + | | + | `const` because of this | = note: only trait implementations may be annotated with `const` @@ -18,13 +22,17 @@ error: const trait impls are not yet implemented --> $DIR/inherent-impl.rs:9:1 | LL | impl const S {} - | ^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^ + | | + | const because of this error: const trait impls are not yet implemented --> $DIR/inherent-impl.rs:13:1 | LL | impl const T {} - | ^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^ + | | + | const because of this error: aborting due to 4 previous errors diff --git a/src/test/ui/syntax-trait-polarity.stderr b/src/test/ui/syntax-trait-polarity.stderr index b66db9feedbdc..fef3a65088855 100644 --- a/src/test/ui/syntax-trait-polarity.stderr +++ b/src/test/ui/syntax-trait-polarity.stderr @@ -8,7 +8,9 @@ error[E0198]: negative impls cannot be unsafe --> $DIR/syntax-trait-polarity.rs:12:1 | LL | unsafe impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsafe because of this error: inherent impls cannot be negative --> $DIR/syntax-trait-polarity.rs:19:1 @@ -20,7 +22,9 @@ error[E0198]: negative impls cannot be unsafe --> $DIR/syntax-trait-polarity.rs:22:1 | LL | unsafe impl<T> !Send for TestType2<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsafe because of this error[E0192]: negative impls are only allowed for auto traits (e.g., `Send` and `Sync`) --> $DIR/syntax-trait-polarity.rs:14:1 diff --git a/src/test/ui/traits/trait-safety-inherent-impl.stderr b/src/test/ui/traits/trait-safety-inherent-impl.stderr index 3911261083ecc..c398785d3949e 100644 --- a/src/test/ui/traits/trait-safety-inherent-impl.stderr +++ b/src/test/ui/traits/trait-safety-inherent-impl.stderr @@ -1,7 +1,11 @@ error[E0197]: inherent impls cannot be unsafe --> $DIR/trait-safety-inherent-impl.rs:5:1 | -LL | / unsafe impl SomeStruct { +LL | unsafe impl SomeStruct { + | ^----- + | | + | _unsafe because of this + | | LL | | fn foo(self) { } LL | | } | |_^ From c30f068dc8b2ef58678b9846ba834dd6dea3fe44 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Thu, 30 Jan 2020 05:31:04 +0100 Subject: [PATCH 02/13] IsAsync -> enum Async { Yes { span: Span, .. }, No } use new span for better diagnostics. --- src/librustc_ast_lowering/expr.rs | 2 +- src/librustc_ast_lowering/item.rs | 27 +++++------- src/librustc_ast_passes/ast_validation.rs | 12 ++--- src/librustc_ast_pretty/pprust.rs | 4 +- src/librustc_builtin_macros/test.rs | 6 ++- src/librustc_expand/build.rs | 4 +- src/librustc_parse/parser/expr.rs | 4 +- src/librustc_parse/parser/item.rs | 44 ++++--------------- src/librustc_parse/parser/mod.rs | 9 ++-- src/librustc_resolve/def_collector.rs | 12 ++--- src/librustc_resolve/late.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 8 ++-- src/librustc_save_analysis/sig.rs | 4 +- src/libsyntax/ast.rs | 26 +++++------ src/libsyntax/mut_visit.rs | 10 ++--- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 2 +- src/test/ui/async-await/async-trait-fn.stderr | 8 +++- .../edition-deny-async-fns-2015.stderr | 4 +- .../ui/parser/fn-header-semantic-fail.stderr | 16 +++++-- 19 files changed, 96 insertions(+), 108 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index dd3316979f6a2..b51d476558312 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -106,7 +106,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ref body, fn_decl_span, ) => { - if let IsAsync::Async { closure_id, .. } = asyncness { + if let Async::Yes { closure_id, .. } = asyncness { self.lower_expr_async_closure( capture_clause, closure_id, diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 8cc3479dd1ba3..73a25620b5a04 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -299,7 +299,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `impl Future<Output = T>` here because lower_body // only cares about the input argument patterns in the function // declaration (decl), not the return types. - let asyncness = header.asyncness.node; + let asyncness = header.asyncness; let body_id = this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); @@ -836,19 +836,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } AssocItemKind::Fn(ref sig, ref body) => { self.current_item = Some(i.span); - let body_id = self.lower_maybe_async_body( - i.span, - &sig.decl, - sig.header.asyncness.node, - body.as_deref(), - ); + 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, sig, impl_item_def_id, impl_trait_return_allow, - sig.header.asyncness.node.opt_return_id(), + asyncness.opt_return_id(), ); (generics, hir::ImplItemKind::Method(sig, body_id)) @@ -1033,12 +1030,12 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, span: Span, decl: &FnDecl, - asyncness: IsAsync, + asyncness: Async, body: Option<&Block>, ) -> hir::BodyId { let closure_id = match asyncness { - IsAsync::Async { closure_id, .. } => closure_id, - IsAsync::NotAsync => return self.lower_fn_body_block(span, decl, body), + Async::Yes { closure_id, .. } => closure_id, + Async::No => return self.lower_fn_body_block(span, decl, body), }; self.lower_body(|this| { @@ -1248,7 +1245,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { hir::FnHeader { unsafety: self.lower_unsafety(h.unsafety), - asyncness: self.lower_asyncness(h.asyncness.node), + asyncness: self.lower_asyncness(h.asyncness), constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), } @@ -1276,10 +1273,10 @@ impl<'hir> LoweringContext<'_, 'hir> { .emit(); } - fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync { + fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { match a { - IsAsync::Async { .. } => hir::IsAsync::Async, - IsAsync::NotAsync => hir::IsAsync::NotAsync, + Async::Yes { .. } => hir::IsAsync::Async, + Async::No => hir::IsAsync::NotAsync, } } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index de4f092dbf011..e0217de1d3b8d 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -221,13 +221,13 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) { - if asyncness.is_async() { - struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`") + fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) { + if let Async::Yes { span, .. } = asyncness { + struct_span_err!(self.session, fn_span, E0706, "trait fns cannot be declared `async`") + .span_label(span, "`async` because of this") .note("`async` trait functions are not currently supported") .note( - "consider using the `async-trait` crate: \ - https://crates.io/crates/async-trait", + "consider using the `async-trait` crate: https://crates.io/crates/async-trait", ) .emit(); } @@ -1144,7 +1144,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility(&item.vis, None); 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.node); + self.check_trait_fn_not_async(item.span, sig.header.asyncness); } } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 633964683dcc6..b1fa818d0a8cf 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -2449,7 +2449,7 @@ impl<'a> State<'a> { } } - crate fn print_asyncness(&mut self, asyncness: ast::IsAsync) { + crate fn print_asyncness(&mut self, asyncness: ast::Async) { if asyncness.is_async() { self.word_nbsp("async"); } @@ -2734,7 +2734,7 @@ impl<'a> State<'a> { self.s.word(visibility_qualified(vis, "")); self.print_constness(header.constness); - self.print_asyncness(header.asyncness.node); + self.print_asyncness(header.asyncness); self.print_unsafety(header.unsafety); match header.ext { diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index dd93596b3cfce..a246e11495345 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -381,8 +381,10 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { .emit(); return false; } - if sig.header.asyncness.node.is_async() { - sd.span_err(i.span, "async functions cannot be used for tests"); + if let ast::Async::Yes { span, .. } = sig.header.asyncness { + sd.struct_span_err(i.span, "async functions cannot be used for tests") + .span_label(span, "async because of this") + .emit(); return false; } diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index 11f94ab2e6279..af22e46eb6afa 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -507,7 +507,7 @@ impl<'a> ExtCtxt<'a> { span, ast::ExprKind::Closure( ast::CaptureBy::Ref, - ast::IsAsync::NotAsync, + ast::Async::No, ast::Movability::Movable, fn_decl, body, @@ -530,7 +530,7 @@ impl<'a> ExtCtxt<'a> { span, ast::ExprKind::Closure( ast::CaptureBy::Ref, - ast::IsAsync::NotAsync, + ast::Async::No, ast::Movability::Movable, fn_decl, body, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 77748d16653a7..5a4225ece65aa 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -13,7 +13,7 @@ use syntax::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_ use syntax::ast::{ AnonConst, BinOp, BinOpKind, FnDecl, FunctionRetTy, Mac, Param, Ty, TyKind, UnOp, }; -use syntax::ast::{Arm, BlockCheckMode, Expr, ExprKind, IsAsync, Label, Movability, RangeLimits}; +use syntax::ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use syntax::ptr::P; use syntax::token::{self, Token, TokenKind}; use syntax::util::classify; @@ -1348,7 +1348,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; let asyncness = - if self.token.span.rust_2018() { self.parse_asyncness() } else { IsAsync::NotAsync }; + if self.token.span.rust_2018() { self.parse_asyncness() } else { Async::No }; if asyncness.is_async() { // Feature-gate `async ||` closures. self.sess.gated_spans.gate(sym::async_closure, self.prev_span); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index a66a85b2b830f..aa43c15e286ed 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -6,13 +6,13 @@ use crate::maybe_whole; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey}; -use rustc_span::source_map::{self, respan, Span}; +use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; +use syntax::ast::{Async, Const, Defaultness, Extern, IsAuto, PathSegment, StrLit, Unsafe}; use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind}; -use syntax::ast::{Const, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafe}; use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind}; use syntax::ptr::P; @@ -105,10 +105,9 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM - let fn_span = self.prev_span; let header = FnHeader { unsafety: Unsafe::No, - asyncness: respan(fn_span, IsAsync::NotAsync), + asyncness: Async::No, constness: Const::No, ext: Extern::from_abi(abi), }; @@ -140,12 +139,7 @@ impl<'a> Parser<'a> { let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; - let header = FnHeader { - unsafety, - asyncness: respan(const_span, IsAsync::NotAsync), - constness, - ext, - }; + let header = FnHeader { unsafety, asyncness: Async::No, constness, ext }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -172,16 +166,9 @@ impl<'a> Parser<'a> { let async_span = self.token.span; if self.is_keyword_ahead(1, &[kw::Fn]) || self.is_keyword_ahead(2, &[kw::Fn]) { // ASYNC FUNCTION ITEM - self.bump(); // `async` + let asyncness = self.parse_asyncness(); // `async` let unsafety = self.parse_unsafety(); // `unsafe`? self.expect_keyword(kw::Fn)?; // `fn` - let asyncness = respan( - async_span, - IsAsync::Async { - closure_id: DUMMY_NODE_ID, - return_impl_trait_id: DUMMY_NODE_ID, - }, - ); self.ban_async_in_2015(async_span); let header = FnHeader { unsafety, asyncness, constness: Const::No, ext: Extern::None }; @@ -211,13 +198,7 @@ impl<'a> Parser<'a> { if self.check_keyword(kw::Fn) { // FUNCTION ITEM self.bump(); - let fn_span = self.prev_span; - let header = FnHeader { - unsafety: Unsafe::No, - asyncness: respan(fn_span, IsAsync::NotAsync), - constness: Const::No, - ext: Extern::None, - }; + let header = FnHeader::default(); return self.parse_item_fn(lo, vis, attrs, header); } @@ -230,13 +211,7 @@ impl<'a> Parser<'a> { self.check(&token::OpenDelim(token::Brace)); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; - let fn_span = self.prev_span; - let header = FnHeader { - unsafety, - asyncness: respan(fn_span, IsAsync::NotAsync), - constness: Const::No, - ext, - }; + let header = FnHeader { unsafety, asyncness: Async::No, constness: Const::No, ext }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -1788,10 +1763,9 @@ impl<'a> Parser<'a> { fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let constness = self.parse_constness(); let asyncness = self.parse_asyncness(); - if let IsAsync::Async { .. } = asyncness { - self.ban_async_in_2015(self.prev_span); + if let Async::Yes { span, .. } = asyncness { + self.ban_async_in_2015(span); } - let asyncness = respan(self.prev_span, asyncness); let unsafety = self.parse_unsafety(); let (constness, unsafety, ext) = if let Const::Yes(_) = constness { (constness, unsafety, Extern::None) diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index bccf5968118b4..2f2f2f8f176e5 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -24,7 +24,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{FileName, Span, DUMMY_SP}; use syntax::ast::DUMMY_NODE_ID; use syntax::ast::{self, AttrStyle, AttrVec, Const, CrateSugar, Extern, Ident, Unsafe}; -use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; +use syntax::ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; use syntax::ptr::P; use syntax::token::{self, DelimToken, Token, TokenKind}; use syntax::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; @@ -954,11 +954,12 @@ impl<'a> Parser<'a> { } /// Parses asyncness: `async` or nothing. - fn parse_asyncness(&mut self) -> IsAsync { + fn parse_asyncness(&mut self) -> Async { if self.eat_keyword(kw::Async) { - IsAsync::Async { closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } + let span = self.prev_span; + Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } } else { - IsAsync::NotAsync + Async::No } } diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index 3a26197c1607a..fe80dec513cfe 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -48,8 +48,8 @@ impl<'a> DefCollector<'a> { decl: &'a FnDecl, body: Option<&'a Block>, ) { - let (closure_id, return_impl_trait_id) = match header.asyncness.node { - IsAsync::Async { closure_id, return_impl_trait_id } => { + let (closure_id, return_impl_trait_id) = match header.asyncness { + Async::Yes { span: _, closure_id, return_impl_trait_id } => { (closure_id, return_impl_trait_id) } _ => unreachable!(), @@ -117,7 +117,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), - ItemKind::Fn(sig, generics, body) if sig.header.asyncness.node.is_async() => { + ItemKind::Fn(sig, generics, body) if sig.header.asyncness.is_async() => { return self.visit_async_fn( i.id, i.ident.name, @@ -215,7 +215,7 @@ 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.node.is_async() => { + AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.is_async() => { return self.visit_async_fn( i.id, i.ident.name, @@ -255,10 +255,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // we must create two defs. let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); match asyncness { - IsAsync::Async { closure_id, .. } => { + Async::Yes { closure_id, .. } => { self.create_def(closure_id, DefPathData::ClosureExpr, expr.span) } - IsAsync::NotAsync => closure_def, + Async::No => closure_def, } } ExprKind::Async(_, async_id, _) => { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 01a0e568137b2..58ff7f447890c 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -2030,7 +2030,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. - ExprKind::Closure(_, IsAsync::Async { .. }, _, ref fn_decl, ref body, _span) => { + ExprKind::Closure(_, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => { self.with_rib(ValueNS, NormalRibKind, |this| { // Resolve arguments: this.resolve_params(&fn_decl.inputs); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5ce81c104e17c..01e3e3f368529 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -290,8 +290,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { // as an `impl Trait` existential type. Because of this, to match // the definition paths when resolving nested types we need to // start walking from the newly-created definition. - match sig.header.asyncness.node { - ast::IsAsync::Async { return_impl_trait_id, .. } => { + match sig.header.asyncness { + ast::Async::Yes { return_impl_trait_id, .. } => { v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty)) } _ => v.visit_ty(ret_ty), @@ -383,8 +383,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { // as an `impl Trait` existential type. Because of this, to match // the definition paths when resolving nested types we need to // start walking from the newly-created definition. - match header.asyncness.node { - ast::IsAsync::Async { return_impl_trait_id, .. } => { + match header.asyncness { + ast::Async::Yes { return_impl_trait_id, .. } => { v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty)) } _ => v.visit_ty(ret_ty), diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 820202c85ab87..d3c4d6d5723b9 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -368,7 +368,7 @@ impl Sig for ast::Item { if let ast::Const::Yes(_) = header.constness { text.push_str("const "); } - if header.asyncness.node.is_async() { + if header.asyncness.is_async() { text.push_str("async "); } if let ast::Unsafe::Yes(_) = header.unsafety { @@ -887,7 +887,7 @@ fn make_method_signature( if let ast::Const::Yes(_) = m.header.constness { text.push_str("const "); } - if m.header.asyncness.node.is_async() { + if m.header.asyncness.is_async() { text.push_str("async "); } if let ast::Unsafe::Yes(_) = m.header.unsafety { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a7142dfda8593..72430fa9c17e4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -34,7 +34,7 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; use rustc_serialize::{self, Decoder, Encoder}; -use rustc_span::source_map::{dummy_spanned, respan, Spanned}; +use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -1198,14 +1198,14 @@ pub enum ExprKind { /// A closure (e.g., `move |a, b, c| a + b + c`). /// /// The final span is the span of the argument block `|...|`. - Closure(CaptureBy, IsAsync, Movability, P<FnDecl>, P<Expr>, Span), + Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span), /// A block (`'label: { ... }`). Block(P<Block>, Option<Label>), /// An async block (`async move { ... }`). /// /// The `NodeId` is the `NodeId` for the closure that results from /// desugaring an async block, just like the NodeId field in the - /// `IsAsync` enum. This is necessary in order to create a def for the + /// `Async::Yes` variant. This is necessary in order to create a def for the /// closure which can be used as a parent of any child defs. Defs /// created during lowering cannot be made the parent of any other /// preexisting defs. @@ -2109,21 +2109,21 @@ pub enum Unsafe { } #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum IsAsync { - Async { closure_id: NodeId, return_impl_trait_id: NodeId }, - NotAsync, +pub enum Async { + Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, + No, } -impl IsAsync { +impl Async { pub fn is_async(self) -> bool { - if let IsAsync::Async { .. } = self { true } else { false } + if let Async::Yes { .. } = self { true } else { false } } /// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item. pub fn opt_return_id(self) -> Option<NodeId> { match self { - IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id), - IsAsync::NotAsync => None, + Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id), + Async::No => None, } } } @@ -2496,7 +2496,7 @@ impl Extern { #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub struct FnHeader { pub unsafety: Unsafe, - pub asyncness: Spanned<IsAsync>, + pub asyncness: Async, pub constness: Const, pub ext: Extern, } @@ -2506,7 +2506,7 @@ impl FnHeader { pub fn has_qualifiers(&self) -> bool { let Self { unsafety, asyncness, constness, ext } = self; matches!(unsafety, Unsafe::Yes(_)) - || asyncness.node.is_async() + || asyncness.is_async() || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } @@ -2516,7 +2516,7 @@ impl Default for FnHeader { fn default() -> FnHeader { FnHeader { unsafety: Unsafe::No, - asyncness: dummy_spanned(IsAsync::NotAsync), + asyncness: Async::No, constness: Const::No, ext: Extern::None, } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 8517f223f92e3..e0180d451936f 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -114,7 +114,7 @@ pub trait MutVisitor: Sized { noop_visit_fn_decl(d, self); } - fn visit_asyncness(&mut self, a: &mut IsAsync) { + fn visit_asyncness(&mut self, a: &mut Async) { noop_visit_asyncness(a, self); } @@ -728,13 +728,13 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: } } -pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) { +pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) { match asyncness { - IsAsync::Async { closure_id, return_impl_trait_id } => { + Async::Yes { span: _, closure_id, return_impl_trait_id } => { vis.visit_id(closure_id); vis.visit_id(return_impl_trait_id); } - IsAsync::NotAsync => {} + Async::No => {} } } @@ -980,7 +980,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>( pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) { let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header; - vis.visit_asyncness(&mut asyncness.node); + vis.visit_asyncness(asyncness); } pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) { diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 0f6a88b2691a8..7ac75c605f2e4 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -121,7 +121,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { }); iter_exprs(depth - 1, &mut |e| g( ExprKind::Closure(CaptureBy::Value, - IsAsync::NotAsync, + Async::No, Movability::Movable, decl.clone(), e, diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr index 9acfa2cc06912..04f72fb645e28 100644 --- a/src/test/ui/async-await/async-trait-fn.stderr +++ b/src/test/ui/async-await/async-trait-fn.stderr @@ -2,7 +2,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/async-trait-fn.rs:3:5 | LL | async fn foo() {} - | ^^^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait @@ -11,7 +13,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/async-trait-fn.rs:4:5 | LL | async fn bar(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index bb09ee9a93296..e6859a3cd93a0 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -56,7 +56,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} - | ^^^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 41d2d9b7faaf1..689bbdd8bab88 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -2,7 +2,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:17:9 | LL | async fn ft1(); - | ^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait @@ -17,7 +19,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:21:21 | LL | /* const */ async unsafe extern "C" fn ft5(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait @@ -26,7 +30,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:28:9 | LL | async fn ft1() {} - | ^^^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait @@ -41,7 +47,9 @@ error[E0706]: trait fns cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:33:21 | LL | /* const */ async unsafe extern "C" fn ft5() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait From 36a17e4067d2e67223cd9a172476ee5503d6b44b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Thu, 30 Jan 2020 08:31:31 +0100 Subject: [PATCH 03/13] parser_fn_front_matter: allow `const .. extern` --- src/librustc_parse/parser/item.rs | 105 +++++++++--------- src/librustc_parse/parser/stmt.rs | 2 +- src/test/ui/issues/issue-60075.rs | 1 - src/test/ui/issues/issue-60075.stderr | 8 +- src/test/ui/parser/fn-header-semantic-fail.rs | 15 +-- .../ui/parser/fn-header-semantic-fail.stderr | 68 +++++++----- .../ui/parser/fn-header-syntactic-pass.rs | 12 +- 7 files changed, 104 insertions(+), 107 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index aa43c15e286ed..d2bcf31cb0551 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -798,12 +798,12 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness(); let (name, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_assoc_ty()? - } else if self.is_const_item() { - self.parse_assoc_const()? + } else if self.is_fn_front_matter() { + self.parse_assoc_fn(at_end, &mut attrs, is_name_required)? } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? { (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default()) } else { - self.parse_assoc_fn(at_end, &mut attrs, is_name_required)? + self.parse_assoc_const()? }; Ok(AssocItem { @@ -819,12 +819,6 @@ impl<'a> Parser<'a> { }) } - /// Returns `true` if we are looking at `const ID` - /// (returns `false` for things like `const fn`, etc.). - fn is_const_item(&self) -> bool { - self.token.is_keyword(kw::Const) && !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) - } - /// This parses the grammar: /// /// AssocConst = "const" Ident ":" Ty "=" Expr ";" @@ -1034,21 +1028,20 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let visibility = self.parse_visibility(FollowedByType::No)?; + let vis = self.parse_visibility(FollowedByType::No)?; - // FOREIGN TYPE ITEM if self.check_keyword(kw::Type) { - return self.parse_item_foreign_type(visibility, lo, attrs); - } - - // FOREIGN STATIC ITEM - if self.is_static_global() { + // FOREIGN TYPE ITEM + self.parse_item_foreign_type(vis, lo, attrs) + } else if self.is_fn_front_matter() { + // FOREIGN FUNCTION ITEM + self.parse_item_foreign_fn(vis, lo, attrs) + } else if self.is_static_global() { + // FOREIGN STATIC ITEM self.bump(); // `static` - return self.parse_item_foreign_static(visibility, lo, attrs); - } - - // Treat `const` as `static` for error recovery, but don't add it to expected tokens. - if self.is_kw_followed_by_ident(kw::Const) { + self.parse_item_foreign_static(vis, lo, attrs) + } 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( @@ -1058,32 +1051,17 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ) .emit(); - return self.parse_item_foreign_static(visibility, lo, attrs); - } - - // FOREIGN FUNCTION ITEM - const MAY_INTRODUCE_FN: &[Symbol] = &[kw::Const, kw::Async, kw::Unsafe, kw::Extern, kw::Fn]; - if MAY_INTRODUCE_FN.iter().any(|&kw| self.check_keyword(kw)) { - return self.parse_item_foreign_fn(visibility, lo, attrs); - } - - match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { - Some(mac) => Ok(P(ForeignItem { - ident: Ident::invalid(), - span: lo.to(self.prev_span), - id: DUMMY_NODE_ID, - attrs, - vis: visibility, - kind: ForeignItemKind::Macro(mac), - tokens: None, - })), - None => { - if !attrs.is_empty() { - self.expected_item_err(&attrs)?; - } - - self.unexpected() + self.parse_item_foreign_static(vis, lo, attrs) + } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? { + let kind = ForeignItemKind::Macro(mac); + let span = lo.to(self.prev_span); + let ident = Ident::invalid(); + Ok(P(ForeignItem { ident, span, id: DUMMY_NODE_ID, attrs, vis, kind, tokens: None })) + } else { + if !attrs.is_empty() { + self.expected_item_err(&attrs)?; } + self.unexpected() } } @@ -1752,6 +1730,29 @@ impl<'a> Parser<'a> { Ok(body) } + /// Is the current token unambiguously the start of an `FnHeader`? + fn is_fn_front_matter(&mut self) -> bool { + // We use an over-approximation here. + // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. + // This works for `async fn` and similar as `async async` is an invalid + // parse and `async fn` is never a valid parse on previous editions. + const QUALIFIER: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; + + let check_qual_follow = |this: &mut Self, dist| { + this.look_ahead(dist, |t| { + // ...qualified and then `fn`, e.g. `const fn`. + t.is_keyword(kw::Fn) + // Two qualifiers. This is enough. + || QUALIFIER.iter().any(|&kw| t.is_keyword(kw)) + }) + }; + self.check_keyword(kw::Fn) // Definitely an `fn`. + // `$qual fn` or `$qual $qual`: + || QUALIFIER.iter().any(|&kw| self.check_keyword(kw)) && check_qual_follow(self, 1) + // `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI. + || self.check_keyword(kw::Extern) && check_qual_follow(self, 2) + } + /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, /// up to and including the `fn` keyword. The formal grammar is: /// @@ -1763,16 +1764,13 @@ impl<'a> Parser<'a> { fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let constness = self.parse_constness(); let asyncness = self.parse_asyncness(); + let unsafety = self.parse_unsafety(); + let ext = self.parse_extern()?; + if let Async::Yes { span, .. } = asyncness { self.ban_async_in_2015(span); } - let unsafety = self.parse_unsafety(); - let (constness, unsafety, ext) = if let Const::Yes(_) = constness { - (constness, unsafety, Extern::None) - } else { - let ext = self.parse_extern()?; - (Const::No, unsafety, ext) - }; + if !self.eat_keyword(kw::Fn) { // It is possible for `expect_one_of` to recover given the contents of // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't @@ -1781,6 +1779,7 @@ impl<'a> Parser<'a> { unreachable!() } } + Ok(FnHeader { constness, unsafety, asyncness, ext }) } diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index e11cdd5dadb72..e97af0dc00c69 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -199,7 +199,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { + fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs index 7d3fc83786e9d..1323f646be893 100644 --- a/src/test/ui/issues/issue-60075.rs +++ b/src/test/ui/issues/issue-60075.rs @@ -6,6 +6,5 @@ trait T { }); //~^ ERROR expected one of `async` //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}` -//~| ERROR expected identifier, found `;` Some(4) } diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr index e8ef981f515fc..60eb99b46b79f 100644 --- a/src/test/ui/issues/issue-60075.stderr +++ b/src/test/ui/issues/issue-60075.stderr @@ -13,11 +13,5 @@ LL | let _ = if true { LL | }); | ^ help: `}` may belong here -error: expected identifier, found `;` - --> $DIR/issue-60075.rs:6:11 - | -LL | }); - | ^ expected identifier - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs index c2b7e69c80d8e..98ff2b6d2e8b3 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.rs +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -18,9 +18,9 @@ fn main() { unsafe fn ft2(); // OK. const fn ft3(); //~ ERROR trait fns cannot be declared const extern "C" fn ft4(); // OK. - /* const */ async unsafe extern "C" fn ft5(); + const async unsafe extern "C" fn ft5(); //~^ ERROR trait fns cannot be declared `async` - //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + //~| ERROR trait fns cannot be declared const } struct Y; @@ -30,10 +30,10 @@ fn main() { unsafe fn ft2() {} // OK. const fn ft3() {} //~ ERROR trait fns cannot be declared const extern "C" fn ft4() {} - /* const */ async unsafe extern "C" fn ft5() {} + const async unsafe extern "C" fn ft5() {} //~^ ERROR trait fns cannot be declared `async` + //~| ERROR trait fns cannot be declared const //~| ERROR method `ft5` has an incompatible type for trait - //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. } impl Y { @@ -41,8 +41,7 @@ fn main() { unsafe fn fi2() {} // OK. const fn fi3() {} // OK. extern "C" fn fi4() {} // OK. - /* const */ async unsafe extern "C" fn fi5() {} // OK. - //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + const async unsafe extern "C" fn fi5() {} // OK. } extern { @@ -50,8 +49,6 @@ fn main() { unsafe fn fe2(); //~ ERROR functions in `extern` blocks cannot have qualifiers const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers - /* const */ async unsafe extern "C" fn fe5(); - //~^ ERROR functions in `extern` blocks cannot have qualifiers - //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks } } diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 689bbdd8bab88..1860106b255ab 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -15,13 +15,19 @@ error[E0379]: trait fns cannot be declared const LL | const fn ft3(); | ^^^^^ trait fns cannot be const +error[E0379]: trait fns cannot be declared const + --> $DIR/fn-header-semantic-fail.rs:21:9 + | +LL | const async unsafe extern "C" fn ft5(); + | ^^^^^ trait fns cannot be const + error[E0706]: trait fns cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:21:21 + --> $DIR/fn-header-semantic-fail.rs:21:9 | -LL | /* const */ async unsafe extern "C" fn ft5(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this +LL | const async unsafe extern "C" fn ft5(); + | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait @@ -43,19 +49,25 @@ error[E0379]: trait fns cannot be declared const LL | const fn ft3() {} | ^^^^^ trait fns cannot be const +error[E0379]: trait fns cannot be declared const + --> $DIR/fn-header-semantic-fail.rs:33:9 + | +LL | const async unsafe extern "C" fn ft5() {} + | ^^^^^ trait fns cannot be const + error[E0706]: trait fns cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:33:21 + --> $DIR/fn-header-semantic-fail.rs:33:9 | -LL | /* const */ async unsafe extern "C" fn ft5() {} - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this +LL | const async unsafe extern "C" fn ft5() {} + | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `async` because of this | = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:49:18 + --> $DIR/fn-header-semantic-fail.rs:48:18 | LL | extern { | ------ in this `extern` block @@ -65,7 +77,7 @@ LL | async fn fe1(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:19 + --> $DIR/fn-header-semantic-fail.rs:49:19 | LL | extern { | ------ in this `extern` block @@ -76,7 +88,7 @@ LL | unsafe fn fe2(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:51:18 + --> $DIR/fn-header-semantic-fail.rs:50:18 | LL | extern { | ------ in this `extern` block @@ -87,7 +99,7 @@ LL | const fn fe3(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:52:23 + --> $DIR/fn-header-semantic-fail.rs:51:23 | LL | extern { | ------ in this `extern` block @@ -98,15 +110,15 @@ LL | extern "C" fn fe4(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:53:48 + --> $DIR/fn-header-semantic-fail.rs:52:42 | LL | extern { | ------ in this `extern` block ... -LL | /* const */ async unsafe extern "C" fn fe5(); - | ---------------------------^^^ - | | - | help: remove the qualifiers: `fn` +LL | const async unsafe extern "C" fn fe5(); + | ---------------------------------^^^ + | | + | help: remove the qualifiers: `fn` error[E0053]: method `ft1` has an incompatible type for trait --> $DIR/fn-header-semantic-fail.rs:28:24 @@ -124,21 +136,21 @@ LL | async fn ft1() {} found fn pointer `fn() -> impl std::future::Future` error[E0053]: method `ft5` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:33:54 + --> $DIR/fn-header-semantic-fail.rs:33:48 | -LL | /* const */ async unsafe extern "C" fn ft5(); - | - type in trait +LL | const async unsafe extern "C" fn ft5(); + | - type in trait ... -LL | /* const */ async unsafe extern "C" fn ft5() {} - | ^ - | | - | the `Output` of this `async fn`'s found opaque type - | expected `()`, found opaque type +LL | const async unsafe extern "C" fn ft5() {} + | ^ + | | + | the `Output` of this `async fn`'s found opaque type + | expected `()`, found opaque type | = note: expected fn pointer `unsafe extern "C" fn()` found fn pointer `unsafe extern "C" fn() -> impl std::future::Future` -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors Some errors have detailed explanations: E0053, E0379, E0706. For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/parser/fn-header-syntactic-pass.rs b/src/test/ui/parser/fn-header-syntactic-pass.rs index 145a208cb249d..0557b9ef6ca23 100644 --- a/src/test/ui/parser/fn-header-syntactic-pass.rs +++ b/src/test/ui/parser/fn-header-syntactic-pass.rs @@ -22,8 +22,7 @@ fn syntax() { unsafe fn f(); const fn f(); extern "C" fn f(); - /* const */ async unsafe extern "C" fn f(); - //^ FIXME(Centril): `const` should be legal syntactically. + const async unsafe extern "C" fn f(); } impl X for Y { @@ -31,8 +30,7 @@ fn syntax() { unsafe fn f(); const fn f(); extern "C" fn f(); - /* const */ async unsafe extern "C" fn f(); - //^ FIXME(Centril): `const` should be legal syntactically. + const async unsafe extern "C" fn f(); } impl Y { @@ -40,8 +38,7 @@ fn syntax() { unsafe fn f(); const fn f(); extern "C" fn f(); - /* const */ async unsafe extern "C" fn f(); - //^ FIXME(Centril): `const` should be legal syntactically. + const async unsafe extern "C" fn f(); } extern { @@ -49,7 +46,6 @@ fn syntax() { unsafe fn f(); const fn f(); extern "C" fn f(); - /* const */ async unsafe extern "C" fn f(); - //^ FIXME(Centril): `const` should be legal syntactically. + const async unsafe extern "C" fn f(); } } From a833be21626890de406e12f2561d2ffbda4aadb4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Thu, 30 Jan 2020 13:02:06 +0100 Subject: [PATCH 04/13] parser: fuse free `fn` parsing together. --- src/librustc_ast_passes/ast_validation.rs | 14 +++ src/librustc_ast_passes/feature_gate.rs | 12 +- src/librustc_parse/parser/item.rs | 111 ++++-------------- src/libsyntax/token.rs | 8 +- src/libsyntax/util/literal.rs | 2 + src/test/ui/async-await/no-async-const.rs | 2 +- src/test/ui/async-await/no-async-const.stderr | 4 +- src/test/ui/async-await/no-const-async.rs | 3 +- src/test/ui/async-await/no-const-async.stderr | 17 ++- src/test/ui/async-await/no-unsafe-async.rs | 2 +- .../ui/async-await/no-unsafe-async.stderr | 4 +- .../feature-gate-const_extern_fn.rs | 14 +-- .../feature-gate-const_extern_fn.stderr | 36 +++--- ...const-extern-fns-dont-need-fn-specifier.rs | 1 - ...t-extern-fns-dont-need-fn-specifier.stderr | 12 +- .../label/label_break_value_illegal_uses.rs | 2 +- .../label_break_value_illegal_uses.stderr | 4 +- .../parser/extern-crate-unexpected-token.rs | 2 +- .../extern-crate-unexpected-token.stderr | 4 +- .../ui/parser/extern-expected-fn-or-brace.rs | 5 +- .../parser/extern-expected-fn-or-brace.stderr | 6 +- src/test/ui/parser/fn-header-semantic-fail.rs | 10 +- .../ui/parser/fn-header-semantic-fail.stderr | 69 +++++++++-- .../ui/parser/fn-header-syntactic-pass.rs | 6 +- src/test/ui/parser/issue-19398.rs | 2 +- src/test/ui/parser/issue-19398.stderr | 8 +- .../ui/unsafe/unsafe-block-without-braces.rs | 2 +- .../unsafe/unsafe-block-without-braces.stderr | 4 +- 28 files changed, 181 insertions(+), 185 deletions(-) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index e0217de1d3b8d..0bc6179dabf5b 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -1089,6 +1089,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_c_varadic_type(fk); + // Functions cannot both be `const async` + if let Some(FnHeader { + constness: Const::Yes(cspan), + asyncness: Async::Yes { span: aspan, .. }, + .. + }) = fk.header() + { + self.err_handler() + .struct_span_err(span, "functions cannot be both `const` and `async`") + .span_label(*cspan, "`const` because of this") + .span_label(*aspan, "`async` because of this") + .emit(); + } + // Functions without bodies cannot have patterns. if let FnKind::Fn(ctxt, _, sig, _, None) = fk { Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index cfab54925b161..0b21de4d78b41 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -496,6 +496,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(header) = fn_kind.header() { // Stability of const fn methods are covered in `visit_assoc_item` below. self.check_extern(header.ext); + + if let (ast::Const::Yes(_), ast::Extern::Implicit) + | (ast::Const::Yes(_), ast::Extern::Explicit(_)) = (header.constness, header.ext) + { + gate_feature_post!( + &self, + const_extern_fn, + span, + "`const extern fn` definitions are unstable" + ); + } } if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { @@ -595,7 +606,6 @@ pub fn check_crate( gate_all!(async_closure, "async closures are unstable"); gate_all!(generators, "yield syntax is experimental"); gate_all!(or_patterns, "or-patterns syntax is experimental"); - gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d2bcf31cb0551..906b82f746b24 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; -use syntax::ast::{Async, Const, Defaultness, Extern, IsAuto, PathSegment, StrLit, Unsafe}; +use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, StrLit, 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}; @@ -96,53 +96,30 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } + if self.is_fn_front_matter() { + // FUNCTION ITEM + return self.parse_item_fn(lo, vis, attrs); + } + if self.eat_keyword(kw::Extern) { if self.eat_keyword(kw::Crate) { + // EXTERN CRATE return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } - + // EXTERN BLOCK let abi = self.parse_abi(); - - if self.eat_keyword(kw::Fn) { - // EXTERN FUNCTION ITEM - let header = FnHeader { - unsafety: Unsafe::No, - asyncness: Async::No, - constness: Const::No, - ext: Extern::from_abi(abi), - }; - return self.parse_item_fn(lo, vis, attrs, header); - } else if self.check(&token::OpenDelim(token::Brace)) { - return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); - } - - self.unexpected()?; + return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); } if self.is_static_global() { - self.bump(); // STATIC ITEM + self.bump(); let m = self.parse_mutability(); let info = self.parse_item_const(Some(m))?; return self.mk_item_with_info(attrs, lo, vis, info); } - let constness = self.parse_constness(); - if let Const::Yes(const_span) = constness { - if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) { - // CONST FUNCTION ITEM - let unsafety = self.parse_unsafety(); - - if self.check_keyword(kw::Extern) { - self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span)); - } - let ext = self.parse_extern()?; - self.expect_keyword(kw::Fn)?; - - let header = FnHeader { unsafety, asyncness: Async::No, constness, ext }; - return self.parse_item_fn(lo, vis, attrs, header); - } - + if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM if self.eat_keyword(kw::Mut) { let prev_span = self.prev_span; @@ -161,21 +138,6 @@ impl<'a> Parser<'a> { return self.mk_item_with_info(attrs, lo, vis, info); } - // Parses `async unsafe? fn`. - if self.check_keyword(kw::Async) { - let async_span = self.token.span; - if self.is_keyword_ahead(1, &[kw::Fn]) || self.is_keyword_ahead(2, &[kw::Fn]) { - // ASYNC FUNCTION ITEM - let asyncness = self.parse_asyncness(); // `async` - let unsafety = self.parse_unsafety(); // `unsafe`? - self.expect_keyword(kw::Fn)?; // `fn` - self.ban_async_in_2015(async_span); - let header = - FnHeader { unsafety, asyncness, constness: Const::No, ext: Extern::None }; - return self.parse_item_fn(lo, vis, attrs, header); - } - } - if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) { // UNSAFE TRAIT ITEM let unsafety = self.parse_unsafety(); @@ -195,26 +157,6 @@ impl<'a> Parser<'a> { return self.mk_item_with_info(attrs, lo, vis, info); } - if self.check_keyword(kw::Fn) { - // FUNCTION ITEM - self.bump(); - let header = FnHeader::default(); - return self.parse_item_fn(lo, vis, attrs, header); - } - - if self.check_keyword(kw::Unsafe) - && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) - { - // UNSAFE FUNCTION ITEM - let unsafety = self.parse_unsafety(); - // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic. - self.check(&token::OpenDelim(token::Brace)); - let ext = self.parse_extern()?; - self.expect_keyword(kw::Fn)?; - let header = FnHeader { unsafety, asyncness: Async::No, constness: Const::No, ext }; - return self.parse_item_fn(lo, vis, attrs, header); - } - if self.eat_keyword(kw::Mod) { // MODULE ITEM let info = self.parse_item_mod(&attrs[..])?; @@ -1662,9 +1604,9 @@ impl<'a> Parser<'a> { lo: Span, vis: Visibility, mut attrs: Vec<Attribute>, - header: FnHeader, ) -> PResult<'a, Option<P<Item>>> { let cfg = ParamCfg { is_name_required: |_| true }; + let header = self.parse_fn_front_matter()?; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; let body = self.parse_fn_body(&mut false, &mut attrs)?; let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); @@ -1730,27 +1672,24 @@ impl<'a> Parser<'a> { Ok(body) } - /// Is the current token unambiguously the start of an `FnHeader`? + /// Is the current token the start of an `FnHeader` / not a valid parse? fn is_fn_front_matter(&mut self) -> bool { // We use an over-approximation here. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. - // This works for `async fn` and similar as `async async` is an invalid - // parse and `async fn` is never a valid parse on previous editions. - const QUALIFIER: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; - - let check_qual_follow = |this: &mut Self, dist| { - this.look_ahead(dist, |t| { - // ...qualified and then `fn`, e.g. `const fn`. - t.is_keyword(kw::Fn) - // Two qualifiers. This is enough. - || QUALIFIER.iter().any(|&kw| t.is_keyword(kw)) - }) - }; + const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; self.check_keyword(kw::Fn) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: - || QUALIFIER.iter().any(|&kw| self.check_keyword(kw)) && check_qual_follow(self, 1) - // `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI. - || self.check_keyword(kw::Extern) && check_qual_follow(self, 2) + || QUALS.iter().any(|&kw| self.check_keyword(kw)) + && self.look_ahead(1, |t| { + // ...qualified and then `fn`, e.g. `const fn`. + t.is_keyword(kw::Fn) + // Two qualifiers. This is enough. Due `async` we need to check that it's reserved. + || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved()) + }) + // `extern ABI fn` + || self.check_keyword(kw::Extern) + && self.look_ahead(1, |t| t.can_begin_literal_or_bool()) + && self.look_ahead(2, |t| t.is_keyword(kw::Fn)) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs index 3045f147698a5..862934300e085 100644 --- a/src/libsyntax/token.rs +++ b/src/libsyntax/token.rs @@ -402,12 +402,14 @@ impl Token { /// Returns `true` if the token is any literal, a minus (which can prefix a literal, /// for example a '-42', or one of the boolean idents). + /// + /// Keep this in sync with `Lit::from_token`. pub fn can_begin_literal_or_bool(&self) -> bool { match self.kind { Literal(..) | BinOp(Minus) => true, Ident(name, false) if name.is_bool_lit() => true, - Interpolated(ref nt) => match **nt { - NtLiteral(..) => true, + Interpolated(ref nt) => match &**nt { + NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)), _ => false, }, _ => false, @@ -530,7 +532,7 @@ impl Token { } /// Returns `true` if the token is a non-raw identifier for which `pred` holds. - fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { + pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { match self.ident() { Some((id, false)) => pred(id), _ => false, diff --git a/src/libsyntax/util/literal.rs b/src/libsyntax/util/literal.rs index dd06c25b4de0f..0c611adc06bcf 100644 --- a/src/libsyntax/util/literal.rs +++ b/src/libsyntax/util/literal.rs @@ -188,6 +188,8 @@ impl Lit { } /// Converts arbitrary token into an AST literal. + /// + /// Keep this in sync with `Token::can_begin_literal_or_bool`. pub fn from_token(token: &Token) -> Result<Lit, LitError> { let lit = match token.kind { token::Ident(name, false) if name.is_bool_lit() => { diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs index 64322990d0a93..963460c118249 100644 --- a/src/test/ui/async-await/no-async-const.rs +++ b/src/test/ui/async-await/no-async-const.rs @@ -2,4 +2,4 @@ // compile-flags: --crate-type lib pub async const fn x() {} -//~^ ERROR expected one of `fn` or `unsafe`, found keyword `const` +//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const` diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr index d5b8b344abe62..e324a77187ab6 100644 --- a/src/test/ui/async-await/no-async-const.stderr +++ b/src/test/ui/async-await/no-async-const.stderr @@ -1,8 +1,8 @@ -error: expected one of `fn` or `unsafe`, found keyword `const` +error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const` --> $DIR/no-async-const.rs:4:11 | LL | pub async const fn x() {} - | ^^^^^ expected one of `fn` or `unsafe` + | ^^^^^ expected one of `extern`, `fn`, or `unsafe` error: aborting due to previous error diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs index 55b27bd3fa1ac..b3c59734e036f 100644 --- a/src/test/ui/async-await/no-const-async.rs +++ b/src/test/ui/async-await/no-const-async.rs @@ -2,5 +2,4 @@ // compile-flags: --crate-type lib pub const async fn x() {} -//~^ ERROR expected identifier, found keyword `async` -//~^^ expected `:`, found keyword `fn` +//~^ ERROR functions cannot be both `const` and `async` diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index 62cd5c45d1950..f6ae0f1447ced 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -1,14 +1,11 @@ -error: expected identifier, found keyword `async` - --> $DIR/no-const-async.rs:4:11 +error: functions cannot be both `const` and `async` + --> $DIR/no-const-async.rs:4:1 | LL | pub const async fn x() {} - | ^^^^^ expected identifier, found keyword + | ^^^^-----^-----^^^^^^^^^^ + | | | + | | `async` because of this + | `const` because of this -error: expected `:`, found keyword `fn` - --> $DIR/no-const-async.rs:4:17 - | -LL | pub const async fn x() {} - | ^^ expected `:` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs index 1ac1bdffda947..f40154e16f34e 100644 --- a/src/test/ui/async-await/no-unsafe-async.rs +++ b/src/test/ui/async-await/no-unsafe-async.rs @@ -8,4 +8,4 @@ impl S { } #[cfg(FALSE)] -unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found keyword `async` +unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr index bbeb34278490b..2651588d59710 100644 --- a/src/test/ui/async-await/no-unsafe-async.stderr +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -4,11 +4,11 @@ error: expected one of `extern` or `fn`, found keyword `async` LL | unsafe async fn g() {} | ^^^^^ expected one of `extern` or `fn` -error: expected one of `extern`, `fn`, or `{`, found keyword `async` +error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:11:8 | LL | unsafe async fn f() {} - | ^^^^^ expected one of `extern`, `fn`, or `{` + | ^^^^^ expected one of `extern` or `fn` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs index d39f2c1fe277e..5667d5535274d 100644 --- a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs +++ b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs @@ -1,12 +1,10 @@ // Check that `const extern fn` and `const unsafe extern fn` are feature-gated. -#[cfg(FALSE)] const extern fn foo1() {} //~ ERROR `const extern fn` definitions are unstable -#[cfg(FALSE)] const extern "C" fn foo2() {} //~ ERROR `const extern fn` definitions are unstable -#[cfg(FALSE)] const extern "Rust" fn foo3() {} //~ ERROR `const extern fn` definitions are unstable -#[cfg(FALSE)] const unsafe extern fn bar1() {} //~ ERROR `const extern fn` definitions are unstable -#[cfg(FALSE)] const unsafe extern "C" fn bar2() {} -//~^ ERROR `const extern fn` definitions are unstable -#[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {} -//~^ ERROR `const extern fn` definitions are unstable +const extern fn foo1() {} //~ ERROR `const extern fn` definitions are unstable +const extern "C" fn foo2() {} //~ ERROR `const extern fn` definitions are unstable +const extern "Rust" fn foo3() {} //~ ERROR `const extern fn` definitions are unstable +const unsafe extern fn bar1() {} //~ ERROR `const extern fn` definitions are unstable +const unsafe extern "C" fn bar2() {} //~ ERROR `const extern fn` definitions are unstable +const unsafe extern "Rust" fn bar3() {} //~ ERROR `const extern fn` definitions are unstable fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr index ed5e0c84a16ae..bd5940a3fd60c 100644 --- a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr +++ b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr @@ -1,53 +1,53 @@ error[E0658]: `const extern fn` definitions are unstable - --> $DIR/feature-gate-const_extern_fn.rs:3:15 + --> $DIR/feature-gate-const_extern_fn.rs:3:1 | -LL | #[cfg(FALSE)] const extern fn foo1() {} - | ^^^^^^^^^^^^ +LL | const extern fn foo1() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable error[E0658]: `const extern fn` definitions are unstable - --> $DIR/feature-gate-const_extern_fn.rs:4:15 + --> $DIR/feature-gate-const_extern_fn.rs:4:1 | -LL | #[cfg(FALSE)] const extern "C" fn foo2() {} - | ^^^^^^^^^^^^ +LL | const extern "C" fn foo2() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable error[E0658]: `const extern fn` definitions are unstable - --> $DIR/feature-gate-const_extern_fn.rs:5:15 + --> $DIR/feature-gate-const_extern_fn.rs:5:1 | -LL | #[cfg(FALSE)] const extern "Rust" fn foo3() {} - | ^^^^^^^^^^^^ +LL | const extern "Rust" fn foo3() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable error[E0658]: `const extern fn` definitions are unstable - --> $DIR/feature-gate-const_extern_fn.rs:6:15 + --> $DIR/feature-gate-const_extern_fn.rs:6:1 | -LL | #[cfg(FALSE)] const unsafe extern fn bar1() {} - | ^^^^^^^^^^^^^^^^^^^ +LL | const unsafe extern fn bar1() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable error[E0658]: `const extern fn` definitions are unstable - --> $DIR/feature-gate-const_extern_fn.rs:7:15 + --> $DIR/feature-gate-const_extern_fn.rs:7:1 | -LL | #[cfg(FALSE)] const unsafe extern "C" fn bar2() {} - | ^^^^^^^^^^^^^^^^^^^ +LL | const unsafe extern "C" fn bar2() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable error[E0658]: `const extern fn` definitions are unstable - --> $DIR/feature-gate-const_extern_fn.rs:9:15 + --> $DIR/feature-gate-const_extern_fn.rs:8:1 | -LL | #[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {} - | ^^^^^^^^^^^^^^^^^^^ +LL | const unsafe extern "Rust" fn bar3() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs index 1886bfccb4e3e..6f575d055a29b 100644 --- a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs @@ -4,5 +4,4 @@ fn main() {} fn container() { const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } //~^ ERROR expected `fn` - //~| ERROR `const extern fn` definitions are unstable } diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr index d36b781d292d2..ec415ec9d0211 100644 --- a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr @@ -4,15 +4,5 @@ error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE` LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn` -error[E0658]: `const extern fn` definitions are unstable - --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:5 - | -LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } - | ^^^^^^^^^^^^ - | - = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information - = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/label/label_break_value_illegal_uses.rs b/src/test/ui/label/label_break_value_illegal_uses.rs index 81cb17743809a..9d4c72410a6d1 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.rs +++ b/src/test/ui/label/label_break_value_illegal_uses.rs @@ -3,7 +3,7 @@ // These are forbidden occurrences of label-break-value fn labeled_unsafe() { - unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{` + unsafe 'b: {} //~ ERROR expected `{`, found `'b` } fn labeled_if() { diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index 46b53c65b4817..fd8850dd8dab2 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -1,8 +1,8 @@ -error: expected one of `extern`, `fn`, or `{`, found `'b` +error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:6:12 | LL | unsafe 'b: {} - | ^^ expected one of `extern`, `fn`, or `{` + | ^^ expected `{` error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:10:13 diff --git a/src/test/ui/parser/extern-crate-unexpected-token.rs b/src/test/ui/parser/extern-crate-unexpected-token.rs index 58b2fa1afdf31..7687f5e64094b 100644 --- a/src/test/ui/parser/extern-crate-unexpected-token.rs +++ b/src/test/ui/parser/extern-crate-unexpected-token.rs @@ -1 +1 @@ -extern crte foo; //~ ERROR expected one of `crate`, `fn`, or `{`, found `crte` +extern crte foo; //~ ERROR expected one of `crate` or `{`, found `crte` diff --git a/src/test/ui/parser/extern-crate-unexpected-token.stderr b/src/test/ui/parser/extern-crate-unexpected-token.stderr index 0e745dc582f4b..e9d287ac0e927 100644 --- a/src/test/ui/parser/extern-crate-unexpected-token.stderr +++ b/src/test/ui/parser/extern-crate-unexpected-token.stderr @@ -1,8 +1,8 @@ -error: expected one of `crate`, `fn`, or `{`, found `crte` +error: expected one of `crate` or `{`, found `crte` --> $DIR/extern-crate-unexpected-token.rs:1:8 | LL | extern crte foo; - | ^^^^ expected one of `crate`, `fn`, or `{` + | ^^^^ expected one of `crate` or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.rs b/src/test/ui/parser/extern-expected-fn-or-brace.rs index 907de0d8f91d8..1dcea17445e7a 100644 --- a/src/test/ui/parser/extern-expected-fn-or-brace.rs +++ b/src/test/ui/parser/extern-expected-fn-or-brace.rs @@ -1,4 +1,3 @@ -// Verifies that the expected token errors for `extern crate` are -// raised +// Verifies that the expected token errors for `extern crate` are raised. -extern "C" mod foo; //~ERROR expected one of `fn` or `{`, found keyword `mod` +extern "C" mod foo; //~ERROR expected `{`, found keyword `mod` diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.stderr b/src/test/ui/parser/extern-expected-fn-or-brace.stderr index 0ebe9a0d3ead5..258a2c2680aaf 100644 --- a/src/test/ui/parser/extern-expected-fn-or-brace.stderr +++ b/src/test/ui/parser/extern-expected-fn-or-brace.stderr @@ -1,8 +1,8 @@ -error: expected one of `fn` or `{`, found keyword `mod` - --> $DIR/extern-expected-fn-or-brace.rs:4:12 +error: expected `{`, found keyword `mod` + --> $DIR/extern-expected-fn-or-brace.rs:3:12 | LL | extern "C" mod foo; - | ^^^ expected one of `fn` or `{` + | ^^^ expected `{` error: aborting due to previous error diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs index 98ff2b6d2e8b3..a05ea277eec20 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.rs +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -10,8 +10,8 @@ fn main() { unsafe fn ff2() {} // OK. const fn ff3() {} // OK. extern "C" fn ff4() {} // OK. - const /* async */ unsafe extern "C" fn ff5() {} // OK. - //^ FIXME(Centril): `async` should be legal syntactically, ensure it's illegal semantically. + const async unsafe extern "C" fn ff5() {} // OK. + //~^ ERROR functions cannot be both `const` and `async` trait X { async fn ft1(); //~ ERROR trait fns cannot be declared `async` @@ -21,6 +21,7 @@ fn main() { const async unsafe extern "C" fn ft5(); //~^ ERROR trait fns cannot be declared `async` //~| ERROR trait fns cannot be declared const + //~| ERROR functions cannot be both `const` and `async` } struct Y; @@ -34,6 +35,7 @@ fn main() { //~^ ERROR trait fns cannot be declared `async` //~| ERROR trait fns cannot be declared const //~| ERROR method `ft5` has an incompatible type for trait + //~| ERROR functions cannot be both `const` and `async` } impl Y { @@ -41,7 +43,8 @@ fn main() { unsafe fn fi2() {} // OK. const fn fi3() {} // OK. extern "C" fn fi4() {} // OK. - const async unsafe extern "C" fn fi5() {} // OK. + const async unsafe extern "C" fn fi5() {} + //~^ ERROR functions cannot be both `const` and `async` } extern { @@ -50,5 +53,6 @@ fn main() { const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks + //~^ ERROR functions cannot be both `const` and `async` } } diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 1860106b255ab..a9e4a18334767 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -1,3 +1,12 @@ +error: functions cannot be both `const` and `async` + --> $DIR/fn-header-semantic-fail.rs:13:5 + | +LL | const async unsafe extern "C" fn ff5() {} // OK. + | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | `async` because of this + | `const` because of this + error[E0706]: trait fns cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:17:9 | @@ -32,8 +41,17 @@ LL | const async unsafe extern "C" fn ft5(); = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait +error: functions cannot be both `const` and `async` + --> $DIR/fn-header-semantic-fail.rs:21:9 + | +LL | const async unsafe extern "C" fn ft5(); + | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | `async` because of this + | `const` because of this + error[E0706]: trait fns cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:28:9 + --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | async fn ft1() {} | -----^^^^^^^^^^^^ @@ -44,19 +62,19 @@ LL | async fn ft1() {} = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error[E0379]: trait fns cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:31:9 + --> $DIR/fn-header-semantic-fail.rs:32:9 | LL | const fn ft3() {} | ^^^^^ trait fns cannot be const error[E0379]: trait fns cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:33:9 + --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^ trait fns cannot be const error[E0706]: trait fns cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:33:9 + --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,8 +84,26 @@ LL | const async unsafe extern "C" fn ft5() {} = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait +error: functions cannot be both `const` and `async` + --> $DIR/fn-header-semantic-fail.rs:34:9 + | +LL | const async unsafe extern "C" fn ft5() {} + | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | `async` because of this + | `const` because of this + +error: functions cannot be both `const` and `async` + --> $DIR/fn-header-semantic-fail.rs:46:9 + | +LL | const async unsafe extern "C" fn fi5() {} + | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | `async` because of this + | `const` because of this + error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:48:18 + --> $DIR/fn-header-semantic-fail.rs:51:18 | LL | extern { | ------ in this `extern` block @@ -77,7 +113,7 @@ LL | async fn fe1(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:49:19 + --> $DIR/fn-header-semantic-fail.rs:52:19 | LL | extern { | ------ in this `extern` block @@ -88,7 +124,7 @@ LL | unsafe fn fe2(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:18 + --> $DIR/fn-header-semantic-fail.rs:53:18 | LL | extern { | ------ in this `extern` block @@ -99,7 +135,7 @@ LL | const fn fe3(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:51:23 + --> $DIR/fn-header-semantic-fail.rs:54:23 | LL | extern { | ------ in this `extern` block @@ -110,7 +146,7 @@ LL | extern "C" fn fe4(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:52:42 + --> $DIR/fn-header-semantic-fail.rs:55:42 | LL | extern { | ------ in this `extern` block @@ -120,8 +156,17 @@ LL | const async unsafe extern "C" fn fe5(); | | | help: remove the qualifiers: `fn` +error: functions cannot be both `const` and `async` + --> $DIR/fn-header-semantic-fail.rs:55:9 + | +LL | const async unsafe extern "C" fn fe5(); + | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | `async` because of this + | `const` because of this + error[E0053]: method `ft1` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:28:24 + --> $DIR/fn-header-semantic-fail.rs:29:24 | LL | async fn ft1(); | - type in trait @@ -136,7 +181,7 @@ LL | async fn ft1() {} found fn pointer `fn() -> impl std::future::Future` error[E0053]: method `ft5` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:33:48 + --> $DIR/fn-header-semantic-fail.rs:34:48 | LL | const async unsafe extern "C" fn ft5(); | - type in trait @@ -150,7 +195,7 @@ LL | const async unsafe extern "C" fn ft5() {} = note: expected fn pointer `unsafe extern "C" fn()` found fn pointer `unsafe extern "C" fn() -> impl std::future::Future` -error: aborting due to 15 previous errors +error: aborting due to 20 previous errors Some errors have detailed explanations: E0053, E0379, E0706. For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/parser/fn-header-syntactic-pass.rs b/src/test/ui/parser/fn-header-syntactic-pass.rs index 0557b9ef6ca23..9e44541993d92 100644 --- a/src/test/ui/parser/fn-header-syntactic-pass.rs +++ b/src/test/ui/parser/fn-header-syntactic-pass.rs @@ -3,9 +3,6 @@ // check-pass // edition:2018 -#![feature(const_extern_fn)] -//^ FIXME(Centril): move check to ast_validation. - fn main() {} #[cfg(FALSE)] @@ -14,8 +11,7 @@ fn syntax() { unsafe fn f(); const fn f(); extern "C" fn f(); - const /* async */ unsafe extern "C" fn f(); - //^ FIXME(Centril): `async` should be legal syntactically. + const async unsafe extern "C" fn f(); trait X { async fn f(); diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs index 90221039b4148..2158a2fd6c11c 100644 --- a/src/test/ui/parser/issue-19398.rs +++ b/src/test/ui/parser/issue-19398.rs @@ -1,5 +1,5 @@ trait T { - extern "Rust" unsafe fn foo(); //~ ERROR expected `fn`, found keyword `unsafe` + extern "Rust" unsafe fn foo(); //~ ERROR expected one of `async`, `const` } fn main() {} diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr index 41ec4f3ced4e9..201a6b2d66a7c 100644 --- a/src/test/ui/parser/issue-19398.stderr +++ b/src/test/ui/parser/issue-19398.stderr @@ -1,8 +1,10 @@ -error: expected `fn`, found keyword `unsafe` - --> $DIR/issue-19398.rs:2:19 +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `extern` + --> $DIR/issue-19398.rs:2:5 | +LL | trait T { + | - expected one of 10 possible tokens LL | extern "Rust" unsafe fn foo(); - | ^^^^^^ expected `fn` + | ^^^^^^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.rs b/src/test/ui/unsafe/unsafe-block-without-braces.rs index a291eb2eed764..4e461161854e6 100644 --- a/src/test/ui/unsafe/unsafe-block-without-braces.rs +++ b/src/test/ui/unsafe/unsafe-block-without-braces.rs @@ -3,4 +3,4 @@ fn main() { std::mem::transmute::<f32, u32>(1.0); //} } -//~^^^ ERROR expected one of `extern`, `fn`, or `{`, found `std` +//~^^^ ERROR expected `{`, found `std` diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.stderr b/src/test/ui/unsafe/unsafe-block-without-braces.stderr index 637fdeead362d..13e0c3681fa00 100644 --- a/src/test/ui/unsafe/unsafe-block-without-braces.stderr +++ b/src/test/ui/unsafe/unsafe-block-without-braces.stderr @@ -1,8 +1,8 @@ -error: expected one of `extern`, `fn`, or `{`, found `std` +error: expected `{`, found `std` --> $DIR/unsafe-block-without-braces.rs:3:9 | LL | unsafe //{ - | - expected one of `extern`, `fn`, or `{` + | - expected `{` LL | std::mem::transmute::<f32, u32>(1.0); | ^^^ unexpected token From b05e9d2b4d8692a9f0932e9098727762bfad6efe Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Fri, 31 Jan 2020 03:20:46 +0100 Subject: [PATCH 05/13] parser: solidify `fn` parsing with `parse_fn`. --- src/librustc_parse/parser/item.rs | 53 +++++++++++++++++-------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 906b82f746b24..d7ffda28bb767 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1596,6 +1596,11 @@ pub(super) struct ParamCfg { pub is_name_required: fn(&token::Token) -> bool, } +impl ParamCfg { + /// Configuration for a free function in the sense that it is not associated. + const FREE: Self = ParamCfg { is_name_required: |_| true }; +} + /// Parsing of functions and methods. impl<'a> Parser<'a> { /// Parses an item-position function declaration. @@ -1605,11 +1610,9 @@ impl<'a> Parser<'a> { vis: Visibility, mut attrs: Vec<Attribute>, ) -> PResult<'a, Option<P<Item>>> { - let cfg = ParamCfg { is_name_required: |_| true }; - let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let body = self.parse_fn_body(&mut false, &mut attrs)?; - let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); + let (ident, sig, generics, body) = + self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; + let kind = ItemKind::Fn(sig, generics, body); self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)) } @@ -1620,11 +1623,9 @@ impl<'a> Parser<'a> { lo: Span, mut attrs: Vec<Attribute>, ) -> PResult<'a, P<ForeignItem>> { - let cfg = ParamCfg { is_name_required: |_| true }; - let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let body = self.parse_fn_body(&mut false, &mut attrs)?; - let kind = ForeignItemKind::Fn(FnSig { header, decl }, generics, body); + let (ident, sig, generics, body) = + self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; + let kind = ForeignItemKind::Fn(sig, generics, body); let span = lo.to(self.prev_span); Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) } @@ -1635,10 +1636,25 @@ impl<'a> Parser<'a> { attrs: &mut Vec<Attribute>, is_name_required: fn(&token::Token) -> bool, ) -> PResult<'a, (Ident, AssocItemKind, Generics)> { - let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(&&ParamCfg { is_name_required })?; - let body = self.parse_fn_body(at_end, attrs)?; - Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics)) + let cfg = ParamCfg { is_name_required }; + let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, &cfg)?; + Ok((ident, AssocItemKind::Fn(sig, body), generics)) + } + + /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`. + fn parse_fn( + &mut self, + at_end: &mut bool, + attrs: &mut Vec<Attribute>, + cfg: &ParamCfg, + ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> { + let header = self.parse_fn_front_matter()?; // `const ... fn` + let ident = self.parse_ident()?; // `foo` + let mut generics = self.parse_generics()?; // `<'a, T, ...>` + let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; // `(p: u8, ...)` + generics.where_clause = self.parse_where_clause()?; // `where T: Ord` + let body = self.parse_fn_body(at_end, attrs)?; // `;` or `{ ... }`. + Ok((ident, FnSig { header, decl }, generics, body)) } /// Parse the "body" of a function. @@ -1722,15 +1738,6 @@ impl<'a> Parser<'a> { Ok(FnHeader { constness, unsafety, asyncness, ext }) } - /// Parse the "signature", including the identifier, parameters, and generics of a function. - fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> { - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; - generics.where_clause = self.parse_where_clause()?; - Ok((ident, decl, generics)) - } - /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, From 04253791952d85a4da5d19d228cbac92e37ee2b9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Fri, 31 Jan 2020 03:31:12 +0100 Subject: [PATCH 06/13] parser: inline `parse_assoc_fn` and friends. --- src/librustc_parse/parser/item.rs | 63 +++++++++++-------------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d7ffda28bb767..8ba957c6b3b52 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -98,7 +98,10 @@ impl<'a> Parser<'a> { if self.is_fn_front_matter() { // FUNCTION ITEM - return self.parse_item_fn(lo, vis, attrs); + let (ident, sig, generics, body) = + self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; + let kind = ItemKind::Fn(sig, generics, body); + return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)); } if self.eat_keyword(kw::Extern) { @@ -741,7 +744,9 @@ impl<'a> Parser<'a> { let (name, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_assoc_ty()? } else if self.is_fn_front_matter() { - self.parse_assoc_fn(at_end, &mut attrs, is_name_required)? + let cfg = ParamCfg { is_name_required }; + let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, &cfg)?; + (ident, AssocItemKind::Fn(sig, body), generics) } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? { (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default()) } else { @@ -968,7 +973,7 @@ impl<'a> Parser<'a> { pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> { maybe_whole!(self, NtForeignItem, |ni| ni); - let attrs = self.parse_outer_attributes()?; + let mut attrs = self.parse_outer_attributes()?; let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; @@ -977,7 +982,19 @@ impl<'a> Parser<'a> { self.parse_item_foreign_type(vis, lo, attrs) } else if self.is_fn_front_matter() { // FOREIGN FUNCTION ITEM - self.parse_item_foreign_fn(vis, lo, attrs) + let (ident, sig, generics, body) = + self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; + let kind = ForeignItemKind::Fn(sig, generics, body); + let span = lo.to(self.prev_span); + Ok(P(ast::ForeignItem { + ident, + attrs, + kind, + id: DUMMY_NODE_ID, + span, + vis, + tokens: None, + })) } else if self.is_static_global() { // FOREIGN STATIC ITEM self.bump(); // `static` @@ -1603,44 +1620,6 @@ impl ParamCfg { /// Parsing of functions and methods. impl<'a> Parser<'a> { - /// Parses an item-position function declaration. - fn parse_item_fn( - &mut self, - lo: Span, - vis: Visibility, - mut attrs: Vec<Attribute>, - ) -> PResult<'a, Option<P<Item>>> { - let (ident, sig, generics, body) = - self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; - let kind = ItemKind::Fn(sig, generics, body); - self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)) - } - - /// Parses a function declaration from a foreign module. - fn parse_item_foreign_fn( - &mut self, - vis: ast::Visibility, - lo: Span, - mut attrs: Vec<Attribute>, - ) -> PResult<'a, P<ForeignItem>> { - let (ident, sig, generics, body) = - self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; - let kind = ForeignItemKind::Fn(sig, generics, body); - let span = lo.to(self.prev_span); - Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) - } - - fn parse_assoc_fn( - &mut self, - at_end: &mut bool, - attrs: &mut Vec<Attribute>, - is_name_required: fn(&token::Token) -> bool, - ) -> PResult<'a, (Ident, AssocItemKind, Generics)> { - let cfg = ParamCfg { is_name_required }; - let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, &cfg)?; - Ok((ident, AssocItemKind::Fn(sig, body), generics)) - } - /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`. fn parse_fn( &mut self, From cdbbc25cc31080e189a98c010a0b39a9074d0c50 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Sat, 1 Feb 2020 10:36:29 +0100 Subject: [PATCH 07/13] parser: move `ban_async_in_2015` to `fn` parsing & improve it. --- src/librustc_parse/parser/item.rs | 12 +++++++ src/librustc_parse/parser/mod.rs | 13 ------- .../edition-deny-async-fns-2015.stderr | 36 +++++++++++++++++++ 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 8ba957c6b3b52..a851ec2124f97 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1717,6 +1717,18 @@ impl<'a> Parser<'a> { Ok(FnHeader { constness, unsafety, asyncness, ext }) } + /// We are parsing `async fn`. If we are on Rust 2015, emit an error. + fn ban_async_in_2015(&self, span: Span) { + if span.rust_2015() { + let diag = self.diagnostic(); + struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition") + .note("to use `async fn`, switch to Rust 2018") + .help("set `edition = \"2018\"` in `Cargo.toml`") + .note("for more on editions, read https://doc.rust-lang.org/edition-guide") + .emit(); + } + } + /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 2f2f2f8f176e5..4716d722778a6 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1273,19 +1273,6 @@ impl<'a> Parser<'a> { } } - /// We are parsing `async fn`. If we are on Rust 2015, emit an error. - fn ban_async_in_2015(&self, async_span: Span) { - if async_span.rust_2015() { - struct_span_err!( - self.diagnostic(), - async_span, - E0670, - "`async fn` is not permitted in the 2015 edition", - ) - .emit(); - } - } - fn collect_tokens<R>( &mut self, f: impl FnOnce(&mut Self) -> PResult<'a, R>, diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index e6859a3cd93a0..4afb0430a7274 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -3,54 +3,90 @@ error[E0670]: `async fn` is not permitted in the 2015 edition | LL | async fn foo() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:5:12 | LL | fn baz() { async fn foo() {} } | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:7:1 | LL | async fn async_baz() { | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:8:5 | LL | async fn bar() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:14:5 | LL | async fn foo() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:36:9 | LL | async fn bar() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:26:9 | LL | async fn foo() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:31:13 | LL | async fn bar() {} | ^^^^^ + | + = note: to use `async fn`, switch to Rust 2018 + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0706]: trait fns cannot be declared `async` --> $DIR/edition-deny-async-fns-2015.rs:18:5 From 05e5530577bf43749186fd56195cffb686f0311e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Mon, 10 Feb 2020 15:24:53 +0100 Subject: [PATCH 08/13] parser: address review comments --- src/librustc_hir/print.rs | 2 +- src/librustc_parse/parser/item.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index b31b814d67be6..e49f99fb717a3 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -648,7 +648,7 @@ impl<'a> State<'a> { self.s.space(); } - if let hir::Constness::Const = constness { + if constness == hir::Constness::Const { self.word_nbsp("const"); } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index a851ec2124f97..2bae86d1179a1 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -646,7 +646,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_span); - if let IsAuto::Yes = is_auto { + if is_auto == IsAuto::Yes { let msg = "trait aliases cannot be `auto`"; self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); } From 79d139ac7056d0102db605715f354689b0214705 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Mon, 10 Feb 2020 15:35:05 +0100 Subject: [PATCH 09/13] parser: simplify ParamCfg -> ReqName --- src/librustc_parse/parser/item.rs | 44 ++++++++++++------------------- src/librustc_parse/parser/ty.rs | 4 +-- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 2bae86d1179a1..d16eb770951e1 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -98,8 +98,7 @@ impl<'a> Parser<'a> { if self.is_fn_front_matter() { // FUNCTION ITEM - let (ident, sig, generics, body) = - self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; + let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; let kind = ItemKind::Fn(sig, generics, body); return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)); } @@ -715,12 +714,12 @@ impl<'a> Parser<'a> { fn parse_assoc_item( &mut self, at_end: &mut bool, - is_name_required: fn(&token::Token) -> bool, + req_name: fn(&token::Token) -> bool, ) -> PResult<'a, P<AssocItem>> { let attrs = self.parse_outer_attributes()?; let mut unclosed_delims = vec![]; let (mut item, tokens) = self.collect_tokens(|this| { - let item = this.parse_assoc_item_(at_end, attrs, is_name_required); + let item = this.parse_assoc_item_(at_end, attrs, req_name); unclosed_delims.append(&mut this.unclosed_delims); item })?; @@ -736,7 +735,7 @@ impl<'a> Parser<'a> { &mut self, at_end: &mut bool, mut attrs: Vec<Attribute>, - is_name_required: fn(&token::Token) -> bool, + req_name: fn(&token::Token) -> bool, ) -> PResult<'a, AssocItem> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; @@ -744,8 +743,7 @@ impl<'a> Parser<'a> { let (name, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_assoc_ty()? } else if self.is_fn_front_matter() { - let cfg = ParamCfg { is_name_required }; - let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, &cfg)?; + let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; (ident, AssocItemKind::Fn(sig, body), generics) } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? { (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default()) @@ -982,8 +980,7 @@ impl<'a> Parser<'a> { self.parse_item_foreign_type(vis, lo, attrs) } else if self.is_fn_front_matter() { // FOREIGN FUNCTION ITEM - let (ident, sig, generics, body) = - self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?; + let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; let kind = ForeignItemKind::Fn(sig, generics, body); let span = lo.to(self.prev_span); Ok(P(ast::ForeignItem { @@ -1607,16 +1604,9 @@ impl<'a> Parser<'a> { } /// The parsing configuration used to parse a parameter list (see `parse_fn_params`). -pub(super) struct ParamCfg { - /// `is_name_required` decides if, per-parameter, - /// the parameter must have a pattern or just a type. - pub is_name_required: fn(&token::Token) -> bool, -} - -impl ParamCfg { - /// Configuration for a free function in the sense that it is not associated. - const FREE: Self = ParamCfg { is_name_required: |_| true }; -} +/// +/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type. +type ReqName = fn(&token::Token) -> bool; /// Parsing of functions and methods. impl<'a> Parser<'a> { @@ -1625,12 +1615,12 @@ impl<'a> Parser<'a> { &mut self, at_end: &mut bool, attrs: &mut Vec<Attribute>, - cfg: &ParamCfg, + req_name: ReqName, ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> { let header = self.parse_fn_front_matter()?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` - let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; // `(p: u8, ...)` + let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)` generics.where_clause = self.parse_where_clause()?; // `where T: Ord` let body = self.parse_fn_body(at_end, attrs)?; // `;` or `{ ... }`. Ok((ident, FnSig { header, decl }, generics, body)) @@ -1732,21 +1722,21 @@ impl<'a> Parser<'a> { /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, - cfg: &ParamCfg, + req_name: ReqName, ret_allow_plus: AllowPlus, ) -> PResult<'a, P<FnDecl>> { Ok(P(FnDecl { - inputs: self.parse_fn_params(cfg)?, + inputs: self.parse_fn_params(req_name)?, output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, })) } /// Parses the parameter list of a function, including the `(` and `)` delimiters. - fn parse_fn_params(&mut self, cfg: &ParamCfg) -> PResult<'a, Vec<Param>> { + fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> { let mut first_param = true; // Parse the arguments, starting out with `self` being allowed... let (mut params, _) = self.parse_paren_comma_seq(|p| { - let param = p.parse_param_general(&cfg, first_param).or_else(|mut e| { + let param = p.parse_param_general(req_name, first_param).or_else(|mut e| { e.emit(); let lo = p.prev_span; // Skip every token until next possible arg or end. @@ -1766,7 +1756,7 @@ impl<'a> Parser<'a> { /// Parses a single function parameter. /// /// - `self` is syntactically allowed when `first_param` holds. - fn parse_param_general(&mut self, cfg: &ParamCfg, first_param: bool) -> PResult<'a, Param> { + fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; @@ -1778,7 +1768,7 @@ impl<'a> Parser<'a> { let is_name_required = match self.token.kind { token::DotDotDot => false, - _ => (cfg.is_name_required)(&self.token), + _ => req_name(&self.token), }; let (pat, ty) = if is_name_required || self.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index e74ce622947bf..f56ae65a03d02 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -1,4 +1,3 @@ -use super::item::ParamCfg; use super::{Parser, PathStyle, TokenType}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -311,8 +310,7 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; - let cfg = ParamCfg { is_name_required: |_| false }; - let decl = self.parse_fn_decl(&cfg, AllowPlus::No)?; + let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?; Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl }))) } From 3341c940068d60ade54ea343301a810c0bb51153 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Tue, 11 Feb 2020 08:19:21 +0100 Subject: [PATCH 10/13] ast_validation: tweak diagnostic output --- src/librustc_ast_passes/ast_validation.rs | 35 ++++++++++++------- src/test/ui/async-await/async-trait-fn.rs | 4 +-- src/test/ui/async-await/async-trait-fn.stderr | 4 +-- .../edition-deny-async-fns-2015.rs | 2 +- .../edition-deny-async-fns-2015.stderr | 2 +- .../const-fn-with-const-param.rs | 2 +- .../const-fn-with-const-param.stderr | 4 +-- src/test/ui/consts/const-fn-mismatch.rs | 8 +++-- src/test/ui/consts/const-fn-mismatch.stderr | 6 ++-- src/test/ui/consts/const-fn-not-in-trait.rs | 10 +++--- .../ui/consts/const-fn-not-in-trait.stderr | 10 +++--- .../ui/feature-gates/feature-gate-const_fn.rs | 6 ++-- .../feature-gate-const_fn.stderr | 12 +++---- .../feature-gate-min_const_fn.rs | 6 ++-- .../feature-gate-min_const_fn.stderr | 12 +++---- src/test/ui/issues/issue-54954.rs | 2 +- src/test/ui/issues/issue-54954.stderr | 4 +-- .../mismatched_types/const-fn-in-trait.stderr | 8 ++--- src/test/ui/parser/fn-header-semantic-fail.rs | 16 ++++----- .../ui/parser/fn-header-semantic-fail.stderr | 24 ++++++------- 20 files changed, 96 insertions(+), 81 deletions(-) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 0bc6179dabf5b..2f0495b8b5a48 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -223,21 +223,29 @@ impl<'a> AstValidator<'a> { fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) { if let Async::Yes { span, .. } = asyncness { - struct_span_err!(self.session, fn_span, E0706, "trait fns cannot be declared `async`") - .span_label(span, "`async` because of this") - .note("`async` trait functions are not currently supported") - .note( - "consider using the `async-trait` crate: https://crates.io/crates/async-trait", - ) - .emit(); + struct_span_err!( + self.session, + fn_span, + E0706, + "functions in traits cannot be declared `async`" + ) + .span_label(span, "`async` because of this") + .note("`async` trait functions are not currently supported") + .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait") + .emit(); } } fn check_trait_fn_not_const(&self, constness: Const) { if let Const::Yes(span) = constness { - struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const") - .span_label(span, "trait fns cannot be const") - .emit(); + struct_span_err!( + self.session, + span, + E0379, + "functions in traits cannot be declared const" + ) + .span_label(span, "functions in traits cannot be const") + .emit(); } } @@ -513,8 +521,11 @@ impl<'a> AstValidator<'a> { for param in &generics.params { if let GenericParamKind::Const { .. } = param.kind { self.err_handler() - .struct_span_err(span, "const parameters are not permitted in `const fn`") - .span_label(const_span, "`const fn` because of this") + .struct_span_err( + span, + "const parameters are not permitted in const functions", + ) + .span_label(const_span, "`const` because of this") .emit(); } } diff --git a/src/test/ui/async-await/async-trait-fn.rs b/src/test/ui/async-await/async-trait-fn.rs index 786100e916da0..f0403b76620c1 100644 --- a/src/test/ui/async-await/async-trait-fn.rs +++ b/src/test/ui/async-await/async-trait-fn.rs @@ -1,7 +1,7 @@ // edition:2018 trait T { - async fn foo() {} //~ ERROR trait fns cannot be declared `async` - async fn bar(&self) {} //~ ERROR trait fns cannot be declared `async` + async fn foo() {} //~ ERROR functions in traits cannot be declared `async` + async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async` } fn main() {} diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr index 04f72fb645e28..6080b2815eeb8 100644 --- a/src/test/ui/async-await/async-trait-fn.stderr +++ b/src/test/ui/async-await/async-trait-fn.stderr @@ -1,4 +1,4 @@ -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/async-trait-fn.rs:3:5 | LL | async fn foo() {} @@ -9,7 +9,7 @@ LL | async fn foo() {} = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/async-trait-fn.rs:4:5 | LL | async fn bar(&self) {} diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs index c85896150c29f..5d2d186137e16 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -16,7 +16,7 @@ impl Foo { trait Bar { async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - //~^ ERROR trait fns cannot be declared `async` + //~^ ERROR functions in traits cannot be declared `async` } fn main() { diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index 4afb0430a7274..f3d982801bb99 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -88,7 +88,7 @@ LL | async fn bar() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} diff --git a/src/test/ui/const-generics/const-fn-with-const-param.rs b/src/test/ui/const-generics/const-fn-with-const-param.rs index f36bf3875c349..e9e236be55630 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.rs +++ b/src/test/ui/const-generics/const-fn-with-const-param.rs @@ -2,7 +2,7 @@ //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash const fn const_u32_identity<const X: u32>() -> u32 { - //~^ ERROR const parameters are not permitted in `const fn` + //~^ ERROR const parameters are not permitted in const functions X } diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr index 68670963f8e5e..ca31d695361f4 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.stderr +++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr @@ -1,10 +1,10 @@ -error: const parameters are not permitted in `const fn` +error: const parameters are not permitted in const functions --> $DIR/const-fn-with-const-param.rs:4:1 | LL | const fn const_u32_identity<const X: u32>() -> u32 { | ^---- | | - | _`const fn` because of this + | _`const` because of this | | LL | | LL | | X diff --git a/src/test/ui/consts/const-fn-mismatch.rs b/src/test/ui/consts/const-fn-mismatch.rs index 5bd274fe66b64..d4cfba6460c45 100644 --- a/src/test/ui/consts/const-fn-mismatch.rs +++ b/src/test/ui/consts/const-fn-mismatch.rs @@ -10,8 +10,10 @@ trait Foo { } impl Foo for u32 { - const fn f() -> u32 { 22 } - //~^ ERROR trait fns cannot be declared const + const fn f() -> u32 { + //~^ ERROR functions in traits cannot be declared const + 22 + } } -fn main() { } +fn main() {} diff --git a/src/test/ui/consts/const-fn-mismatch.stderr b/src/test/ui/consts/const-fn-mismatch.stderr index 03bb7c6e8d6d8..0f4ce010fee00 100644 --- a/src/test/ui/consts/const-fn-mismatch.stderr +++ b/src/test/ui/consts/const-fn-mismatch.stderr @@ -1,8 +1,8 @@ -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-mismatch.rs:13:5 | -LL | const fn f() -> u32 { 22 } - | ^^^^^ trait fns cannot be const +LL | const fn f() -> u32 { + | ^^^^^ functions in traits cannot be const error: aborting due to previous error diff --git a/src/test/ui/consts/const-fn-not-in-trait.rs b/src/test/ui/consts/const-fn-not-in-trait.rs index 3975c22c56e91..1006d854688a4 100644 --- a/src/test/ui/consts/const-fn-not-in-trait.rs +++ b/src/test/ui/consts/const-fn-not-in-trait.rs @@ -5,9 +5,11 @@ trait Foo { const fn f() -> u32; - //~^ ERROR trait fns cannot be declared const - const fn g() -> u32 { 0 } - //~^ ERROR trait fns cannot be declared const + //~^ ERROR functions in traits cannot be declared const + const fn g() -> u32 { + //~^ ERROR functions in traits cannot be declared const + 0 + } } -fn main() { } +fn main() {} diff --git a/src/test/ui/consts/const-fn-not-in-trait.stderr b/src/test/ui/consts/const-fn-not-in-trait.stderr index 6821a6c2bc690..12ce3066037d1 100644 --- a/src/test/ui/consts/const-fn-not-in-trait.stderr +++ b/src/test/ui/consts/const-fn-not-in-trait.stderr @@ -1,14 +1,14 @@ -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-not-in-trait.rs:7:5 | LL | const fn f() -> u32; - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-not-in-trait.rs:9:5 | -LL | const fn g() -> u32 { 0 } - | ^^^^^ trait fns cannot be const +LL | const fn g() -> u32 { + | ^^^^^ functions in traits cannot be const error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.rs b/src/test/ui/feature-gates/feature-gate-const_fn.rs index f46d1dc13d3f0..691c367aeb859 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-const_fn.rs @@ -4,13 +4,13 @@ const fn foo() -> usize { 0 } // ok trait Foo { const fn foo() -> u32; //~ ERROR const fn is unstable - //~| ERROR trait fns cannot be declared const + //~| ERROR functions in traits cannot be declared const const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable - //~| ERROR trait fns cannot be declared const + //~| ERROR functions in traits cannot be declared const } impl Foo for u32 { - const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const + const fn foo() -> u32 { 0 } //~ ERROR functions in traits cannot be declared const } trait Bar {} diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.stderr b/src/test/ui/feature-gates/feature-gate-const_fn.stderr index 6a44f079bfbb4..843e56301375a 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn.stderr @@ -1,20 +1,20 @@ -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-const_fn.rs:6:5 | LL | const fn foo() -> u32; - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-const_fn.rs:8:5 | LL | const fn bar() -> u32 { 0 } - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-const_fn.rs:13:5 | LL | const fn foo() -> u32 { 0 } - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const error[E0658]: const fn is unstable --> $DIR/feature-gate-const_fn.rs:6:5 diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.rs b/src/test/ui/feature-gates/feature-gate-min_const_fn.rs index 669631df2ad17..5a01e053ed038 100644 --- a/src/test/ui/feature-gates/feature-gate-min_const_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.rs @@ -4,13 +4,13 @@ const fn foo() -> usize { 0 } // stabilized trait Foo { const fn foo() -> u32; //~ ERROR const fn is unstable - //~| ERROR trait fns cannot be declared const + //~| ERROR functions in traits cannot be declared const const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable - //~| ERROR trait fns cannot be declared const + //~| ERROR functions in traits cannot be declared const } impl Foo for u32 { - const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const + const fn foo() -> u32 { 0 } //~ ERROR functions in traits cannot be declared const } trait Bar {} diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr index 7ab9d748b31f7..56a882e30fc4a 100644 --- a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -1,20 +1,20 @@ -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:6:5 | LL | const fn foo() -> u32; - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:8:5 | LL | const fn bar() -> u32 { 0 } - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:13:5 | LL | const fn foo() -> u32 { 0 } - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const error[E0658]: const fn is unstable --> $DIR/feature-gate-min_const_fn.rs:6:5 diff --git a/src/test/ui/issues/issue-54954.rs b/src/test/ui/issues/issue-54954.rs index 9e9f92ed9ace5..3d6355f5c5978 100644 --- a/src/test/ui/issues/issue-54954.rs +++ b/src/test/ui/issues/issue-54954.rs @@ -5,7 +5,7 @@ const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); trait Tt { const fn const_val<T: Sized>() -> usize { - //~^ ERROR trait fns cannot be declared const + //~^ ERROR functions in traits cannot be declared const core::mem::size_of::<T>() } } diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr index d99a5772e8a4c..4967b82216e46 100644 --- a/src/test/ui/issues/issue-54954.stderr +++ b/src/test/ui/issues/issue-54954.stderr @@ -1,8 +1,8 @@ -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/issue-54954.rs:7:5 | LL | const fn const_val<T: Sized>() -> usize { - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const error[E0283]: type annotations needed --> $DIR/issue-54954.rs:3:24 diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr index ec1f36bf08774..817582df27db1 100644 --- a/src/test/ui/mismatched_types/const-fn-in-trait.stderr +++ b/src/test/ui/mismatched_types/const-fn-in-trait.stderr @@ -1,14 +1,14 @@ -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-in-trait.rs:7:5 | LL | const fn g(); - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-in-trait.rs:11:5 | LL | const fn f() -> u32 { 22 } - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs index a05ea277eec20..c327667f4cdc7 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.rs +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -14,26 +14,26 @@ fn main() { //~^ ERROR functions cannot be both `const` and `async` trait X { - async fn ft1(); //~ ERROR trait fns cannot be declared `async` + async fn ft1(); //~ ERROR functions in traits cannot be declared `async` unsafe fn ft2(); // OK. - const fn ft3(); //~ ERROR trait fns cannot be declared const + const fn ft3(); //~ ERROR functions in traits cannot be declared const extern "C" fn ft4(); // OK. const async unsafe extern "C" fn ft5(); - //~^ ERROR trait fns cannot be declared `async` - //~| ERROR trait fns cannot be declared const + //~^ ERROR functions in traits cannot be declared `async` + //~| ERROR functions in traits cannot be declared const //~| ERROR functions cannot be both `const` and `async` } struct Y; impl X for Y { - async fn ft1() {} //~ ERROR trait fns cannot be declared `async` + async fn ft1() {} //~ ERROR functions in traits cannot be declared `async` //~^ ERROR method `ft1` has an incompatible type for trait unsafe fn ft2() {} // OK. - const fn ft3() {} //~ ERROR trait fns cannot be declared const + const fn ft3() {} //~ ERROR functions in traits cannot be declared const extern "C" fn ft4() {} const async unsafe extern "C" fn ft5() {} - //~^ ERROR trait fns cannot be declared `async` - //~| ERROR trait fns cannot be declared const + //~^ ERROR functions in traits cannot be declared `async` + //~| ERROR functions in traits cannot be declared const //~| ERROR method `ft5` has an incompatible type for trait //~| ERROR functions cannot be both `const` and `async` } diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index a9e4a18334767..1142cee9851b0 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -7,7 +7,7 @@ LL | const async unsafe extern "C" fn ff5() {} // OK. | | `async` because of this | `const` because of this -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:17:9 | LL | async fn ft1(); @@ -18,19 +18,19 @@ LL | async fn ft1(); = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:19:9 | LL | const fn ft3(); - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:21:9 | LL | const async unsafe extern "C" fn ft5(); - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:21:9 | LL | const async unsafe extern "C" fn ft5(); @@ -50,7 +50,7 @@ LL | const async unsafe extern "C" fn ft5(); | | `async` because of this | `const` because of this -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | async fn ft1() {} @@ -61,19 +61,19 @@ LL | async fn ft1() {} = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:32:9 | LL | const fn ft3() {} - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0379]: trait fns cannot be declared const +error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} - | ^^^^^ trait fns cannot be const + | ^^^^^ functions in traits cannot be const -error[E0706]: trait fns cannot be declared `async` +error[E0706]: functions in traits cannot be declared `async` --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} From 27f60906aa400aa42bca5346701b7a02fbc1a872 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Tue, 11 Feb 2020 08:24:05 +0100 Subject: [PATCH 11/13] rustc_bulltin_macros: tweak span_labels --- src/librustc_builtin_macros/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index a246e11495345..02a0bc00c1169 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -377,13 +377,13 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { if let ast::ItemKind::Fn(ref sig, ref generics, _) = i.kind { if let ast::Unsafe::Yes(span) = sig.header.unsafety { sd.struct_span_err(i.span, "unsafe functions cannot be used for tests") - .span_label(span, "unsafe because of this") + .span_label(span, "`unsafe` because of this") .emit(); return false; } if let ast::Async::Yes { span, .. } = sig.header.asyncness { sd.struct_span_err(i.span, "async functions cannot be used for tests") - .span_label(span, "async because of this") + .span_label(span, "`async` because of this") .emit(); return false; } From 4ca3bbf0b21c82d50d14aca9b74a4dd919d9087f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Tue, 11 Feb 2020 08:27:50 +0100 Subject: [PATCH 12/13] parser: add test for 'extern crate async' --- src/test/ui/parser/extern-crate-async.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/ui/parser/extern-crate-async.rs diff --git a/src/test/ui/parser/extern-crate-async.rs b/src/test/ui/parser/extern-crate-async.rs new file mode 100644 index 0000000000000..6a54ac7f4a520 --- /dev/null +++ b/src/test/ui/parser/extern-crate-async.rs @@ -0,0 +1,12 @@ +// Make sure that we don't parse `extern crate async` +// the front matter of a function leading us astray. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern crate async; + +#[cfg(FALSE)] +extern crate async as something_else; From 9828559aad8672bb320517bd0fa1992ce144b848 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Tue, 11 Feb 2020 08:40:16 +0100 Subject: [PATCH 13/13] parser: is_fn_front_matter -> check_fn_front_matter --- src/librustc_parse/parser/item.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d16eb770951e1..ccd55c5c08a70 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -96,7 +96,7 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } - if self.is_fn_front_matter() { + if self.check_fn_front_matter() { // FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; let kind = ItemKind::Fn(sig, generics, body); @@ -742,7 +742,7 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness(); let (name, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_assoc_ty()? - } else if self.is_fn_front_matter() { + } 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) } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? { @@ -978,7 +978,7 @@ impl<'a> Parser<'a> { if self.check_keyword(kw::Type) { // FOREIGN TYPE ITEM self.parse_item_foreign_type(vis, lo, attrs) - } else if self.is_fn_front_matter() { + } else if self.check_fn_front_matter() { // FOREIGN FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; let kind = ForeignItemKind::Fn(sig, generics, body); @@ -1658,7 +1658,7 @@ impl<'a> Parser<'a> { } /// Is the current token the start of an `FnHeader` / not a valid parse? - fn is_fn_front_matter(&mut self) -> bool { + fn check_fn_front_matter(&mut self) -> bool { // We use an over-approximation here. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];